new release#269
Merged
Merged
Conversation
Track block counts, entity counts, limits, and offsets independently per World.Environment so overworld, nether, and end no longer share a single count. Counts are now persistent rather than derived from getNearbyEntities, so they stay accurate when nether/end chunks are unloaded — the original bug in #43. - IslandBlockCount: every map keyed by Environment first; legacy data migrates lazily into Environment.NORMAL on first access. - BlockLimitsListener: env-aware tracking; resolution priority is island-env, world-named, env-default. New blocklimits-nether and blocklimits-end config sections override the env default for one env each. - EntityLimitListener: persistent per-env counts maintained via spawn-handler increments and EntityRemoveEvent decrements (UNLOAD cause excluded so chunk unload doesn't drop the count). EntityPortalEvent migrates counts between envs to prevent the obvious portal exploit. - JoinListener: permission format extended. 5-segment perms still apply the limit to all envs independently; new 6-segment form '<gm>.island.limit.<env>.<KEY>.<N>' targets one env (overworld/nether/end). - LimitPanel: one tab per env (skipped for envs the gamemode doesn't generate). LimitTab reads counts from the IBC. - Placeholders: env-suffixed variants added (_overworld_count etc.); the unsuffixed forms remain as sums for back-compat. - RecountCalculator: rebuilds counts per-env, including a loaded-entity scan to seed migrated servers' nether/end entity counts. - Tests: 230/230 passing, including new coverage for migration, env-prefixed perms, env-isolated counts, and per-env panel display. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Separate block and entity limits per dimension (fixes #43)
- Drop redundant eq() matchers in JoinListenerTest verify() calls (S6068) - Replace public modifier with package-private on JUnit 5 tests (S5786) - Use non-deprecated PlayerJoinEvent(Player, Component) constructor (S5738) - Rename `var` local in LimitTabTest to avoid restricted identifier (S6213) - Remove unused imports (eq, mock, Disabled) (S1128) - Use StringBuilder.isEmpty() over length() > 0 (S7158) - Drop "throws Exception" from BlockLimitsListenerTest methods that don't throw (S1130) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Drop the unused islandWorldManager field from Limits - Remove unnecessary intermediate raw Map cast in IslandBlockCount.newInner Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Extract entity-key handling from loadEntityLimits into applyEntityKey to cut cognitive complexity from 17 to under the threshold - Extract group-override handling into helpers so loadGroupLimitOverrides has a single break/continue path - Replace duplicated " - skipping..." and ".limit" string literals with SKIPPING and LIMIT_SUFFIX constants Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Drop the unused GameModeAddon parameter from LimitPanel.addEnvTab (was 8 params, now 7) and the unused Island parameter from LimitTab.addEntityLimits/addEntityGroupLimits - Hoist the duplicated translation keys (max-color, regular-color, block-limit-syntax) and "[limit]" placeholder into constants - Use EnumMap for the EntityType limit map in addEntityLimits Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Split RecountCalculator.scanAsync's nested chunk/column logic into a scanColumn helper and lift loop bounds out of the per-block check - Break EntityLimitListener.atLimit into resolveTypeLimit, resolveGroupLimits, checkTypeLimit, and checkGroupLimits so each method has a single responsibility - Extract JoinListener.checkPerms's per-permission body into applyOnePerm so the loop becomes a thin filter-and-apply pass Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Now that addEntityLimits/addEntityGroupLimits no longer use the island, the constructor's island parameter is dead too. Remove it and update the LimitPanel and LimitTabTest call sites. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- JoinListener.applyOnePerm: pull the @nullable event-IBC into a local before the null check so the analyzer sees the guard before the applyLimit call - IslandBlockCount.newInner: use diamond operator on the EnumMap via a typed local, dodging the unchecked-cast inference issue Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The floating jitpack snapshot v1.21-SNAPSHOT resolves to an ephemeral git-described build whose jar/POM get evicted, breaking CI even on unchanged commits. Switch to the equivalent stable Maven Central coordinates (org.mockbukkit.mockbukkit:mockbukkit-v1.21:4.110.0). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Brings the supported-versions list in line with the other addons (1.21.5-1.21.11, 26.1, 26.1.1, 26.1.2). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Update Modrinth game-versions to current MC range
- BlockSpreadEvent: decrement old block before adding new (was leaking old counts) - BlockGrowEvent: revert count increment when event is cancelled due to limit hit - RecountCalculator: load chunks in parallel instead of sequentially (fixes calc timeout on large islands) - RecountCalculator: use @nonnull getIsland(Island) to prevent permission limit loss on null ibc
The BlockGrowEvent handler decremented the new block's count after a cancelled (over-limit) grow. But process(block, true) returns before incrementing when the limit is hit, so that decrement removed a count that was never added — driving a real, physically-present block's count below its true value and letting the next grow slip past the limit. Drop the spurious decrement (the cancel branch was already balanced) and add tests covering: - BlockSpreadEvent decrementing the old block and adding the new (the leak this PR fixes) - BlockSpreadEvent reverting cleanly when the new material is at limit - BlockGrowEvent at a non-zero limit leaving the count untouched on a blocked grow (regression guard for the reverted line) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Fix block count leaks and parallelize recount chunk loading (supersedes #263)
… in CLAUDE.md Add a "Block State Transitions" section capturing the count-balance rule for form/spread/grow handlers (decrement old, add new with limit check, revert on cancel) and the gotcha that process(block, true) does not increment when the limit is hit — so no compensating decrement belongs in the cancel branch. Also brings in the pending Dependency Source Lookup, Project Layout, and Key Dependencies sections. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
BlockMultiPlaceEvent extends BlockPlaceEvent and does not declare its own HandlerList, so a single multi-place dispatch is delivered to BOTH onBlock(BlockPlaceEvent) and onBlock(BlockMultiPlaceEvent) — each calling process(block, true). A bed (or door, double-tall plant) was therefore counted twice on placement, while breaking it fired a single BlockBreakEvent and decremented once, permanently leaking +1 per place/break cycle until the island hit a phantom limit. Skip BlockMultiPlaceEvent instances in the BlockPlaceEvent handler and let the dedicated handler count them once — the same subtype-guard pattern onBlock(BlockFormEvent) already uses for its subclasses. Tests dispatch through the real plugin manager (so the double delivery actually occurs) and assert a bed counts once and returns to zero after a break. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Count multi-block placements (beds, doors) once, not twice (#86)
#127) When a player built an iron golem, detectIronGolem() assumed the CreatureSpawnEvent location was the BASE iron block and only searched upward. The built-mob spawn location is not guaranteed to be a specific block of the structure — when it is the body block, the old search matched nothing and removed only the spawn block, leaving the base, both arms and the pumpkin behind. Vanilla consumes those blocks, so Limits left a half-built golem's worth of blocks in the world (and uncounted). Anchor detection on the carved pumpkin / jack o'lantern instead, which is unambiguous: scan the spawn block and the two above it for the head, then verify and erase the body, base and arms relative to it. This works whether the spawn anchors on the base, body or head, and — unlike the old code, which unconditionally aired the spawn block — erases nothing unless a full valid pattern matches. Snowman detection is anchored the same way. Tests build a coordinate-keyed mock block grid and verify every structure block is removed for both spawn anchors, that a snowman is cleared, and that a lone iron block is left untouched. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Fix entity counts drifting above reality when mobs die off-island. trackSpawn counted the entity against the island where it spawned, but onEntityRemove used getIslandAt(entity.getLocation()) which returns empty when the entity wandered outside island bounds before dying or despawning. Added an entityIslandMap (UUID → islandId) so decrement always targets the correct island regardless of the entity's current location. onEntityPortal also updates the mapping for env-to-env transfers. A justPortaled debounce list prevents double-decrement if EntityRemoveEvent fires for the source-world removal during portal. - Fix HangingPlaceEvent race: change onBlock priority from MONITOR to LOW. Both onBlock (limit check) and onHangingPlaceTrack (tracking) were at MONITOR. Bukkit does not guarantee handler dispatch order within a single listener class, so trackSpawn could increment the entity count before the limit check had a chance to cancel the event, leaving a spurious +1 in the persistent count. - Fix processIsland undoing other plugins' event cancellations. cancelableEvent.setCancelled(false) was called unconditionally when the entity was not on a tracked island. Now guarded by runAsync so it only reverses this plugin's own pre-cancellation for async spawns (golems, withers). Other plugins' cancellations are left intact.
Anchor golem/snowman block removal on the pumpkin, not the spawn block (#127)
Fix three entity counting bugs in EntityLimitListener
Previously the only entity-limit check for spawn eggs was on the resulting CreatureSpawnEvent, which is cancelled when over the limit — but by then the egg item has already been consumed, so players lost the egg and got no spawn (and no message). Reported for right-clicking a mob with a spawn egg. Add LOW-priority guards on PlayerInteractEvent (egg on a block) and PlayerInteractEntityEvent (egg on a mob) that resolve the egg's entity type, check the island's limit for that type up front, and cancel the interaction (keeping the egg) with the entity-limits.hit-limit message when at the limit. A spawn egg always produces its own type, so the egg material maps directly to the entity type being checked. Refactors atLimit(Island, Entity) to delegate to a new atLimit(Island, EntityType, Environment) overload so the limit can be checked without an entity instance. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Deny spawn-egg use before consumption when at the entity limit (#134)
fixMaterial() hard-referenced Material.COPPER_WALL_TORCH, COPPER_TORCH and the COPPER_*_CHEST family, which only exist on Minecraft 1.21.9+. On older servers (e.g. Paper 1.21.8) the JVM failed to link these static field references, throwing NoSuchFieldError on the first BlockFadeEvent. Resolve these constants by name via Guava's Enums.getIfPresent into static final Optionals at class load, and guard the fixMaterial branches on isPresent(). The same jar now links and runs on both 1.21.8 and 1.21.9+. Lookups happen once, not in the per-tick hot path. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Resolve the open issues reported on the new-code period: Main code: - BlockLimitsListener: replace Guava Optional copper fields with nullable Material (S4738); refactor fixMaterial to a lookup map and extract loadLimits helpers to cut cognitive complexity (S3776); lazy-supplier logging (S2629); drop unused handleBreak param (S1172). - EntityLimitListener: constants for duplicated literals (S1192); extract assignment from condition (S1121); remove always-false getHand() null check (S2583); single Optional resolve before get (S3655). - Stream.toList() over collect(toList()) (S6204) in Limits, RecountCalculator, OffsetCommand; rename shadowing locals (S1117); switch->if in CalcCommand/RecountCommand (S1301); CalcCommand island field -> local (S1450); drop unused OffsetCommand alias param (S1172); remove redundant lambda braces in JoinListener (S1602). Tests: - Drop redundant public modifier on 181 JUnit 5 methods (S5786). - Replace deprecated PlayerJoinEvent(String)/BlockMultiPlaceEvent ctors and PlayerInteractEvent.isCancelled() (S5738/S1874). - Parameterize the four invalid-perm-format tests (S5976); method reference (S1612); assertNotEquals (S5785); drop useless eq() matchers (S6068); remove unused imports/vars/throws/commented code and add a missing assertion (S1128/S1481/S1854/S1130/S125/S2699). All 243 tests pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add the four keys introduced this release to all 20 translation files: admin.limits.offset.description (reused each file's existing translation, previously orphaned under offset.main.description) and the panel env-overworld/env-nether/env-end dimension names, localized per language. Convert 375 legacy & color codes to MiniMessage tags across all 21 locale files (e.g. &c -> <red>, &a -> <green>). Also fix eight pre-existing broken codes in translations where the colour letter had been dropped (hr, es, uk, tr messages and it regular-color) to <green>. CRLF line endings preserved. Co-Authored-By: Claude Opus 4.8 (1M context) <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.



No description provided.