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
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,12 @@ public void deleteIsland(@NonNull Island island, boolean removeBlocks, @Nullable
// Set the owner of the island to no one.
island.setOwner(null);
island.setFlag(Flags.LOCK, RanksManager.VISITOR_RANK);
// Drop the island from the per-player UUID index. It is unowned now, so it
// must not count towards anyone's concurrent islands or be returned by
// getIslands(world, uuid) until it is registered to a new owner again. This
// keeps the runtime index consistent with the one rebuilt on startup, which
// only indexes owned islands (IslandCache#addIsland).
islandCache.removeIslandFromUUIDIndex(island);
if (removeBlocks) {
// Remove players from island
removePlayersFromIsland(island);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,25 @@ public void deleteIslandFromCache(@NonNull String uniqueId) {
}
}

/**
* Removes every player's link to this island from the per-UUID lookup index
* without evicting the island from {@code islandsById} or the island grid.
* <p>
* Used when an island is soft-deleted (see
* {@link world.bentobox.bentobox.managers.IslandsManager#deleteIsland}). The
* island becomes unowned, so it must no longer count towards any player's
* concurrent islands or show up in {@link #getIslands(World, UUID)}, yet it
* must stay known so its location remains reserved and the region-file purge
* can still find and reap it. This mirrors how the index is rebuilt on
* startup, where {@link #addIsland(Island)} only indexes owned islands.
*
* @param island the island to de-index
* @since 3.23.0
*/
public void removeIslandFromUUIDIndex(@NonNull Island island) {
removeFromIslandsByUUID(island);
}

/**
* Returns island referenced by player's UUID. Returns the island the player is
* on now, or their last known island
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,26 @@ void testDeleteIslandIslandBooleanRemoveBlocks() {
verify(pim).callEvent(any(IslandDeleteEvent.class));
}

/**
* A soft-deleted island becomes unowned, so it must be dropped from the
* per-player UUID index. Otherwise a pending-deletion island keeps counting
* towards the ex-owner's concurrent islands (and shows up in
* {@code getIslands(world, uuid)}) until the server restarts.
*/
@Test
void testDeleteIslandRemovesIslandFromUUIDIndex() {
UUID localOwner = UUID.randomUUID();
Island island = islandsManager.createIsland(location, localOwner);
assertNotNull(island);
assertEquals(1, islandsManager.getNumberOfConcurrentIslands(localOwner, world));

islandsManager.deleteIsland(island, true, localOwner);

assertNull(island.getOwner());
assertEquals(0, islandsManager.getNumberOfConcurrentIslands(localOwner, world));
assertTrue(islandsManager.getIslands(world, localOwner).isEmpty());
}

/**
* Test method for
* {@link world.bentobox.bentobox.managers.IslandsManager#undeleteIsland(world.bentobox.bentobox.database.objects.Island)}.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,27 @@ void testRemovePlayerIslandUUID() {
ic.removePlayer(island, owner);
}

/**
* Test for {@link IslandCache#removeIslandFromUUIDIndex(Island)}. The island
* must no longer be associated with any player, but must stay cached and
* known at its location so the region purge can still reap it.
*/
@Test
void testRemoveIslandFromUUIDIndex() {
ic.addIsland(island);
assertEquals(island, ic.getIsland(world, owner));

ic.removeIslandFromUUIDIndex(island);

// Not associated with the player any more
assertTrue(ic.getIslands(world, owner).isEmpty());
assertNull(ic.getIsland(world, owner));
assertFalse(ic.hasIsland(world, owner));
// Still cached and still occupying its grid slot
assertEquals(island, ic.getIslandById("uniqueId"));
assertEquals(island, ic.getIslandAt(island.getCenter()));
}

/**
* Test method for {@link world.bentobox.bentobox.managers.island.IslandCache#size(org.bukkit.World)}.
*/
Expand Down
Loading