Skip to content

Commit aa54c61

Browse files
authored
Merge pull request #269 from BentoBoxWorld/develop
new release
2 parents 7478046 + 1ad244f commit aa54c61

57 files changed

Lines changed: 4980 additions & 4110 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,4 @@ jobs:
3535
env:
3636
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
3737
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
38-
run: mvn -B verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar
38+
run: mvn -B verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Dsonar.projectKey=BentoBoxWorld_Limits

.github/workflows/modrinth-publish.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,9 @@ jobs:
8787
1.21.9
8888
1.21.10
8989
1.21.11
90+
26.1
91+
26.1.1
92+
26.1.2
9093
9194
# Path to the built JAR — Maven produces Limits-<version>.jar in target/
9295
# Note: glob patterns are not supported; use the release tag directly.

CLAUDE.md

Lines changed: 134 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -36,40 +36,74 @@ Limits is a **BentoBox addon** (not a standalone Spigot plugin). It depends on B
3636
4. Registers three listeners: `BlockLimitsListener`, `JoinListener`, `EntityLimitListener`
3737
5. Registers PlaceholderAPI placeholders for each material and entity type
3838

39-
### Three-Tier Limit System
39+
### Per-Environment Tracking (since #43)
4040

41-
Limits are resolved in a priority hierarchy (highest wins):
41+
Block counts, entity counts, limits, and offsets are all tracked **per `World.Environment`** (overworld, nether, end). The data model in `IslandBlockCount` keys every map by `Environment` first, then by material/entity. Pre-env data on disk is migrated into `Environment.NORMAL` lazily on first access.
4242

43-
1. **Island-specific** (`IslandBlockCount.blockLimits` / `entityLimits`): set by player permissions, checked at join
44-
2. **World-specific** (`BlockLimitsListener.worldLimitMap`): from `config.yml` `worlds:` section
45-
3. **Default** (`BlockLimitsListener.defaultLimitMap`): from `config.yml` `blocklimits:` section
43+
This means:
44+
- Counts in nether and end are persistent — they don't go to zero when chunks unload (the original bug in #43).
45+
- A single config-defined limit applies independently to each env (`HOPPER: 10` allows 10 in overworld, 10 in nether, 10 in end).
46+
- Entity portal teleports decrement the source-env count and increment the destination-env count via `EntityPortalEvent`.
4647

