From 3deeb90ffcf562f9736ef270cd661a5a41862e3a Mon Sep 17 00:00:00 2001 From: ChrisM-Pek Date: Thu, 27 Aug 2026 09:17:29 +0200 Subject: [PATCH 1/2] fix(sanctuary): compter rubis et saphirs sur toutes les rangees d'inventaire Co-authored-by: Cursor --- sanctuary/build.gradle | 3 +++ .../sanctuary26/sanctuary/shop/ShopService.java | 15 ++------------- .../sanctuary/shop/ShopDeliveryTimingSmoke.java | 5 +++++ 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/sanctuary/build.gradle b/sanctuary/build.gradle index bfe2fe8..845b8af 100644 --- a/sanctuary/build.gradle +++ b/sanctuary/build.gradle @@ -88,6 +88,9 @@ tasks.register("verifyBlackMarket") { || !service.contains("loadedDeliveryBox") || !service.contains("PARCEL_RETENTION_MILLIS") || !policy.contains("DataComponents.CONTAINER") || !policy.contains("DataComponents.BUNDLE_CONTENTS") || !shop.contains("public static final boolean OPEN = true") + || !shop.contains("BlackMarketService.countPlayerItem") + || !shop.contains("BlackMarketService.removePlayerItem") + || shop.contains("getContainerSize()") || !questData.contains('SAVE_KEY = "black_market_quests"') || !quests.contains("ServerLivingEntityEvents.AFTER_DEATH") || !quests.contains("QuestBoardTier.ACTIVATION_COST") diff --git a/sanctuary/src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/ShopService.java b/sanctuary/src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/ShopService.java index 6ec1204..e5bf85d 100644 --- a/sanctuary/src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/ShopService.java +++ b/sanctuary/src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/ShopService.java @@ -237,24 +237,13 @@ public final class ShopService { } private static Item currency(Identifier id) { return BuiltInRegistries.ITEM.getOptional(id).orElse(null); } private static int countCurrency(ServerPlayer player, Item item) { - if (item == null) return 0; - int total = 0; - for (int slot = 0; slot < player.getInventory().getContainerSize(); slot++) { - ItemStack stack = player.getInventory().getItem(slot); if (stack.is(item)) total += stack.getCount(); - } - return total; + return item == null ? 0 : BlackMarketService.countPlayerItem(player, item); } private static boolean hasCurrency(ServerPlayer player, Item item, int count) { return countCurrency(player, item) >= count; } private static void removeCurrency(ServerPlayer player, Item item, int count) { - int remaining = count; - for (int slot = 0; slot < player.getInventory().getContainerSize() && remaining > 0; slot++) { - ItemStack stack = player.getInventory().getItem(slot); - if (!stack.is(item)) continue; - int removed = Math.min(remaining, stack.getCount()); stack.shrink(removed); remaining -= removed; - } - player.getInventory().setChanged(); + BlackMarketService.removePlayerItem(player, item, count); } private static void celebrate(ServerLevel level, BlockPos pos, java.util.UUID owner, ItemStack parcel) { level.playSound(null, pos, SoundEvents.PLAYER_LEVELUP, SoundSource.BLOCKS, 0.65F, 1.35F); diff --git a/sanctuary/src/test/java/fr/koka99cab/sanctuary26/sanctuary/shop/ShopDeliveryTimingSmoke.java b/sanctuary/src/test/java/fr/koka99cab/sanctuary26/sanctuary/shop/ShopDeliveryTimingSmoke.java index 346a11b..abcf664 100644 --- a/sanctuary/src/test/java/fr/koka99cab/sanctuary26/sanctuary/shop/ShopDeliveryTimingSmoke.java +++ b/sanctuary/src/test/java/fr/koka99cab/sanctuary26/sanctuary/shop/ShopDeliveryTimingSmoke.java @@ -1,5 +1,6 @@ package fr.koka99cab.sanctuary26.sanctuary.shop; +import fr.koka99cab.sanctuary26.sanctuary.gameplay.SanctuaryInventoryCapacity; import net.minecraft.util.RandomSource; public final class ShopDeliveryTimingSmoke { @@ -35,5 +36,9 @@ public final class ShopDeliveryTimingSmoke { || ShopProgression.slotCost(10) != -1) { throw new AssertionError("Shop capacity bounds are invalid"); } + if (SanctuaryInventoryCapacity.VANILLA_ROW_COUNT != 4 + || SanctuaryInventoryCapacity.MAX_ROW_COUNT != 6) { + throw new AssertionError("Shop currency counting must include overflow rows 5-6"); + } } } -- 2.54.0 From 3eed6b5a65781f2d5c3b62c84c95baa37288e0e4 Mon Sep 17 00:00:00 2001 From: ChrisM-Pek Date: Thu, 27 Aug 2026 10:27:12 +0200 Subject: [PATCH 2/2] fix(sanctuary): compter aussi les gemmes au rang inventaire 4/5 Co-authored-by: Cursor --- sanctuary/build.gradle | 4 ++ .../SanctuaryPlayerInventoryView.java | 13 ++++- .../sanctuary/shop/BlackMarketService.java | 55 +++++++++++++++++-- .../shop/ShopDeliveryTimingSmoke.java | 5 ++ 4 files changed, 69 insertions(+), 8 deletions(-) diff --git a/sanctuary/build.gradle b/sanctuary/build.gradle index 845b8af..c5ca285 100644 --- a/sanctuary/build.gradle +++ b/sanctuary/build.gradle @@ -74,6 +74,7 @@ tasks.register("verifyBlackMarket") { inputs.file(file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/QuestBoardGenerator.java")) inputs.file(file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/QuestBoardService.java")) inputs.file(file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/QuestBoardTier.java")) + inputs.file(file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/api/inventory/SanctuaryPlayerInventoryView.java")) doLast { def data = file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/BlackMarketData.java").text def service = file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/BlackMarketService.java").text @@ -81,6 +82,7 @@ tasks.register("verifyBlackMarket") { def shop = file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/ShopService.java").text def questData = file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/QuestBoardData.java").text def quests = file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/QuestBoardService.java").text + def inventoryView = file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/api/inventory/SanctuaryPlayerInventoryView.java").text if (!data.contains('SAVE_KEY = "black_market"') || !data.contains("DATA_VERSION = 2") || !data.contains("ItemStack.CODEC.fieldOf(\"item\")") || !data.contains("replaceListing") || !service.contains("LISTING_FEE_RUBIES = 1") || !service.contains("COMMISSION_PERCENT = 5") @@ -91,6 +93,8 @@ tasks.register("verifyBlackMarket") { || !shop.contains("BlackMarketService.countPlayerItem") || !shop.contains("BlackMarketService.removePlayerItem") || shop.contains("getContainerSize()") + || !inventoryView.contains("getNonEquipmentItems") + || !service.contains("currencyStacks") || !questData.contains('SAVE_KEY = "black_market_quests"') || !quests.contains("ServerLivingEntityEvents.AFTER_DEATH") || !quests.contains("QuestBoardTier.ACTIVATION_COST") diff --git a/sanctuary/src/main/java/fr/koka99cab/sanctuary26/sanctuary/api/inventory/SanctuaryPlayerInventoryView.java b/sanctuary/src/main/java/fr/koka99cab/sanctuary26/sanctuary/api/inventory/SanctuaryPlayerInventoryView.java index 54b3e23..1f5965d 100644 --- a/sanctuary/src/main/java/fr/koka99cab/sanctuary26/sanctuary/api/inventory/SanctuaryPlayerInventoryView.java +++ b/sanctuary/src/main/java/fr/koka99cab/sanctuary26/sanctuary/api/inventory/SanctuaryPlayerInventoryView.java @@ -33,8 +33,10 @@ public final class SanctuaryPlayerInventoryView { List slots = new ArrayList<>(rows * SanctuaryInventoryCapacity.ROW_SIZE); Inventory inventory = player.getInventory(); - int vanillaSlots = Math.min(rows, SanctuaryInventoryCapacity.VANILLA_ROW_COUNT) - * SanctuaryInventoryCapacity.ROW_SIZE; + int vanillaSlots = Math.min( + Math.min(rows, SanctuaryInventoryCapacity.VANILLA_ROW_COUNT) + * SanctuaryInventoryCapacity.ROW_SIZE, + inventory.getNonEquipmentItems().size()); for (int slot = 0; slot < vanillaSlots; slot++) { slots.add(new SlotReference(inventory, slot, slot < SanctuaryInventoryCapacity.ROW_SIZE)); } @@ -65,11 +67,16 @@ public final class SanctuaryPlayerInventoryView { public record SlotReference(Container container, int slot, boolean hotbar) { public ItemStack stack() { + if (container instanceof Inventory inventory && slot >= 0 && slot < Inventory.INVENTORY_SIZE) { + List items = inventory.getNonEquipmentItems(); + if (slot < items.size()) return items.get(slot); + } return container.getItem(slot); } public ItemStack remove(int count) { - ItemStack removed = container.removeItem(slot, count); + ItemStack stored = stack(); + ItemStack removed = stored.split(count); container.setChanged(); return removed; } diff --git a/sanctuary/src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/BlackMarketService.java b/sanctuary/src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/BlackMarketService.java index 36aab57..26d790a 100644 --- a/sanctuary/src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/BlackMarketService.java +++ b/sanctuary/src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/BlackMarketService.java @@ -4,11 +4,16 @@ import fr.koka99cab.sanctuary26.sanctuary.SanctuaryMod; import fr.koka99cab.sanctuary26.sanctuary.api.inventory.SanctuaryPlayerInventoryView; import fr.koka99cab.sanctuary26.sanctuary.network.BlackMarketCreatePayload; import fr.koka99cab.sanctuary26.sanctuary.network.BlackMarketEditorPayload; +import fr.koka99cab.sanctuary26.sanctuary.gameplay.SanctuaryOverflowAccess; +import fr.koka99cab.sanctuary26.sanctuary.gameplay.SanctuaryOverflowContainer; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.time.Duration; +import java.util.ArrayList; import java.util.HexFormat; +import java.util.IdentityHashMap; +import java.util.List; import java.util.Optional; import java.util.UUID; import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; @@ -29,8 +34,11 @@ import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.permissions.Permissions; import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundSource; +import net.minecraft.world.Container; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.inventory.Slot; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.block.entity.SignBlockEntity; @@ -345,21 +353,58 @@ public final class BlackMarketService { } private static int countCurrency(ServerPlayer player, Item item) { return countPlayerItem(player, item); } static int countPlayerItem(ServerPlayer player, Item item) { + if (item == null) return 0; long count = 0L; - for (var slot : SanctuaryPlayerInventoryView.unlockedRows(player)) - if (slot.stack().is(item)) count += slot.stack().getCount(); + for (ItemStack stack : currencyStacks(player)) { + if (stack.is(item)) count += stack.getCount(); + } return (int) Math.min(Integer.MAX_VALUE, count); } private static void removeCurrency(ServerPlayer player, Item item, int amount) { removePlayerItem(player, item, amount); } static void removePlayerItem(ServerPlayer player, Item item, int amount) { int remaining = amount; - for (var slot : SanctuaryPlayerInventoryView.unlockedRows(player)) { + for (ItemStack stack : currencyStacks(player)) { if (remaining <= 0) break; - ItemStack stack = slot.stack(); if (!stack.is(item)) continue; int removed = Math.min(remaining, stack.getCount()); - stack.shrink(removed); remaining -= removed; slot.markChanged(); + stack.shrink(removed); + remaining -= removed; } + player.getInventory().setChanged(); + SanctuaryOverflowAccess.of(player).setChanged(); + } + + /** + * Rank 4 (5 rows) puts the second-to-last visual bank on vanilla slots 27-35; + * rank 5 (6 rows) puts it on overflow. Count both the 26.2 main stacks and the + * inventory menu so those banks match what the player sees. + */ + private static List currencyStacks(ServerPlayer player) { + IdentityHashMap seen = new IdentityHashMap<>(); + List stacks = new ArrayList<>(); + for (Slot slot : player.inventoryMenu.slots) { + if (!countsAsPlayerStorage(slot)) continue; + remember(stacks, seen, slot.getItem()); + } + for (var slot : SanctuaryPlayerInventoryView.unlockedRows(player)) { + remember(stacks, seen, slot.stack()); + } + remember(stacks, seen, SanctuaryPlayerInventoryView.offhand(player).stack()); + return stacks; + } + + private static boolean countsAsPlayerStorage(Slot slot) { + Container container = slot.container; + if (container instanceof SanctuaryOverflowContainer) return slot.isActive(); + if (!(container instanceof Inventory)) return false; + int index = slot.getContainerSlot(); + return index >= 0 && index < Inventory.INVENTORY_SIZE; + } + + private static void remember(List stacks, IdentityHashMap seen, + ItemStack stack) { + if (stack == null || stack.isEmpty() || seen.put(stack, Boolean.TRUE) != null) return; + stacks.add(stack); } private static void writeSign(ServerLevel level, SignBlockEntity sign, BlackMarketData.Listing listing) { SignText text = new SignText() diff --git a/sanctuary/src/test/java/fr/koka99cab/sanctuary26/sanctuary/shop/ShopDeliveryTimingSmoke.java b/sanctuary/src/test/java/fr/koka99cab/sanctuary26/sanctuary/shop/ShopDeliveryTimingSmoke.java index abcf664..6ead670 100644 --- a/sanctuary/src/test/java/fr/koka99cab/sanctuary26/sanctuary/shop/ShopDeliveryTimingSmoke.java +++ b/sanctuary/src/test/java/fr/koka99cab/sanctuary26/sanctuary/shop/ShopDeliveryTimingSmoke.java @@ -1,6 +1,7 @@ package fr.koka99cab.sanctuary26.sanctuary.shop; import fr.koka99cab.sanctuary26.sanctuary.gameplay.SanctuaryInventoryCapacity; +import fr.koka99cab.sanctuary26.sanctuary.progression.SanctuaryStat; import net.minecraft.util.RandomSource; public final class ShopDeliveryTimingSmoke { @@ -40,5 +41,9 @@ public final class ShopDeliveryTimingSmoke { || SanctuaryInventoryCapacity.MAX_ROW_COUNT != 6) { throw new AssertionError("Shop currency counting must include overflow rows 5-6"); } + if (SanctuaryStat.INVENTORY.valueAt(4) != 5.0 + || SanctuaryStat.INVENTORY.valueAt(5) != 6.0) { + throw new AssertionError("Inventory ranks 4/5 and 5/5 no longer map to 5 and 6 rows"); + } } } -- 2.54.0