diff --git a/pom.xml b/pom.xml
index 6964411..cf83be3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -58,7 +58,7 @@
1.17.5
1.21.11-R0.1-SNAPSHOT
- 2.7.1-SNAPSHOT
+ 3.17.0-SNAPSHOT
${build.version}-SNAPSHOT
@@ -114,14 +114,6 @@
-
-
- jitpack.io
- https://jitpack.io
-
- true
-
-
spigot-repo
https://hub.spigotmc.org/nexus/content/repositories/snapshots
@@ -146,9 +138,9 @@
- com.github.MockBukkit
- MockBukkit
- v1.21-SNAPSHOT
+ org.mockbukkit.mockbukkit
+ mockbukkit-v1.21
+ 4.110.0
test
diff --git a/src/main/java/com/wasteofplastic/invswitcher/Store.java b/src/main/java/com/wasteofplastic/invswitcher/Store.java
index 9454697..89c0c37 100644
--- a/src/main/java/com/wasteofplastic/invswitcher/Store.java
+++ b/src/main/java/com/wasteofplastic/invswitcher/Store.java
@@ -676,4 +676,134 @@ private static void setTotalExperience(final Player player, final int exp)
public void saveOnShutdown() {
Bukkit.getOnlinePlayers().forEach(p -> this.storeAndSave(p, p.getWorld(), true));
}
+
+ /**
+ * Compute the storage key for a player and island event world, without using
+ * the player's current location. Used when the player is not in the target world.
+ * @param player - player
+ * @param world - the BentoBox event world
+ * @param island - the island involved in the event (may be null)
+ * @return storage key for this world/island combination
+ */
+ String getStorageKeyForEvent(Player player, World world, Island island) {
+ String overworldName = getOverworldName(world);
+ if (!addon.getSettings().isIslandsActive()) {
+ return overworldName;
+ }
+ World overworld = Util.getWorld(world);
+ if (overworld == null) {
+ return overworldName;
+ }
+ int count = addon.getIslands().getNumberOfConcurrentIslands(player.getUniqueId(), overworld);
+ if (count <= 1) {
+ return overworldName;
+ }
+ // Only use island-specific key if the player owns the island
+ if (island != null && island.getOwner() != null && island.getOwner().equals(player.getUniqueId())) {
+ return overworldName + "/" + island.getUniqueId();
+ }
+ return overworldName;
+ }
+
+ /**
+ * Clears the stored inventory for a BentoBox world when the player is not currently in
+ * that world. Called when BentoBox fires a {@code PlayerResetInventoryEvent} while the
+ * player is in a non-BentoBox world so the player's current inventory is not affected.
+ * @param player - online player
+ * @param world - the BentoBox world whose stored inventory should be cleared
+ * @param island - the island involved in the reset (may be null)
+ */
+ public void clearStoredInventoryForWorld(Player player, World world, Island island) {
+ InventoryStorage store = getInv(player);
+ String key = getStorageKeyForEvent(player, world, island);
+ String worldKey = getOverworldName(world);
+ Settings settings = addon.getSettings();
+ if (settings.isInventory()) {
+ String k = settings.isIslandsInventory() ? key : worldKey;
+ store.setInventory(k, Collections.emptyList());
+ }
+ database.saveObjectAsync(store);
+ }
+
+ /**
+ * Clears the stored ender chest for a BentoBox world when the player is not currently in
+ * that world. Called when BentoBox fires a {@code PlayerResetEnderChestEvent} while the
+ * player is in a non-BentoBox world.
+ * @param player - online player
+ * @param world - the BentoBox world whose stored ender chest should be cleared
+ * @param island - the island involved in the reset (may be null)
+ */
+ public void clearStoredEnderChestForWorld(Player player, World world, Island island) {
+ InventoryStorage store = getInv(player);
+ String key = getStorageKeyForEvent(player, world, island);
+ String worldKey = getOverworldName(world);
+ Settings settings = addon.getSettings();
+ if (settings.isEnderChest()) {
+ String k = settings.isIslandsEnderChest() ? key : worldKey;
+ store.setEnderChest(k, Collections.emptyList());
+ }
+ database.saveObjectAsync(store);
+ }
+
+ /**
+ * Zeroes the stored experience for a BentoBox world when the player is not currently in
+ * that world. Called when BentoBox fires a {@code PlayerResetExpEvent} while the
+ * player is in a non-BentoBox world.
+ * @param player - online player
+ * @param world - the BentoBox world whose stored experience should be zeroed
+ * @param island - the island involved in the reset (may be null)
+ */
+ public void clearStoredExpForWorld(Player player, World world, Island island) {
+ InventoryStorage store = getInv(player);
+ String key = getStorageKeyForEvent(player, world, island);
+ String worldKey = getOverworldName(world);
+ Settings settings = addon.getSettings();
+ if (settings.isExperience()) {
+ String k = settings.isIslandsExperience() ? key : worldKey;
+ store.setExp(k, 0);
+ }
+ database.saveObjectAsync(store);
+ }
+
+ /**
+ * Removes the stored health for a BentoBox world when the player is not currently in
+ * that world. Called when BentoBox fires a {@code PlayerResetHealthEvent} while the
+ * player is in a non-BentoBox world. Removing the entry means the player will receive
+ * maximum health the next time they enter the world.
+ * @param player - online player
+ * @param world - the BentoBox world whose stored health should be removed
+ * @param island - the island involved in the reset (may be null)
+ */
+ public void clearStoredHealthForWorld(Player player, World world, Island island) {
+ InventoryStorage store = getInv(player);
+ String key = getStorageKeyForEvent(player, world, island);
+ String worldKey = getOverworldName(world);
+ Settings settings = addon.getSettings();
+ if (settings.isHealth()) {
+ String k = settings.isIslandsHealth() ? key : worldKey;
+ store.getHealth().remove(k);
+ }
+ database.saveObjectAsync(store);
+ }
+
+ /**
+ * Resets the stored food level to full (20) for a BentoBox world when the player is not
+ * currently in that world. Called when BentoBox fires a {@code PlayerResetHungerEvent}
+ * while the player is in a non-BentoBox world.
+ * @param player - online player
+ * @param world - the BentoBox world whose stored food level should be reset
+ * @param island - the island involved in the reset (may be null)
+ */
+ public void clearStoredFoodForWorld(Player player, World world, Island island) {
+ InventoryStorage store = getInv(player);
+ String key = getStorageKeyForEvent(player, world, island);
+ String worldKey = getOverworldName(world);
+ Settings settings = addon.getSettings();
+ if (settings.isFood()) {
+ String k = settings.isIslandsFood() ? key : worldKey;
+ store.setFood(k, 20);
+ }
+ database.saveObjectAsync(store);
+ }
+
}
diff --git a/src/main/java/com/wasteofplastic/invswitcher/listeners/PlayerListener.java b/src/main/java/com/wasteofplastic/invswitcher/listeners/PlayerListener.java
index 97110c5..b404d40 100644
--- a/src/main/java/com/wasteofplastic/invswitcher/listeners/PlayerListener.java
+++ b/src/main/java/com/wasteofplastic/invswitcher/listeners/PlayerListener.java
@@ -17,6 +17,12 @@
import com.wasteofplastic.invswitcher.InvSwitcher;
import world.bentobox.bentobox.api.events.island.IslandEnterEvent;
+import world.bentobox.bentobox.api.events.player.PlayerBaseEvent;
+import world.bentobox.bentobox.api.events.player.PlayerResetEnderChestEvent;
+import world.bentobox.bentobox.api.events.player.PlayerResetExpEvent;
+import world.bentobox.bentobox.api.events.player.PlayerResetHealthEvent;
+import world.bentobox.bentobox.api.events.player.PlayerResetHungerEvent;
+import world.bentobox.bentobox.api.events.player.PlayerResetInventoryEvent;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.util.Util;
@@ -183,5 +189,100 @@ public void onPlayerQuit(final PlayerQuitEvent event) {
addon.getStore().removeFromCache(event.getPlayer());
}
+ /**
+ * Intercepts BentoBox's inventory reset when the player is not in the BentoBox world.
+ * Cancels the direct clear and instead wipes the stored inventory data for that world.
+ * @param event - event
+ */
+ @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
+ public void onPlayerResetInventory(PlayerResetInventoryEvent event) {
+ if (!shouldInterceptPlayerReset(event)) return;
+ event.setCancelled(true);
+ Player player = Bukkit.getPlayer(event.getPlayerUUID());
+ if (player != null) {
+ addon.getStore().clearStoredInventoryForWorld(player, event.getWorld(), event.getIsland());
+ }
+ }
+
+ /**
+ * Intercepts BentoBox's ender chest reset when the player is not in the BentoBox world.
+ * Cancels the direct clear and instead wipes the stored ender chest data for that world.
+ * @param event - event
+ */
+ @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
+ public void onPlayerResetEnderChest(PlayerResetEnderChestEvent event) {
+ if (!shouldInterceptPlayerReset(event)) return;
+ event.setCancelled(true);
+ Player player = Bukkit.getPlayer(event.getPlayerUUID());
+ if (player != null) {
+ addon.getStore().clearStoredEnderChestForWorld(player, event.getWorld(), event.getIsland());
+ }
+ }
+
+ /**
+ * Intercepts BentoBox's experience reset when the player is not in the BentoBox world.
+ * Cancels the direct clear and instead zeroes the stored experience for that world.
+ * @param event - event
+ */
+ @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
+ public void onPlayerResetExp(PlayerResetExpEvent event) {
+ if (!shouldInterceptPlayerReset(event)) return;
+ event.setCancelled(true);
+ Player player = Bukkit.getPlayer(event.getPlayerUUID());
+ if (player != null) {
+ addon.getStore().clearStoredExpForWorld(player, event.getWorld(), event.getIsland());
+ }
+ }
+
+ /**
+ * Intercepts BentoBox's health reset when the player is not in the BentoBox world.
+ * Cancels the direct reset and instead removes the stored health for that world
+ * (so the player receives max health when they next enter the world).
+ * @param event - event
+ */
+ @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
+ public void onPlayerResetHealth(PlayerResetHealthEvent event) {
+ if (!shouldInterceptPlayerReset(event)) return;
+ event.setCancelled(true);
+ Player player = Bukkit.getPlayer(event.getPlayerUUID());
+ if (player != null) {
+ addon.getStore().clearStoredHealthForWorld(player, event.getWorld(), event.getIsland());
+ }
+ }
+
+ /**
+ * Intercepts BentoBox's hunger reset when the player is not in the BentoBox world.
+ * Cancels the direct reset and instead sets stored food to full (20) for that world.
+ * @param event - event
+ */
+ @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
+ public void onPlayerResetHunger(PlayerResetHungerEvent event) {
+ if (!shouldInterceptPlayerReset(event)) return;
+ event.setCancelled(true);
+ Player player = Bukkit.getPlayer(event.getPlayerUUID());
+ if (player != null) {
+ addon.getStore().clearStoredFoodForWorld(player, event.getWorld(), event.getIsland());
+ }
+ }
+
+ /**
+ * Determines whether InvSwitcher should intercept a BentoBox player reset event.
+ * Returns true if the event's world is managed by InvSwitcher, the player is online,
+ * and the player is currently in a different world (not the event world).
+ * @param event - the reset event
+ * @return true if InvSwitcher should cancel the event and handle it itself
+ */
+ private boolean shouldInterceptPlayerReset(PlayerBaseEvent event) {
+ World eventWorld = event.getWorld();
+ if (!addon.getWorlds().contains(eventWorld)) {
+ return false;
+ }
+ Player player = Bukkit.getPlayer(event.getPlayerUUID());
+ if (player == null) {
+ return false;
+ }
+ // Only intercept if the player is not currently in the event world
+ return !Util.sameWorld(player.getWorld(), eventWorld);
+ }
}
diff --git a/src/test/java/com/wasteofplastic/invswitcher/StoreTest.java b/src/test/java/com/wasteofplastic/invswitcher/StoreTest.java
index 9cdb000..fbddcf0 100644
--- a/src/test/java/com/wasteofplastic/invswitcher/StoreTest.java
+++ b/src/test/java/com/wasteofplastic/invswitcher/StoreTest.java
@@ -645,4 +645,180 @@ public void testMigrationFromOldWorldKey() {
verify(player.getInventory(), atLeastOnce()).setContents(any(ItemStack[].class));
}
+ // --- clearStoredXForWorld Tests ---
+
+ /**
+ * When inventory is enabled and the event fires for a world the player is not in,
+ * the stored inventory for that world should be cleared.
+ * After clearing, loading inventory for that world should give empty contents.
+ */
+ @Test
+ public void testClearStoredInventoryForWorld() {
+ sets.setStatistics(false);
+ sets.setAdvancements(false);
+ Island island = mock(Island.class);
+ // First save something in the store
+ try (MockedStatic mockedBukkit = mockStatic(Bukkit.class, Mockito.RETURNS_MOCKS)) {
+ s.storeInventory(player, world);
+ assertTrue(s.isWorldStored(player, world), "Inventory should be stored before clearing");
+
+ // Clear stored inventory for the world
+ s.clearStoredInventoryForWorld(player, world, island);
+
+ // isWorldStored returns true even after clearing (entry exists but is empty list)
+ assertTrue(s.isWorldStored(player, world));
+
+ // Load inventory back - should set empty contents to player
+ s.getInventory(player, world);
+ // setContents should have been called with empty array
+ verify(player.getInventory(), atLeastOnce()).setContents(any(ItemStack[].class));
+ }
+ }
+
+ /**
+ * When ender chest is enabled, clearStoredEnderChestForWorld should work without error.
+ */
+ @Test
+ public void testClearStoredEnderChestForWorld() {
+ sets.setStatistics(false);
+ sets.setAdvancements(false);
+ Island island = mock(Island.class);
+ try (MockedStatic mockedBukkit = mockStatic(Bukkit.class, Mockito.RETURNS_MOCKS)) {
+ s.storeInventory(player, world);
+ // Should not throw
+ s.clearStoredEnderChestForWorld(player, world, island);
+ }
+ }
+
+ /**
+ * When experience is enabled, clearStoredExpForWorld should zero out the stored exp.
+ */
+ @Test
+ public void testClearStoredExpForWorld() {
+ sets.setStatistics(false);
+ sets.setAdvancements(false);
+ Island island = mock(Island.class);
+ when(player.getTotalExperience()).thenReturn(500);
+ try (MockedStatic mockedBukkit = mockStatic(Bukkit.class, Mockito.RETURNS_MOCKS)) {
+ s.storeInventory(player, world);
+ // Should not throw
+ s.clearStoredExpForWorld(player, world, island);
+ }
+ }
+
+ /**
+ * When health is enabled, clearStoredHealthForWorld should work without error.
+ */
+ @Test
+ public void testClearStoredHealthForWorld() {
+ sets.setStatistics(false);
+ sets.setAdvancements(false);
+ Island island = mock(Island.class);
+ when(player.getHealth()).thenReturn(10.0);
+ try (MockedStatic mockedBukkit = mockStatic(Bukkit.class, Mockito.RETURNS_MOCKS)) {
+ s.storeInventory(player, world);
+ // Should not throw
+ s.clearStoredHealthForWorld(player, world, island);
+ }
+ }
+
+ /**
+ * When food is enabled, clearStoredFoodForWorld should work without error.
+ */
+ @Test
+ public void testClearStoredFoodForWorld() {
+ sets.setStatistics(false);
+ sets.setAdvancements(false);
+ Island island = mock(Island.class);
+ when(player.getFoodLevel()).thenReturn(8);
+ try (MockedStatic mockedBukkit = mockStatic(Bukkit.class, Mockito.RETURNS_MOCKS)) {
+ s.storeInventory(player, world);
+ // Should not throw
+ s.clearStoredFoodForWorld(player, world, island);
+ }
+ }
+
+ /**
+ * clearStoredInventoryForWorld should be a no-op when inventory is disabled in settings.
+ * No exceptions should be thrown.
+ */
+ @Test
+ public void testClearStoredInventoryForWorldInventoryDisabled() {
+ sets.setInventory(false);
+ sets.setStatistics(false);
+ sets.setAdvancements(false);
+ Island island = mock(Island.class);
+ try (MockedStatic mockedBukkit = mockStatic(Bukkit.class, Mockito.RETURNS_MOCKS)) {
+ s.storeInventory(player, world);
+ // With inventory disabled, nothing is stored in the inventory map
+ assertFalse(s.isWorldStored(player, world));
+
+ // Calling clear should be a no-op (no exception, no effect)
+ s.clearStoredInventoryForWorld(player, world, island);
+ assertFalse(s.isWorldStored(player, world));
+ }
+ }
+
+ /**
+ * getStorageKeyForEvent should return the world name when islands mode is inactive.
+ */
+ @Test
+ public void testGetStorageKeyForEventIslandsDisabled() {
+ sets.setIslandsActive(false);
+ Island island = mock(Island.class);
+ String key = s.getStorageKeyForEvent(player, world, island);
+ assertEquals("world", key);
+ }
+
+ /**
+ * getStorageKeyForEvent should return world name when player has only 1 island.
+ */
+ @Test
+ public void testGetStorageKeyForEventSingleIsland() {
+ sets.setIslandsActive(true);
+ Island island = mock(Island.class);
+ try (MockedStatic mockedUtil = mockStatic(Util.class)) {
+ mockedUtil.when(() -> Util.getWorld(world)).thenReturn(world);
+ when(islandsManager.getNumberOfConcurrentIslands(playerUUID, world)).thenReturn(1);
+ String key = s.getStorageKeyForEvent(player, world, island);
+ assertEquals("world", key);
+ }
+ }
+
+ /**
+ * getStorageKeyForEvent should return island-specific key when player owns the island
+ * and has multiple islands.
+ */
+ @Test
+ public void testGetStorageKeyForEventMultipleIslandsOwner() {
+ sets.setIslandsActive(true);
+ Island island = mock(Island.class);
+ when(island.getOwner()).thenReturn(playerUUID);
+ when(island.getUniqueId()).thenReturn("island-abc");
+ try (MockedStatic mockedUtil = mockStatic(Util.class)) {
+ mockedUtil.when(() -> Util.getWorld(world)).thenReturn(world);
+ when(islandsManager.getNumberOfConcurrentIslands(playerUUID, world)).thenReturn(2);
+ String key = s.getStorageKeyForEvent(player, world, island);
+ assertEquals("world/island-abc", key);
+ }
+ }
+
+ /**
+ * getStorageKeyForEvent should return just the world name when player does not own the island
+ * (e.g., kicked from a team). Uses the world-level key since the player is a member, not owner.
+ */
+ @Test
+ public void testGetStorageKeyForEventMultipleIslandsNotOwner() {
+ sets.setIslandsActive(true);
+ Island island = mock(Island.class);
+ UUID otherOwner = UUID.randomUUID();
+ when(island.getOwner()).thenReturn(otherOwner); // player is NOT the owner
+ try (MockedStatic mockedUtil = mockStatic(Util.class)) {
+ mockedUtil.when(() -> Util.getWorld(world)).thenReturn(world);
+ when(islandsManager.getNumberOfConcurrentIslands(playerUUID, world)).thenReturn(2);
+ String key = s.getStorageKeyForEvent(player, world, island);
+ assertEquals("world", key); // Falls back to world name
+ }
+ }
+
}
diff --git a/src/test/java/com/wasteofplastic/invswitcher/listeners/PlayerListenerTest.java b/src/test/java/com/wasteofplastic/invswitcher/listeners/PlayerListenerTest.java
index cd3f6b1..0c4c61f 100644
--- a/src/test/java/com/wasteofplastic/invswitcher/listeners/PlayerListenerTest.java
+++ b/src/test/java/com/wasteofplastic/invswitcher/listeners/PlayerListenerTest.java
@@ -1,6 +1,8 @@
package com.wasteofplastic.invswitcher.listeners;
+import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.mockStatic;
@@ -37,6 +39,11 @@
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.events.island.IslandEnterEvent;
+import world.bentobox.bentobox.api.events.player.PlayerResetEnderChestEvent;
+import world.bentobox.bentobox.api.events.player.PlayerResetExpEvent;
+import world.bentobox.bentobox.api.events.player.PlayerResetHealthEvent;
+import world.bentobox.bentobox.api.events.player.PlayerResetHungerEvent;
+import world.bentobox.bentobox.api.events.player.PlayerResetInventoryEvent;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.managers.IslandsManager;
import world.bentobox.bentobox.util.Util;
@@ -64,6 +71,8 @@ public class PlayerListenerTest {
private Settings settings;
@Mock
private IslandsManager islandsManager;
+ @Mock
+ private Island island;
private UUID playerUUID;
private MockedStatic mockedBentoBox;
@@ -353,4 +362,159 @@ public void testOnPlayerRespawnNoIsland() {
verify(store, never()).storeAndSave(any(), any(), any(boolean.class));
}
+ // --- Player Reset Event Tests ---
+
+ /**
+ * When the event world is not managed by InvSwitcher, the event should not be intercepted
+ * and the store clear methods should not be called.
+ */
+ @Test
+ public void testOnPlayerResetInventoryWorldNotManaged() {
+ // notWorld is not in the addon's worlds set
+ when(addon.getWorlds()).thenReturn(Set.of(world)); // only 'world' is managed
+ PlayerResetInventoryEvent event = new PlayerResetInventoryEvent(notWorld, island, playerUUID);
+ try (MockedStatic mockedBukkit = mockStatic(Bukkit.class)) {
+ mockedBukkit.when(() -> Bukkit.getPlayer(playerUUID)).thenReturn(player);
+ pl.onPlayerResetInventory(event);
+ }
+ assertFalse(event.isCancelled(), "Event should not be cancelled when world is not managed");
+ verify(store, never()).clearStoredInventoryForWorld(any(), any(), any());
+ }
+
+ /**
+ * When the player is offline, the event should not be intercepted.
+ */
+ @Test
+ public void testOnPlayerResetInventoryPlayerOffline() {
+ PlayerResetInventoryEvent event = new PlayerResetInventoryEvent(world, island, playerUUID);
+ try (MockedStatic mockedBukkit = mockStatic(Bukkit.class)) {
+ mockedBukkit.when(() -> Bukkit.getPlayer(playerUUID)).thenReturn(null); // offline
+ pl.onPlayerResetInventory(event);
+ }
+ assertFalse(event.isCancelled(), "Event should not be cancelled when player is offline");
+ verify(store, never()).clearStoredInventoryForWorld(any(), any(), any());
+ }
+
+ /**
+ * When the player is currently in the event world, BentoBox should handle the reset directly.
+ */
+ @Test
+ public void testOnPlayerResetInventoryPlayerInEventWorld() {
+ // player.getWorld() returns 'world', event world is also 'world'
+ when(player.getWorld()).thenReturn(world);
+ PlayerResetInventoryEvent event = new PlayerResetInventoryEvent(world, island, playerUUID);
+ try (MockedStatic mockedBukkit = mockStatic(Bukkit.class);
+ MockedStatic mockedUtil = mockStatic(Util.class)) {
+ mockedBukkit.when(() -> Bukkit.getPlayer(playerUUID)).thenReturn(player);
+ mockedUtil.when(() -> Util.sameWorld(world, world)).thenReturn(true);
+ pl.onPlayerResetInventory(event);
+ }
+ assertFalse(event.isCancelled(), "Event should not be cancelled when player is in event world");
+ verify(store, never()).clearStoredInventoryForWorld(any(), any(), any());
+ }
+
+ /**
+ * When the player is in a non-BentoBox world, the inventory reset event should be cancelled
+ * and the stored inventory for the BentoBox world should be cleared.
+ */
+ @Test
+ public void testOnPlayerResetInventoryPlayerInDifferentWorld() {
+ // player is in notWorld, event fires for world
+ when(player.getWorld()).thenReturn(notWorld);
+ PlayerResetInventoryEvent event = new PlayerResetInventoryEvent(world, island, playerUUID);
+ try (MockedStatic mockedBukkit = mockStatic(Bukkit.class);
+ MockedStatic mockedUtil = mockStatic(Util.class)) {
+ mockedBukkit.when(() -> Bukkit.getPlayer(playerUUID)).thenReturn(player);
+ mockedUtil.when(() -> Util.sameWorld(notWorld, world)).thenReturn(false);
+ pl.onPlayerResetInventory(event);
+ }
+ assertTrue(event.isCancelled(), "Event should be cancelled when player is in a different world");
+ verify(store).clearStoredInventoryForWorld(player, world, island);
+ }
+
+ /**
+ * Ender chest reset should be intercepted when the player is in a different world.
+ */
+ @Test
+ public void testOnPlayerResetEnderChestPlayerInDifferentWorld() {
+ when(player.getWorld()).thenReturn(notWorld);
+ PlayerResetEnderChestEvent event = new PlayerResetEnderChestEvent(world, island, playerUUID);
+ try (MockedStatic mockedBukkit = mockStatic(Bukkit.class);
+ MockedStatic mockedUtil = mockStatic(Util.class)) {
+ mockedBukkit.when(() -> Bukkit.getPlayer(playerUUID)).thenReturn(player);
+ mockedUtil.when(() -> Util.sameWorld(notWorld, world)).thenReturn(false);
+ pl.onPlayerResetEnderChest(event);
+ }
+ assertTrue(event.isCancelled(), "Event should be cancelled when player is in a different world");
+ verify(store).clearStoredEnderChestForWorld(player, world, island);
+ }
+
+ /**
+ * Ender chest reset should not be intercepted when the player is in the event world.
+ */
+ @Test
+ public void testOnPlayerResetEnderChestPlayerInEventWorld() {
+ when(player.getWorld()).thenReturn(world);
+ PlayerResetEnderChestEvent event = new PlayerResetEnderChestEvent(world, island, playerUUID);
+ try (MockedStatic mockedBukkit = mockStatic(Bukkit.class);
+ MockedStatic mockedUtil = mockStatic(Util.class)) {
+ mockedBukkit.when(() -> Bukkit.getPlayer(playerUUID)).thenReturn(player);
+ mockedUtil.when(() -> Util.sameWorld(world, world)).thenReturn(true);
+ pl.onPlayerResetEnderChest(event);
+ }
+ assertFalse(event.isCancelled());
+ verify(store, never()).clearStoredEnderChestForWorld(any(), any(), any());
+ }
+
+ /**
+ * Experience reset should be intercepted when the player is in a different world.
+ */
+ @Test
+ public void testOnPlayerResetExpPlayerInDifferentWorld() {
+ when(player.getWorld()).thenReturn(notWorld);
+ PlayerResetExpEvent event = new PlayerResetExpEvent(world, island, playerUUID);
+ try (MockedStatic mockedBukkit = mockStatic(Bukkit.class);
+ MockedStatic mockedUtil = mockStatic(Util.class)) {
+ mockedBukkit.when(() -> Bukkit.getPlayer(playerUUID)).thenReturn(player);
+ mockedUtil.when(() -> Util.sameWorld(notWorld, world)).thenReturn(false);
+ pl.onPlayerResetExp(event);
+ }
+ assertTrue(event.isCancelled(), "Event should be cancelled when player is in a different world");
+ verify(store).clearStoredExpForWorld(player, world, island);
+ }
+
+ /**
+ * Health reset should be intercepted when the player is in a different world.
+ */
+ @Test
+ public void testOnPlayerResetHealthPlayerInDifferentWorld() {
+ when(player.getWorld()).thenReturn(notWorld);
+ PlayerResetHealthEvent event = new PlayerResetHealthEvent(world, island, playerUUID);
+ try (MockedStatic mockedBukkit = mockStatic(Bukkit.class);
+ MockedStatic mockedUtil = mockStatic(Util.class)) {
+ mockedBukkit.when(() -> Bukkit.getPlayer(playerUUID)).thenReturn(player);
+ mockedUtil.when(() -> Util.sameWorld(notWorld, world)).thenReturn(false);
+ pl.onPlayerResetHealth(event);
+ }
+ assertTrue(event.isCancelled(), "Event should be cancelled when player is in a different world");
+ verify(store).clearStoredHealthForWorld(player, world, island);
+ }
+
+ /**
+ * Hunger reset should be intercepted when the player is in a different world.
+ */
+ @Test
+ public void testOnPlayerResetHungerPlayerInDifferentWorld() {
+ when(player.getWorld()).thenReturn(notWorld);
+ PlayerResetHungerEvent event = new PlayerResetHungerEvent(world, island, playerUUID);
+ try (MockedStatic mockedBukkit = mockStatic(Bukkit.class);
+ MockedStatic mockedUtil = mockStatic(Util.class)) {
+ mockedBukkit.when(() -> Bukkit.getPlayer(playerUUID)).thenReturn(player);
+ mockedUtil.when(() -> Util.sameWorld(notWorld, world)).thenReturn(false);
+ pl.onPlayerResetHunger(event);
+ }
+ assertTrue(event.isCancelled(), "Event should be cancelled when player is in a different world");
+ verify(store).clearStoredFoodForWorld(player, world, island);
+ }
+
}