Merged
Conversation
Release 1.17.2
Release 1.18.1
Version 1.19.0
Version 1.19.1
Release 1.20.1
Release 1.21.0
Release 1.22.0
Version 1.23.0
Release 1.24.0
Release 1.25.0
Translations and GUI locale improvements
Update ja.yml
Release 1.26.0
New Version
Release 1.27.1
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…vent On Paper servers, CreatureSpawnEvent fires for the new shulker *after* the original shulker has already teleported away. If the original shulker teleports outside the island bounding box, getNearbyEntities counts N-1 shulkers instead of N, so the limit check incorrectly allows duplication past the configured limit. Paper's ShulkerDuplicateEvent fires *before* the original shulker teleports and before the duplicate is created, so the island entity count is accurate. Register PaperShulkerLimitListener when Paper is detected at runtime; fall back to the existing CreatureSpawnEvent handling on Spigot. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Change Paper API dependency from 1.21.8 to 1.20.4, which is the last version compiled for Java 17. Paper 1.20.6+ targets Java 21 (class version 65), which the compiler rejects under --release 17. - Stage the remaining add_tags source files (IslandBlockCount, BlockLimitsListener, RecountCalculator, etc.) that Limits.java depends on; they were missing from the previous commit, causing NamespacedKey / Material type mismatches in CI. - Fix @AfterEach (JUnit 5) -> @after (JUnit 4) in the three test files that have JUnit 4 imports; the annotation was unresolved in CI. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add isLogLimitsOnJoin() config option (from master commit bdf41ea) so that the verbose per-permission log lines can be silenced. Wraps each addon.log() call in checkPerms/runNullCheckAndSet with the guard. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Conflict in JoinListener.java resolved by keeping the add_tags/PR branch version, which already incorporates the log-limits-on-join changes from master commit bdf41ea. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…n-limit Fix #242: enforce shulker entity limit on Paper via ShulkerDuplicateEvent
…cate literals - Extract ISLAND_PLACEHOLDER constant in Limits.java (6 occurrences of "_island_") - Extract UNKNOWN_PLAYER/NO_ISLAND/UNKNOWN_MATERIAL constants in OffsetCommand.java - Extract handlePipelineResult() in CalcCommand to reduce cognitive complexity - Extract logIfEnabled() and applyAmbiguousLimit() in JoinListener to reduce complexity - Extract collectIslandGroupLimits(), applyGlobalGroupLimits(), updateGroupLimitsFromIbc(), checkGroupLimits() in EntityLimitListener to reduce atLimit() complexity from 23 to ~10 - Extract isGolemHead(), eraseGolemIfArmsMatch(), isWitherHead(), eraseWitherIfArmsMatch() in EntityLimitListener to reduce detectIronGolem/detectWither complexity - Break Pipeliner<->RecountCalculator class cycle by replacing Pipeliner parameter in RecountCalculator.scanIsland() with functional interfaces (LongSupplier, Runnable, BooleanSupplier) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.




Summary
Addresses all CRITICAL severity issues flagged by SonarCloud analysis. The issues fall into two categories: duplicate string literals and excessive cognitive complexity.
Duplicate String Literals
SonarCloud flags string literals that appear 5 or more times without being extracted into a named constant. Duplicated literals are a maintenance hazard — if the value ever needs to change, every copy must be updated individually.
Limits.javaThe string
"_island_"was inlined 6 times across tworegisterCountAndLimitPlaceholdersoverloads.Fix: Extracted as
private static final String ISLAND_PLACEHOLDER = "_island_";and replaced all 6 occurrences.OffsetCommand.javaThree message keys were each repeated 5 times across the
execute()andtabComplete()methods:"general.errors.unknown-player""general.errors.player-has-no-island""admin.limits.offset.unknown"Fix: Extracted as
UNKNOWN_PLAYER,NO_ISLAND, andUNKNOWN_MATERIALconstants and replaced all occurrences.Cognitive Complexity
SonarCloud measures cognitive complexity by counting structural elements (if/for/while/lambda/ternary) and adding extra weight for each level of nesting. The default threshold is 15. Methods over this limit are harder to read, test, and maintain.
CalcCommand.execute()(was: 17)The method contained an inline lambda passed to
thenAccept()with its own branching logic, which added nesting on top of the existingif/elsestructure.Fix: Extracted the lambda body into a
handlePipelineResult(User, Results)helper method, making the async call a clean one-liner.JoinListener.checkPerms()andrunNullCheckAndSet()(was: 17 and 25)checkPerms()repeated theaddon.getSettings().isLogLimitsOnJoin()guard on every log call, adding complexity each time.runNullCheckAndSet()had a deeply nestedelsebranch handling the ambiguous case where a name matches both aMaterialand anEntityType.Fix:
logIfEnabled(String)— a single guarded log call that callers use unconditionally, eliminating repeatedif (isLogLimitsOnJoin)checks.applyAmbiguousLimit(IslandBlockCount, EntityType, Material, int)— moves the ambiguous-matchelsebranch out ofrunNullCheckAndSet(), reducing it to a simple if/else-if chain.EntityLimitListener.detectIronGolem()(was: 17) anddetectWither()(was: 20)Both methods iterated over cardinal directions and then nested another loop inside to check arm positions, resulting in 4 levels of nesting.
Fix:
isGolemHead(Block)andisWitherHead(Block)— simple type checks that replace repeated inline conditionals.eraseGolemIfArmsMatch(Block, Block, BlockFace)anderaseWitherIfArmsMatch(Block, Block, BlockFace)— each contains the inner arm-checking loop. Returning a boolean lets the parent method use early return cleanly.EntityLimitListener.atLimit()(was: 23)The method did everything inline: collecting island group limits, applying global group limits, updating limits from island-specific overrides, and iterating to check each group — all with lambdas and loops nested inside
ifblocks.Fix: Extracted four helpers:
collectIslandGroupLimits(IslandBlockCount, Entity, Map)— populatesgroupsLimitsfrom the island's stored entity group limit settings.applyGlobalGroupLimits(Entity, Map)— fills in any group limits from the global config that aren't already overridden by island settings.updateGroupLimitsFromIbc(IslandBlockCount, Map)— applies island-specific group limit overrides back onto the working map.checkGroupLimits(Island, Entity, IslandBlockCount, Map)— iterates the final map and returns anAtLimitResultif any group is at its limit.atLimit()itself is now a readable top-level orchestration method.Class Cycle (
Pipeliner↔RecountCalculator)SonarCloud flags bidirectional dependencies between classes in the same package as a design smell. Cycles make classes impossible to reuse or test independently.
The cycle:
PipelinerholdsRecountCalculatorinstances in its queues and callsiD.scanIsland(this).RecountCalculator.scanIsland(Pipeliner)called back intoPipelinerto get the start timestamp, remove itself from the in-process queue, and check whether the task was cancelled.Fix: Replaced the
Pipelinerparameter inRecountCalculator.scanIsland()with three functional interfaces:LongSupplier startTime— returnsinProcessQueue.getOrDefault(iD, System.currentTimeMillis())Runnable onRemove— callsinProcessQueue.remove(iD)BooleanSupplier isCancelled— delegates totask::isCancelledRunnable recurse— calls() -> scanIsland(iD)for the recursive continuationPipeliner.scanIsland(RecountCalculator)now passes these lambdas, andRecountCalculatorhas no reference toPipelinerat all — the cycle is broken.🤖 Generated with Claude Code