feat(limits): add configurable auto-refresh and harden limit persistence#260
feat(limits): add configurable auto-refresh and harden limit persistence#260matheus-fsc wants to merge 1 commit intoBentoBoxWorld:developfrom
Conversation
Introduce a configurable auto-refresh loop for permission-based limits and add runtime auditing for islands above their effective limits. Changes: - add auto-refresh-seconds to config (default 3600, 0 disables scheduler) - add Settings#getAutoRefreshSeconds() and parse value safely - start/stop JoinListener auto-refresh task in addon lifecycle - refresh online owners' island permission limits on schedule - audit block/entity/entity-group limit breaches and emit console warnings for admins - fix recount world resolution to evaluate material limits against the scanned world (normal/nether/end) - fix IslandBlockCount null-handling for entity maps so deserialized null maps are reattached - persist owner limit clears and admin offset changes immediately via setIsland() - add Settings tests for auto-refresh default and override behavior Validation: - full suite passed with JDK 21: mvn test (222 tests, 0 failures, 0 errors)
There was a problem hiding this comment.
Pull request overview
Adds a configurable scheduled refresh to re-evaluate permission-based island limits and introduces runtime auditing to detect and warn about islands exceeding effective block/entity limits, while also hardening persistence and fixing recount world resolution.
Changes:
- Add
auto-refresh-secondsconfig +Settings#getAutoRefreshSeconds()and tests. - Start/stop an auto-refresh task in addon lifecycle to refresh owner permission limits and audit limit breaches.
- Fix recount limit evaluation world selection and improve persistence/null-handling for deserialized island limit maps and admin offset updates.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| src/test/java/world/bentobox/limits/SettingsTest.java | Adds tests for the new auto-refresh configuration behavior. |
| src/main/resources/config.yml | Introduces auto-refresh-seconds configuration with documentation and default. |
| src/main/java/world/bentobox/limits/Settings.java | Parses/stores the auto-refresh interval and exposes it via a getter. |
| src/main/java/world/bentobox/limits/objects/IslandBlockCount.java | Ensures deserialized null entity maps are reattached and clears don’t NPE. |
| src/main/java/world/bentobox/limits/listeners/JoinListener.java | Implements scheduled refresh + auditing and persists owner-permission removals. |
| src/main/java/world/bentobox/limits/Limits.java | Wires auto-refresh start/stop into addon enable/disable lifecycle. |
| src/main/java/world/bentobox/limits/commands/admin/OffsetCommand.java | Persists offset changes immediately via setIsland(). |
| src/main/java/world/bentobox/limits/calculators/RecountCalculator.java | Evaluates material limits against the correct scanned world (normal/nether/end). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| private Map<EntityType, Integer> countEntitiesInIslandSpace(Island island) { | ||
| Map<EntityType, Integer> counts = new EnumMap<>(EntityType.class); | ||
| World world = island.getWorld(); | ||
| collectEntityCounts(island, world, counts); | ||
| IslandWorldManager iwm = addon.getPlugin().getIWM(); | ||
| if (iwm.isNetherIslands(world) && iwm.getNetherWorld(world) != null) { | ||
| collectEntityCounts(island, iwm.getNetherWorld(world), counts); | ||
| } | ||
| if (iwm.isEndIslands(world) && iwm.getEndWorld(world) != null) { | ||
| collectEntityCounts(island, iwm.getEndWorld(world), counts); | ||
| } | ||
| return counts; | ||
| } | ||
|
|
||
| private void collectEntityCounts(Island island, World world, Map<EntityType, Integer> counts) { | ||
| for (Entity entity : world.getEntities()) { | ||
| if (island.inIslandSpace(entity.getLocation())) { | ||
| counts.merge(entity.getType(), 1, Integer::sum); | ||
| } | ||
| } |
There was a problem hiding this comment.
The scheduled auto-refresh runs on the main thread and the audit path does an O(totalEntitiesInWorld) scan per island via world.getEntities() + island.inIslandSpace(). This can cause noticeable server lag spikes on large servers. Prefer the existing pattern used in EntityLimitListener (e.g., EntityLimitListener.java:454-503) using world.getNearbyEntities(island.getBoundingBox()) (and then filtering/grouping) so the query is spatially bounded and doesn’t require iterating every entity in the world.
| private void refreshPlayerIslands(GameModeAddon gameMode, Player player) { | ||
| addon.getIslands().getIslands(gameMode.getOverWorld(), player.getUniqueId()).stream() | ||
| .filter(island -> player.getUniqueId().equals(island.getOwner())) | ||
| .forEach(island -> { | ||
| String islandId = island.getUniqueId(); | ||
| IslandBlockCount islandBlockCount = addon.getBlockLimitListener().getIsland(islandId); | ||
| if (!joinEventCheck(player, islandId, islandBlockCount)) { | ||
| checkPerms(player, gameMode.getPermissionPrefix() + "island.limit.", islandId, | ||
| gameMode.getDescription().getName()); | ||
| } | ||
| auditIslandLimitBreaches(island, player.getName()); | ||
| }); |
There was a problem hiding this comment.
Auto-refresh calls checkPerms() for each owned island, and checkPerms() always persists via BlockLimitsListener.setIsland() (which unconditionally triggers handler.saveObjectAsync; see BlockLimitsListener.java:574-577). With the scheduler enabled, this can create periodic database writes even when permissions/limits didn’t change. Consider tracking whether any permission-derived limits actually changed (or gating persistence behind IslandBlockCount#isChanged / map-diff) before calling setIsland during scheduled refreshes.
Introduce a configurable auto-refresh loop for permission-based limits and add runtime auditing for islands above their effective limits.
Changes:
add auto-refresh-seconds to config (default 3600, 0 disables scheduler)
add Settings#getAutoRefreshSeconds() and parse value safely
start/stop JoinListener auto-refresh task in addon lifecycle
refresh online owners' island permission limits on schedule
audit block/entity/entity-group limit breaches and emit console warnings for admins
fix recount world resolution to evaluate material limits against the scanned world (normal/nether/end)
fix IslandBlockCount null-handling for entity maps so deserialized null maps are reattached
persist owner limit clears and admin offset changes immediately via setIsland()
add Settings tests for auto-refresh default and override behavior
Validation: