diff --git a/pom.xml b/pom.xml
index f2c68b7..c6baa7e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -64,7 +64,7 @@
-LOCAL
- 1.17.0
+ 1.17.1
BentoBoxWorld_addon-invSwitcher
bentobox-world
@@ -238,6 +238,7 @@
3.13.0
${java.version}
+ true
diff --git a/src/main/java/com/wasteofplastic/invswitcher/Store.java b/src/main/java/com/wasteofplastic/invswitcher/Store.java
index 7fc4feb..5ef1022 100644
--- a/src/main/java/com/wasteofplastic/invswitcher/Store.java
+++ b/src/main/java/com/wasteofplastic/invswitcher/Store.java
@@ -31,6 +31,7 @@
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
+import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
@@ -64,6 +65,7 @@
public class Store {
private static final CharSequence THE_END = "_the_end";
private static final CharSequence NETHER = "_nether";
+ static final String DEFAULT_WORLD_KEY = "default";
private final Database database;
private final Map cache;
private final Map currentKey;
@@ -108,6 +110,9 @@ public String getStorageKey(Player player, World world, Island island) {
* @return storage key
*/
String getStorageKey(Player player, World world, Location location, Island island) {
+ if (!addon.getWorlds().contains(world)) {
+ return DEFAULT_WORLD_KEY;
+ }
String overworldName = getOverworldName(world);
if (!addon.getSettings().isIslandsActive()) {
@@ -159,9 +164,27 @@ String getStorageKey(Player player, World world, Location location, Island islan
* @return overworld name
*/
private String getOverworldName(World world) {
+ if (!addon.getWorlds().contains(world)) {
+ return DEFAULT_WORLD_KEY;
+ }
return (world.getName().replace(THE_END, "")).replace(NETHER, "");
}
+ private String findOldNonBentoBoxKey(InventoryStorage store) {
+ if (store.getInventory() == null) {
+ return null;
+ }
+ Set bentoboxOverworlds = addon.getWorlds().stream()
+ .map(w -> (w.getName().replace(THE_END, "")).replace(NETHER, ""))
+ .collect(Collectors.toSet());
+ return store.getInventory().keySet().stream()
+ .filter(k -> !k.contains("/"))
+ .filter(k -> !bentoboxOverworlds.contains(k))
+ .filter(k -> !DEFAULT_WORLD_KEY.equals(k))
+ .findFirst()
+ .orElse(null);
+ }
+
/**
* Get the current storage key for a player.
* @param player - player
@@ -209,10 +232,20 @@ public void getInventory(Player player, World world, Island island) {
// Always track the island-level key so future saves and island detection work correctly
currentKey.put(player.getUniqueId(), islandKey);
+ // Migration: non-BentoBox worlds previously stored data under individual world names.
+ // Now they share DEFAULT_WORLD_KEY. Find and migrate old data on first access.
+ String islandLoadKey = islandKey;
+ if (DEFAULT_WORLD_KEY.equals(islandKey) && !store.isInventory(islandKey)) {
+ String oldKey = findOldNonBentoBoxKey(store);
+ if (oldKey != null) {
+ islandLoadKey = oldKey;
+ store.clearWorldData(oldKey);
+ }
+ }
+
// Backward compat: if island-specific key has no data, migrate from world-only key.
// This only happens once — the world-only data is cleared after migration so that
// other islands don't also inherit a duplicate copy.
- String islandLoadKey = islandKey;
if (islandKey.contains("/") && !store.isInventory(islandKey)) {
if (store.isInventory(worldKey)) {
islandLoadKey = worldKey;
diff --git a/src/test/java/com/wasteofplastic/invswitcher/StoreTest.java b/src/test/java/com/wasteofplastic/invswitcher/StoreTest.java
index ac4feba..dfe5419 100644
--- a/src/test/java/com/wasteofplastic/invswitcher/StoreTest.java
+++ b/src/test/java/com/wasteofplastic/invswitcher/StoreTest.java
@@ -21,7 +21,9 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Comparator;
+import java.util.HashSet;
import java.util.Optional;
+import java.util.Set;
import java.util.UUID;
import java.util.logging.Logger;
@@ -78,6 +80,8 @@ public class StoreTest {
private Settings sets;
+ private Set bentoboxWorlds;
+
private UUID playerUUID;
@Mock
@@ -131,6 +135,11 @@ public void setUp() throws Exception {
DatabaseType mockDbt = mock(DatabaseType.class);
when(bbSettings.getDatabaseType()).thenReturn(mockDbt);
+ // Register world as a BentoBox world
+ bentoboxWorlds = new HashSet<>();
+ bentoboxWorlds.add(world);
+ when(addon.getWorlds()).thenReturn(bentoboxWorlds);
+
// Disable island switching by default for existing tests
sets.setIslandsActive(false);
@@ -378,6 +387,7 @@ public void testGetStorageKeyGenericNether() {
World netherWorld = mock(World.class);
when(netherWorld.getName()).thenReturn("world_nether");
when(netherWorld.getEnvironment()).thenReturn(Environment.NETHER);
+ bentoboxWorlds.add(netherWorld);
// Set up overworld for Util.getWorld
World overworld = mock(World.class);
@@ -512,4 +522,83 @@ public void testFullScenarioSingleToMultipleIslands() {
}
}
+ // --- Non-BentoBox world tests ---
+
+ @Test
+ public void testGetStorageKeyNonBentoBoxWorld() {
+ World otherWorld = mock(World.class);
+ when(otherWorld.getName()).thenReturn("em_adventurers_guild");
+ // otherWorld is NOT in bentoboxWorlds
+ String key = s.getStorageKey(player, otherWorld);
+ assertEquals(Store.DEFAULT_WORLD_KEY, key);
+ }
+
+ @Test
+ public void testAllNonBentoBoxWorldsShareKey() {
+ World world1 = mock(World.class);
+ when(world1.getName()).thenReturn("world");
+ World world2 = mock(World.class);
+ when(world2.getName()).thenReturn("em_adventurers_guild");
+ World world3 = mock(World.class);
+ when(world3.getName()).thenReturn("em_diamond_arena");
+ // None are in bentoboxWorlds
+ assertEquals(Store.DEFAULT_WORLD_KEY, s.getStorageKey(player, world1));
+ assertEquals(Store.DEFAULT_WORLD_KEY, s.getStorageKey(player, world2));
+ assertEquals(Store.DEFAULT_WORLD_KEY, s.getStorageKey(player, world3));
+ }
+
+ @Test
+ public void testBentoBoxToNonBentoBoxRestoresInventory() {
+ sets.setStatistics(false);
+ sets.setAdvancements(false);
+
+ World nonBBWorld = mock(World.class);
+ when(nonBBWorld.getName()).thenReturn("em_adventurers_guild");
+
+ try (MockedStatic mockedBukkit = mockStatic(Bukkit.class, Mockito.RETURNS_MOCKS)) {
+ // Step 1: Enter BentoBox world from non-BB world — saves "outside" inventory
+ s.storeInventory(player, nonBBWorld);
+ s.getInventory(player, world);
+ assertEquals("world", s.getCurrentKey(player));
+
+ // Step 2: Leave BentoBox world to a DIFFERENT non-BB world
+ s.storeInventory(player, world);
+ s.getInventory(player, nonBBWorld);
+ // Should load from DEFAULT_WORLD_KEY (where step 1 saved)
+ assertEquals(Store.DEFAULT_WORLD_KEY, s.getCurrentKey(player));
+
+ // Verify inventory was loaded (setContents called)
+ verify(player.getInventory(), atLeastOnce()).setContents(any(ItemStack[].class));
+ }
+ }
+
+ @Test
+ public void testMigrationFromOldWorldKey() {
+ sets.setStatistics(false);
+ sets.setAdvancements(false);
+
+ // Simulate old data: inventory was saved under "overworld" (old behavior)
+ World overworld = mock(World.class);
+ when(overworld.getName()).thenReturn("overworld");
+ // Temporarily add overworld to BentoBox worlds so storeAndSave uses "overworld" key
+ bentoboxWorlds.add(overworld);
+
+ try (MockedStatic mockedBukkit = mockStatic(Bukkit.class, Mockito.RETURNS_MOCKS)) {
+ s.storeInventory(player, overworld);
+ assertTrue(s.isWorldStored(player, overworld));
+ }
+
+ // Now remove overworld from BentoBox worlds (simulating the fix being applied)
+ bentoboxWorlds.remove(overworld);
+
+ // Loading for a non-BB world should migrate from the old "overworld" key
+ World otherWorld = mock(World.class);
+ when(otherWorld.getName()).thenReturn("em_adventurers_guild");
+ s.getInventory(player, otherWorld);
+ assertEquals(Store.DEFAULT_WORLD_KEY, s.getCurrentKey(player));
+
+ // Verify inventory was loaded (migration found the old "overworld" data)
+ verify(player.getInventory(), atLeastOnce()).setContents(any(ItemStack[].class));
+ }
+
}