47-
**Offsets** (`blockLimitsOffset`, `entityLimitsOffset`) are added on top of any limit found — used by the `offset` admin command to give per-island bonus allowances.
48+
### Limit Resolution Order
49+
50+
For a block placement (or entity spawn) in environment `env`, the limit is resolved in priority order:
51+
52+
1. **Island-specific env limit** (`IslandBlockCount.envBlockLimits[env]`) — set by player permissions, checked at join.
53+
2. **World-specific limit** (`BlockLimitsListener.worldLimitMap[world]`) — from the `worlds:` section. Each world is one env so this is implicitly env-scoped.
54+
3. **Env default** (`BlockLimitsListener.envDefaultLimitMap[env]`) — from `blocklimits` (seeded into all envs) plus `blocklimits-nether` / `blocklimits-end` overrides.
55+
56+
**Offsets** (`envBlockLimitsOffset[env]`, `envEntityLimitsOffset[env]`) are added on top of any resolved limit. The legacy `/offset` admin command sets the same offset across all envs via the `setBlockLimitsOffsetAllEnvs` / `setEntityLimitsOffsetAllEnvs` helpers.
57+
58+
### Persistent Entity Counts
59+
60+
`EntityLimitListener` no longer counts entities via `World.getNearbyEntities(island.getBoundingBox())`. Instead it maintains the count in `IslandBlockCount.envEntityCounts`:
61+
62+
- Increment on MONITOR-priority handlers for `CreatureSpawnEvent`, `VehicleCreateEvent`, `HangingPlaceEvent` (after our LOW-priority limit check has had its say).
63+
- Decrement on `EntityRemoveEvent` whenever the cause is **not** `UNLOAD` (so death, despawn, drop, plugin removal, etc. all decrement; chunk unload does not).
64+
- `EntityPortalEvent` (MONITOR) handles env-to-env teleport: decrement source env, increment destination env.
65+
66+
This is Paper-only (the addon dropped Spigot support; `EntityRemoveEvent` is on Bukkit's API now but `EntityRemoveEvent.Cause` is needed).
4867

4968
### Key Classes
5069

5170
| Class | Role |
5271
|---|---|
5372
| `Limits` | Main addon; wires everything together, registers placeholders |
5473
| `Settings` | Parses `config.yml`; holds entity limits, entity group limits, game mode list |
55-
| `IslandBlockCount` | Per-island data object stored in BentoBox's database (`@Table("IslandBlockCount")`); tracks block counts, per-island block/entity limits, and offsets |
74+
| `IslandBlockCount` | Per-island data object stored in BentoBox's database (`@Table("IslandBlockCount")`); tracks block counts, entity counts, limits, and offsets — all keyed by `Environment` |
75+
| `EnvNamespacedKeyMapAdapter` | Gson type adapter for `Map<Environment, Map<NamespacedKey, Integer>>` — needed because `NamespacedKey` is not enum-keyed and Gson can't handle it natively |
5676
| `BlockLimitsListener` | Core block tracking listener; handles all block place/break/grow/explode events; maintains the `islandCountMap` in memory; persists via BentoBox `Database<IslandBlockCount>` |
5777
| `JoinListener` | Applies permission-based limits on player join, island creation/reset, and ownership change; fires `LimitsPermCheckEvent` / `LimitsJoinPermCheckEvent` for external cancellation |
5878
| `EntityLimitListener` | Cancels entity spawn/breed/vehicle-create events when entity or group limits are exceeded; handles async golem/snowman spawning edge cases |
5979
| `RecountCalculator` | Async chunk scanner used by the admin `calc` command to rebuild block counts from scratch; uses chunk snapshots and BentoBox's `Pipeliner` |
6080

6181
### Permission-Based Limits
6282

63-
Permission format: `<gamemode>.island.limit.<MATERIAL_OR_ENTITY_OR_GROUP>.<NUMBER>`
64-
65-
Example: `bskyblock.island.limit.HOPPER.20`
83+
Two formats:
84+
- 5-segment, all-env: `<gamemode>.island.limit.<KEY>.<NUMBER>` — applied independently to overworld, nether, and end.
85+
- 6-segment, env-scoped: `<gamemode>.island.limit.<env>.<KEY>.<NUMBER>` where `<env>``{overworld, nether, end}`.
6686

67-
`JoinListener.checkPerms()` clears all permission-based limits then re-applies them from scratch on each join. The highest value wins if multiple permissions grant the same limit. Wildcards are not supported.
87+
`JoinListener.checkPerms()` clears all permission-based limits then re-applies them from scratch on each join. The highest value wins if multiple permissions grant the same limit for the same env. Wildcards are not supported.
6888

6989
### Block Material Normalization
7090

7191
`BlockLimitsListener.fixMaterial()` normalizes variant materials to their canonical form (e.g., `CHIPPED_ANVIL``ANVIL`, `REDSTONE_WALL_TORCH``REDSTONE_TORCH`, `PISTON_HEAD``PISTON`/`STICKY_PISTON`). Block config keys can use Bukkit Material names or Minecraft tag names (e.g., `minecraft:logs`).
7292

93+
### Block State Transitions
94+
95+
When one block becomes another in place — `BlockFormEvent`, `EntityBlockFormEvent`, `BlockSpreadEvent` (grass/mycelium/fire spread), `BlockGrowEvent` (crops, sugar cane, etc.) — the handlers must keep the count balanced: **decrement the replaced block, then add the new one with a limit check, and revert on cancel.** The canonical shape (see `onBlock(BlockFormEvent)`):
96+
97+
```java
98+
process(e.getBlock(), false); // remove old
99+
if (process(e.getBlock(), e.getNewState().getBlockData(), true) > -1) {
100+
e.setCancelled(true);
101+
process(e.getBlock(), true); // limit hit → restore old
102+
}
103+
```
104+
105+
Key invariant when editing these handlers: `process(block, true)` returns the limit **before** incrementing when the limit is hit, so it only ever adds to the count on the success path (`-1` return). Do **not** add a compensating `process(..., false)` in the cancel branch — nothing was added, so it would decrement a real block's count below its true value and let the next transition slip past the limit. `BlockLimitsListenerTest` guards this with the `*StateTransition`, `*AtLimitCancelsAndRestoresOld`, and `testBlockGrowAtNonZeroLimitDoesNotDecrement` cases.
106+
73107
### Events API
74108

75109
Two cancellable events are fired so other plugins can intercept limit application:
@@ -146,3 +180,92 @@ worldLimitField.setAccessible(true);
146180
#### Testing Debounce (`justSpawned`)
147181

148182
`EntityLimitListener`'s private `justSpawned` list (deduplicates entity spawns) can be accessed via reflection to test debounce behavior.
183+
184+
## Dependency Source Lookup
185+
186+
When you need to inspect source code for a dependency (e.g., BentoBox, addons):
187+
188+
1. **Check local Maven repo first**: `~/.m2/repository/` — sources jars are named `*-sources.jar`
189+
2. **Check the workspace**: Look for sibling directories or Git submodules that may contain the dependency as a local project (e.g., `../bentoBox`, `../addon-*`)
190+
3. **Check Maven local cache for already-extracted sources** before downloading anything
191+
4. Only download a jar or fetch from the internet if the above steps yield nothing useful
192+
193+
Prefer reading `.java` source files directly from a local Git clone over decompiling or extracting a jar.
194+
195+
In general, the latest version of BentoBox should be targeted.
196+
197+
## Project Layout
198+
199+
Related projects are checked out as siblings under `~/git/`:
200+
201+
**Core:**
202+
- `bentobox/` — core BentoBox framework
203+
204+
**Game modes:**
205+
- `addon-acidisland/` — AcidIsland game mode
206+
- `addon-bskyblock/` — BSkyBlock game mode
207+
- `Boxed/` — Boxed game mode (expandable box area)
208+
- `CaveBlock/` — CaveBlock game mode
209+
- `OneBlock/` — AOneBlock game mode
210+
- `SkyGrid/` — SkyGrid game mode
211+
- `RaftMode/` — Raft survival game mode
212+
- `StrangerRealms/` — StrangerRealms game mode
213+
- `Brix/` — plot game mode
214+
- `parkour/` — Parkour game mode
215+
- `poseidon/` — Poseidon game mode
216+
- `gg/` — gg game mode
217+
218+
**Addons:**
219+
- `addon-level/` — island level calculation
220+
- `addon-challenges/` — challenges system
221+
- `addon-welcomewarpsigns/` — warp signs
222+
- `addon-limits/` — block/entity limits
223+
- `addon-invSwitcher/` / `invSwitcher/` — inventory switcher
224+
- `addon-biomes/` / `Biomes/` — biomes management
225+
- `Bank/` — island bank
226+
- `Border/` — world border for islands
227+
- `Chat/` — island chat
228+
- `CheckMeOut/` — island submission/voting
229+
- `ControlPanel/` — game mode control panel
230+
- `Converter/` — ASkyBlock to BSkyBlock converter
231+
- `DimensionalTrees/` — dimension-specific trees
232+
- `discordwebhook/` — Discord integration
233+
- `Downloads/` — BentoBox downloads site
234+
- `DragonFights/` — per-island ender dragon fights
235+
- `ExtraMobs/` — additional mob spawning rules
236+
- `FarmersDance/` — twerking crop growth
237+
- `GravityFlux/` — gravity addon
238+
- `Greenhouses-addon/` — greenhouse biomes
239+
- `IslandFly/` — island flight permission
240+
- `IslandRankup/` — island rankup system
241+
- `Likes/` — island likes/dislikes
242+
- `Limits/` — block/entity limits
243+
- `lost-sheep/` — lost sheep adventure
244+
- `MagicCobblestoneGenerator/` — custom cobblestone generator
245+
- `PortalStart/` — portal-based island start
246+
- `pp/` — pp addon
247+
- `Regionerator/` — region management
248+
- `Residence/` — residence addon
249+
- `TopBlock/` — top ten for OneBlock
250+
- `TwerkingForTrees/` — twerking tree growth
251+
- `Upgrades/` — island upgrades (Vault)
252+
- `Visit/` — island visiting
253+
- `weblink/` — web link addon
254+
- `CrowdBound/` — CrowdBound addon
255+
256+
**Data packs:**
257+
- `BoxedDataPack/` — advancement datapack for Boxed
258+
259+
**Documentation & tools:**
260+
- `docs/` — main documentation site
261+
- `docs-chinese/` — Chinese documentation
262+
- `docs-french/` — French documentation
263+
- `BentoBoxWorld.github.io/` — GitHub Pages site
264+
- `website/` — website
265+
- `translation-tool/` — translation tool
266+
267+
Check these for source before any network fetch.
268+
269+
## Key Dependencies (source locations)
270+
271+
- `world.bentobox:bentobox``~/git/bentobox/src/`

README.md

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,32 +19,54 @@ There is a user command and an admin command called "limits". Admins can check t
1919

2020
The config.yml has the following sections:
2121

22-
* blocklimits
23-
* worlds
24-
* entitylimits
22+
* `blocklimits`, `blocklimits-nether`, `blocklimits-end`
23+
* `worlds`
24+
* `entitylimits`, `entitylimits-nether`, `entitylimits-end`
25+
* `entitygrouplimits`, `entitygrouplimits-nether`, `entitygrouplimits-end`
26+
27+
### Per-environment separation
28+
29+
Limits are tracked independently in the overworld, nether, and end. A `HOPPER: 10` limit means the player can place up to 10 hoppers in **each** of overworld, nether, and end — 30 hoppers total across the island. Likewise for entities and entity groups.
30+
31+
If you want a different limit in nether or end, add a corresponding `*-nether` or `*-end` section that overrides the env-default for those entries only.
2532

2633
### blocklimits
2734

28-
This section lists the maximum number of blocks allowed for each block material. Do not use non-block materials because they will not work. The limits apply to all game worlds.
35+
The base block-limit section. Values here apply to every environment unless overridden by `blocklimits-nether` / `blocklimits-end` or by a `worlds.<worldname>` entry.
2936

3037
### worlds
3138

32-
This section lists block limits for specific worlds. You must name the world specifically, e.g. AcidIsland_world and then list the materials and the limit.
39+
Per-world overrides. Name the world specifically (e.g. `AcidIsland_world`) and list the materials and limits. A world entry overrides the env-default for that exact world.
3340

3441
### entitylimits
3542

36-
Coming soon!
43+
Default entity-type limits applied independently per environment. Override per env via `entitylimits-nether` / `entitylimits-end`.
44+
45+
### entitygrouplimits
46+
47+
Define named entity groups (icon, member set, default limit). Override the limit value per env with `entitygrouplimits-nether` / `entitygrouplimits-end`. The icon and member set are fixed in the base section — only the numeric limit can be overridden per env.
3748

3849
## Permissions
3950

40-
Island owners can have exclusive permissions that override the default or world settings. The format is:
51+
Island owners can have exclusive permissions that override the default or world settings. Two formats are supported:
4152

42-
Format is `GAME-MODE-NAME.island.limit.MATERIAL.LIMIT`
53+
* All-environment: `<gamemode>.island.limit.<KEY>.<NUMBER>` — applies the limit independently to every environment.
54+
* Per-environment: `<gamemode>.island.limit.<env>.<KEY>.<NUMBER>` — applies only to one environment, where `<env>` is `overworld`, `nether`, or `end`.
4355

44-
example: `bskyblock.island.limit.hopper.10`
56+
Examples:
57+
58+
```
59+
bskyblock.island.limit.hopper.10 # 10 hoppers in each env
60+
bskyblock.island.limit.nether.hopper.5 # only 5 hoppers in nether
61+
bskyblock.island.limit.end.enderman.50 # only 50 endermen in the end
62+
```
4563

4664
Permissions activate when the player logs in.
4765

66+
### Migrating an existing server
67+
68+
When upgrading from a pre-env version of Limits, existing per-island block counts are migrated to the overworld slot on first load. Counts in the nether/end will start at zero and be populated as entities and blocks change. Run `/<gamemode> admin limits calc <player>` to fully recount any island and redistribute its counts across environments.
69+
4870
Usage permissions are (put the gamemode name, e.g. acidisland at the front):
4971

5072
```

pom.xml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@
6262
<!-- Do not change unless you want different name for local builds. -->
6363
<build.number>-LOCAL</build.number>
6464
<!-- This allows to change between versions. -->
65-
<build.version>1.28.1</build.version>
65+
<build.version>1.28.2</build.version>
6666
<sonar.projectKey>BentoBoxWorld_Limits</sonar.projectKey>
6767
<sonar.organization>bentobox-world</sonar.organization>
6868
<sonar.host.url>https://sonarcloud.io</sonar.host.url>
@@ -135,9 +135,9 @@
135135

136136
<dependencies>
137137
<dependency>
138-
<groupId>com.github.MockBukkit</groupId>
139-
<artifactId>MockBukkit</artifactId>
140-
<version>v1.21-SNAPSHOT</version>
138+
<groupId>org.mockbukkit.mockbukkit</groupId>
139+
<artifactId>mockbukkit-v1.21</artifactId>
140+
<version>4.110.0</version>
141141
<scope>test</scope>
142142
<exclusions>
143143
<exclusion>

0 commit comments

Comments
 (0)