From e4b5f5221c48b906ba68740cdfc068e1e959eb16 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 20 May 2026 21:58:37 +0000 Subject: [PATCH 1/3] Initial plan From 444977e1b0eeecc27815c6bbba74993a5c9c569c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 20 May 2026 22:07:27 +0000 Subject: [PATCH 2/3] Fix XP increase when teleporting between worlds with advancements When granting advancement criteria via awardCriteria(), some Minecraft advancements reward XP, causing the player's experience to increase on every world switch. Fix by saving the player's current XP before granting advancement criteria in setAdvancements() and restoring it afterward. Also add test testGetInventoryAdvancementsPreservesExperience to verify that setTotalExperience is called after advancement criteria are awarded, ensuring XP is properly restored. Agent-Logs-Url: https://github.com/BentoBoxWorld/InvSwitcher/sessions/dde552a1-224e-42d1-94cb-218e3609eaf8 Co-authored-by: tastybento <4407265+tastybento@users.noreply.github.com> --- .../6fe7981a-2e32-439e-9aaf-1de05cb43e26.json | 39 ++++++++++++++++ .../b878f9a4-d9f0-41e1-9d37-3c6e67e446a8.json | 24 ++++++++++ .../com/wasteofplastic/invswitcher/Store.java | 13 +++++- .../wasteofplastic/invswitcher/StoreTest.java | 44 +++++++++++++++++++ 4 files changed, 118 insertions(+), 2 deletions(-) create mode 100644 database_backup/InventoryStorage/6fe7981a-2e32-439e-9aaf-1de05cb43e26.json create mode 100644 database_backup/InventoryStorage/b878f9a4-d9f0-41e1-9d37-3c6e67e446a8.json diff --git a/database_backup/InventoryStorage/6fe7981a-2e32-439e-9aaf-1de05cb43e26.json b/database_backup/InventoryStorage/6fe7981a-2e32-439e-9aaf-1de05cb43e26.json new file mode 100644 index 0000000..b72bced --- /dev/null +++ b/database_backup/InventoryStorage/6fe7981a-2e32-439e-9aaf-1de05cb43e26.json @@ -0,0 +1,39 @@ +{ + "uniqueId": "6fe7981a-2e32-439e-9aaf-1de05cb43e26", + "inventory": { + "default": [ + "is:\n ==: org.bukkit.inventory.ItemStack\n", + null, + "is:\n ==: org.bukkit.inventory.ItemStack\n", + null, + null, + "is:\n ==: org.bukkit.inventory.ItemStack\n" + ] + }, + "health": { + "default": 0.0 + }, + "food": { + "default": 0 + }, + "exp": { + "default": 0 + }, + "location": {}, + "gameMode": {}, + "advancements": {}, + "enderChest": { + "default": [ + "is:\n ==: org.bukkit.inventory.ItemStack\n", + null, + "is:\n ==: org.bukkit.inventory.ItemStack\n", + null, + null, + "is:\n ==: org.bukkit.inventory.ItemStack\n" + ] + }, + "untypedStats": {}, + "blockStats": {}, + "itemStats": {}, + "entityStats": {} +} \ No newline at end of file diff --git a/database_backup/InventoryStorage/b878f9a4-d9f0-41e1-9d37-3c6e67e446a8.json b/database_backup/InventoryStorage/b878f9a4-d9f0-41e1-9d37-3c6e67e446a8.json new file mode 100644 index 0000000..679ba6a --- /dev/null +++ b/database_backup/InventoryStorage/b878f9a4-d9f0-41e1-9d37-3c6e67e446a8.json @@ -0,0 +1,24 @@ +{ + "uniqueId": "b878f9a4-d9f0-41e1-9d37-3c6e67e446a8", + "inventory": { + "world/island-primary": [ + "is:\n ==: org.bukkit.inventory.ItemStack\n", + null, + "is:\n ==: org.bukkit.inventory.ItemStack\n", + null, + null, + "is:\n ==: org.bukkit.inventory.ItemStack\n" + ] + }, + "health": {}, + "food": {}, + "exp": {}, + "location": {}, + "gameMode": {}, + "advancements": {}, + "enderChest": {}, + "untypedStats": {}, + "blockStats": {}, + "itemStats": {}, + "entityStats": {} +} \ No newline at end of file diff --git a/src/main/java/com/wasteofplastic/invswitcher/Store.java b/src/main/java/com/wasteofplastic/invswitcher/Store.java index 5ef1022..9454697 100644 --- a/src/main/java/com/wasteofplastic/invswitcher/Store.java +++ b/src/main/java/com/wasteofplastic/invswitcher/Store.java @@ -320,7 +320,15 @@ private void setFood(InventoryStorage store, Player player, String overworldName private void setAdvancements(InventoryStorage store, Player player, String overworldName) { // Advancements - store.getAdvancements(overworldName).forEach((k, v) -> { + Map> advancements = store.getAdvancements(overworldName); + if (advancements.isEmpty()) { + return; + } + // Save current experience before granting advancements, because some advancements + // reward XP when their criteria are awarded, which would incorrectly increase the + // player's experience points. + int savedExp = getTotalExperience(player); + advancements.forEach((k, v) -> { Iterator it = Bukkit.advancementIterator(); while (it.hasNext()) { Advancement a = it.next(); @@ -330,7 +338,8 @@ private void setAdvancements(InventoryStorage store, Player player, String overw } } }); - + // Restore experience to prevent advancement rewards from modifying it + setTotalExperience(player, savedExp); } public void removeFromCache(Player player) { diff --git a/src/test/java/com/wasteofplastic/invswitcher/StoreTest.java b/src/test/java/com/wasteofplastic/invswitcher/StoreTest.java index dfe5419..9cdb000 100644 --- a/src/test/java/com/wasteofplastic/invswitcher/StoreTest.java +++ b/src/test/java/com/wasteofplastic/invswitcher/StoreTest.java @@ -22,6 +22,7 @@ import java.nio.file.Path; import java.util.Comparator; import java.util.HashSet; +import java.util.List; import java.util.Optional; import java.util.Set; import java.util.UUID; @@ -30,8 +31,11 @@ import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.NamespacedKey; import org.bukkit.World; import org.bukkit.World.Environment; +import org.bukkit.advancement.Advancement; +import org.bukkit.advancement.AdvancementProgress; import org.bukkit.attribute.AttributeInstance; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; @@ -200,6 +204,46 @@ public void testGetInventory() { verify(player).setTotalExperience(0); } + /** + * Test that advancement grants during {@link Store#getInventory} do not modify the player's + * experience points. Some advancements reward XP when their criteria are awarded; the store + * must save and restore XP around the advancement grant step. + */ + @Test + public void testGetInventoryAdvancementsPreservesExperience() { + sets.setAdvancements(true); + sets.setExperience(true); + sets.setStatistics(false); + sets.setIslandsActive(false); + + // Mock an advancement with awarded criteria + Advancement advancement = mock(Advancement.class); + NamespacedKey advKey = NamespacedKey.minecraft("story_mine_stone"); + when(advancement.getKey()).thenReturn(advKey); + + AdvancementProgress progress = mock(AdvancementProgress.class); + Set criteria = new HashSet<>(Set.of("mine_stone")); + when(progress.getAwardedCriteria()).thenReturn(criteria); + when(player.getAdvancementProgress(advancement)).thenReturn(progress); + + try (MockedStatic mockedBukkit = mockStatic(Bukkit.class, Mockito.RETURNS_MOCKS)) { + // Return a fresh iterator each time so both storeInventory and getInventory can iterate + mockedBukkit.when(Bukkit::advancementIterator).thenAnswer(inv -> List.of(advancement).iterator()); + + // Store inventory (saves advancement data and clears player including XP reset) + s.storeInventory(player, world); + + // Load inventory — experience set, advancements granted, XP restored + s.getInventory(player, world); + } + + // setTotalExperience should be called exactly 3 times: + // 1. clearPlayer during storeInventory (XP reset to 0) + // 2. experience loading during getInventory (XP set to stored value 0) + // 3. XP restoration inside setAdvancements after granting advancement criteria + verify(player, times(3)).setTotalExperience(0); + } + /** * Test method for {@link com.wasteofplastic.invswitcher.Store#removeFromCache(org.bukkit.entity.Player)}. */ From ea50727c2261924837af2c25b68b33317eaddd0c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 20 May 2026 22:07:48 +0000 Subject: [PATCH 3/3] Remove accidentally committed test database files and add to .gitignore Agent-Logs-Url: https://github.com/BentoBoxWorld/InvSwitcher/sessions/dde552a1-224e-42d1-94cb-218e3609eaf8 Co-authored-by: tastybento <4407265+tastybento@users.noreply.github.com> --- .gitignore | 4 ++ .../6fe7981a-2e32-439e-9aaf-1de05cb43e26.json | 39 ------------------- .../b878f9a4-d9f0-41e1-9d37-3c6e67e446a8.json | 24 ------------ 3 files changed, 4 insertions(+), 63 deletions(-) delete mode 100644 database_backup/InventoryStorage/6fe7981a-2e32-439e-9aaf-1de05cb43e26.json delete mode 100644 database_backup/InventoryStorage/b878f9a4-d9f0-41e1-9d37-3c6e67e446a8.json diff --git a/.gitignore b/.gitignore index 5e2fb46..46abb5a 100644 --- a/.gitignore +++ b/.gitignore @@ -46,6 +46,10 @@ release.properties dependency-reduced-pom.xml buildNumber.properties + # Test artifacts +database/ +database_backup/ + # Intellij *.iml *.java___jb_tmp___ diff --git a/database_backup/InventoryStorage/6fe7981a-2e32-439e-9aaf-1de05cb43e26.json b/database_backup/InventoryStorage/6fe7981a-2e32-439e-9aaf-1de05cb43e26.json deleted file mode 100644 index b72bced..0000000 --- a/database_backup/InventoryStorage/6fe7981a-2e32-439e-9aaf-1de05cb43e26.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "uniqueId": "6fe7981a-2e32-439e-9aaf-1de05cb43e26", - "inventory": { - "default": [ - "is:\n ==: org.bukkit.inventory.ItemStack\n", - null, - "is:\n ==: org.bukkit.inventory.ItemStack\n", - null, - null, - "is:\n ==: org.bukkit.inventory.ItemStack\n" - ] - }, - "health": { - "default": 0.0 - }, - "food": { - "default": 0 - }, - "exp": { - "default": 0 - }, - "location": {}, - "gameMode": {}, - "advancements": {}, - "enderChest": { - "default": [ - "is:\n ==: org.bukkit.inventory.ItemStack\n", - null, - "is:\n ==: org.bukkit.inventory.ItemStack\n", - null, - null, - "is:\n ==: org.bukkit.inventory.ItemStack\n" - ] - }, - "untypedStats": {}, - "blockStats": {}, - "itemStats": {}, - "entityStats": {} -} \ No newline at end of file diff --git a/database_backup/InventoryStorage/b878f9a4-d9f0-41e1-9d37-3c6e67e446a8.json b/database_backup/InventoryStorage/b878f9a4-d9f0-41e1-9d37-3c6e67e446a8.json deleted file mode 100644 index 679ba6a..0000000 --- a/database_backup/InventoryStorage/b878f9a4-d9f0-41e1-9d37-3c6e67e446a8.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "uniqueId": "b878f9a4-d9f0-41e1-9d37-3c6e67e446a8", - "inventory": { - "world/island-primary": [ - "is:\n ==: org.bukkit.inventory.ItemStack\n", - null, - "is:\n ==: org.bukkit.inventory.ItemStack\n", - null, - null, - "is:\n ==: org.bukkit.inventory.ItemStack\n" - ] - }, - "health": {}, - "food": {}, - "exp": {}, - "location": {}, - "gameMode": {}, - "advancements": {}, - "enderChest": {}, - "untypedStats": {}, - "blockStats": {}, - "itemStats": {}, - "entityStats": {} -} \ No newline at end of file