Skip to content

Fix sonarcloud criticals#244

Merged
tastybento merged 24 commits intodevelopfrom
fix-sonarcloud-criticals
Feb 21, 2026
Merged

Fix sonarcloud criticals#244
tastybento merged 24 commits intodevelopfrom
fix-sonarcloud-criticals

Conversation

@tastybento
Copy link
Member

@tastybento tastybento commented Feb 21, 2026

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.java

The string "_island_" was inlined 6 times across two registerCountAndLimitPlaceholders overloads.

Fix: Extracted as private static final String ISLAND_PLACEHOLDER = "_island_"; and replaced all 6 occurrences.

OffsetCommand.java

Three message keys were each repeated 5 times across the execute() and tabComplete() methods:

  • "general.errors.unknown-player"
  • "general.errors.player-has-no-island"
  • "admin.limits.offset.unknown"

Fix: Extracted as UNKNOWN_PLAYER, NO_ISLAND, and UNKNOWN_MATERIAL constants 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 existing if/else structure.

Fix: Extracted the lambda body into a handlePipelineResult(User, Results) helper method, making the async call a clean one-liner.

JoinListener.checkPerms() and runNullCheckAndSet() (was: 17 and 25)

checkPerms() repeated the addon.getSettings().isLogLimitsOnJoin() guard on every log call, adding complexity each time. runNullCheckAndSet() had a deeply nested else branch handling the ambiguous case where a name matches both a Material and an EntityType.

Fix:

  • Extracted logIfEnabled(String) — a single guarded log call that callers use unconditionally, eliminating repeated if (isLogLimitsOnJoin) checks.
  • Extracted applyAmbiguousLimit(IslandBlockCount, EntityType, Material, int) — moves the ambiguous-match else branch out of runNullCheckAndSet(), reducing it to a simple if/else-if chain.

EntityLimitListener.detectIronGolem() (was: 17) and detectWither() (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:

  • Extracted isGolemHead(Block) and isWitherHead(Block) — simple type checks that replace repeated inline conditionals.
  • Extracted eraseGolemIfArmsMatch(Block, Block, BlockFace) and eraseWitherIfArmsMatch(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 if blocks.

Fix: Extracted four helpers:

  • collectIslandGroupLimits(IslandBlockCount, Entity, Map) — populates groupsLimits from 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 an AtLimitResult if any group is at its limit.

atLimit() itself is now a readable top-level orchestration method.


Class Cycle (PipelinerRecountCalculator)

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: Pipeliner holds RecountCalculator instances in its queues and calls iD.scanIsland(this). RecountCalculator.scanIsland(Pipeliner) called back into Pipeliner to get the start timestamp, remove itself from the in-process queue, and check whether the task was cancelled.

Fix: Replaced the Pipeliner parameter in RecountCalculator.scanIsland() with three functional interfaces:

  • LongSupplier startTime — returns inProcessQueue.getOrDefault(iD, System.currentTimeMillis())
  • Runnable onRemove — calls inProcessQueue.remove(iD)
  • BooleanSupplier isCancelled — delegates to task::isCancelled
  • Runnable recurse — calls () -> scanIsland(iD) for the recursive continuation

Pipeliner.scanIsland(RecountCalculator) now passes these lambdas, and RecountCalculator has no reference to Pipeliner at all — the cycle is broken.

🤖 Generated with Claude Code

tastybento and others added 24 commits August 20, 2021 17:07
Translations and GUI locale improvements
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>
@sonarqubecloud
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
B Maintainability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

@tastybento tastybento merged commit 1d0a3b7 into develop Feb 21, 2026
2 of 3 checks passed
@tastybento tastybento deleted the fix-sonarcloud-criticals branch February 21, 2026 05:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant