Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/main/java/world/bentobox/chunkblock/Settings.java
Original file line number Diff line number Diff line change
Expand Up @@ -314,8 +314,9 @@ public class Settings implements WorldSettings {
@ConfigComment("Admins can change protection sizes for players individually using /chadmin range set <player> <new range>")
@ConfigComment("or set this permission: chunkblock.island.range.<number>")
@ConfigComment("ChunkBlock: this must cover the largest unlockable ring of chunks (see chunkblock.max-chunks).")
@ConfigComment("With max-chunks 441 (21x21, ring 10) the minimum needed is 168.")
@ConfigEntry(path = "world.protection-range")
private int islandProtectionRange = 240;
private int islandProtectionRange = 168;

@ConfigComment("Start islands at these coordinates. This is where new islands will start in the")
@ConfigComment("world. These must be a factor of your island distance, but the plugin will auto")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import world.bentobox.chunkblock.events.ChunkUnlockEvent;
import world.bentobox.chunkblock.events.RingCompleteEvent;
import world.bentobox.level.events.IslandLevelCalculatedEvent;
import world.bentobox.level.events.IslandPreLevelEvent;

/**
* Watches island level changes from the Level addon. Levels are chunk currency here:
Expand All @@ -44,6 +45,27 @@ public LevelListener(ChunkBlock addon) {
this.addon = addon;
}

/**
* Shrinks the island's protection range to cover only the unlocked chunks so the
* Level addon scans the playable area instead of the entire 240-block default.
* The calculator reads the range in the same tick; the original is restored on
* the next tick.
*/
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
public void onIslandPreLevel(IslandPreLevelEvent e) {
Island island = e.getIsland();
if (island == null || !addon.inWorld(island.getWorld())) {
return;
}
int ring = addon.getChunkManager().currentRing(island);
int needed = ring * 16 + ChunkManager.CHUNK_CENTER;
int stored = island.getProtectionRange();
if (needed < stored) {
island.setProtectionRange(needed);
Bukkit.getScheduler().runTask(addon.getPlugin(), () -> island.setProtectionRange(stored));
}
}

/**
* Fires after every island level calculation, before results are saved. Never
* cancelled here — we only read the level.
Expand Down
2 changes: 1 addition & 1 deletion src/test/java/world/bentobox/chunkblock/SettingsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ void testGetIslandDistance() {
*/
@Test
void testGetIslandProtectionRange() {
assertEquals(240, s.getIslandProtectionRange());
assertEquals(168, s.getIslandProtectionRange());
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
Expand All @@ -28,6 +29,7 @@
import world.bentobox.chunkblock.events.ChunkRelockEvent;
import world.bentobox.chunkblock.events.ChunkUnlockEvent;
import world.bentobox.chunkblock.events.RingCompleteEvent;
import world.bentobox.level.events.IslandPreLevelEvent;

/**
* Tests the credit-announcement and LIFO re-lock flows in {@link LevelListener} and the
Expand Down Expand Up @@ -216,6 +218,45 @@ void testIslandResetClearsRingRewards() {
assertEquals(1, data.getUnlockedChunkCount());
}

@Test
void testPreLevelShrinksProtectionRangeToUnlockedArea() {
when(island.getProtectionRange()).thenReturn(240);
// Only center chunk is unlocked → ring 0 → needed = 8
IslandPreLevelEvent pre = new IslandPreLevelEvent(uuid, island);
listener.onIslandPreLevel(pre);
verify(island).setProtectionRange(ChunkManager.CHUNK_CENTER);
// Restore scheduled for next tick
verify(sch).runTask(any(), any(Runnable.class));
}

@Test
void testPreLevelRangeMatchesCurrentRing() {
when(island.getProtectionRange()).thenReturn(240);
level = 8;
claimRingOne();
// Ring 1 unlocked → needed = 1 * 16 + 8 = 24
IslandPreLevelEvent pre = new IslandPreLevelEvent(uuid, island);
listener.onIslandPreLevel(pre);
verify(island).setProtectionRange(24);
}

@Test
void testPreLevelSkipsWhenRangeAlreadySmallEnough() {
when(island.getProtectionRange()).thenReturn(8);
IslandPreLevelEvent pre = new IslandPreLevelEvent(uuid, island);
listener.onIslandPreLevel(pre);
verify(island, never()).setProtectionRange(anyInt());
}

@Test
void testPreLevelIgnoresOtherWorlds() {
when(addon.inWorld(world)).thenReturn(false);
when(island.getProtectionRange()).thenReturn(240);
IslandPreLevelEvent pre = new IslandPreLevelEvent(uuid, island);
listener.onIslandPreLevel(pre);
verify(island, never()).setProtectionRange(anyInt());
}

/** Claims and celebrates all eight chunks of ring 1, closing it with the last one */
private void claimRingOne() {
for (int[] offset : new int[][] { { 1, 0 }, { 0, 1 }, { -1, 0 }, { 0, -1 }, { 1, 1 }, { -1, 1 },
Expand Down
Loading