From dc5157f97320becd309c7c1310816376259da684 Mon Sep 17 00:00:00 2001 From: Dustin Norberg Date: Thu, 24 Sep 2026 04:23:28 -0400 Subject: [PATCH] Fix notebook inventory clicks and ALL button --- gradle.properties | 2 +- .../client/screen/NotebookScreen.java | 4 +-- .../gametest/WritingDataGameTests.java | 24 ++++++++++++++ .../rivencraft/menu/NotebookMenu.java | 32 +++++++++++++------ 4 files changed, 49 insertions(+), 13 deletions(-) diff --git a/gradle.properties b/gradle.properties index b267552..98e9d96 100644 --- a/gradle.properties +++ b/gradle.properties @@ -35,7 +35,7 @@ mod_name=Rivencraft # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. mod_license=LGPL-3.0-or-later # The mod version. Rivencraft uses the x.y.z.b policy documented in README.md. -mod_version=0.3.3.2 +mod_version=0.3.3.3 immersive_portals_version=6.0.7 # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # This should match the base package used for the mod sources. diff --git a/src/main/java/net/dnorberg/rivencraft/client/screen/NotebookScreen.java b/src/main/java/net/dnorberg/rivencraft/client/screen/NotebookScreen.java index d4b6425..3d6f223 100644 --- a/src/main/java/net/dnorberg/rivencraft/client/screen/NotebookScreen.java +++ b/src/main/java/net/dnorberg/rivencraft/client/screen/NotebookScreen.java @@ -47,12 +47,12 @@ public final class NotebookScreen extends AbstractContainerScreen Button sortButton = Button.builder(Component.literal("AZ"), button -> {}) .bounds(leftPos, topPos, 18, 18).build(); Button allButton = Button.builder(Component.literal("ALL"), button -> {}) - .bounds(leftPos + 20, topPos, 18, 18).build(); + .bounds(leftPos + 20, topPos, 26, 18).build(); sortButton.active = false; allButton.active = false; addRenderableWidget(sortButton); addRenderableWidget(allButton); - textInput = new EditBox(font, leftPos + 40, topPos, 94, 18, + textInput = new EditBox(font, leftPos + 48, topPos, 86, 18, Component.translatable("screen.rivencraft.notebook.search")); textInput.setMaxLength(32); textInput.setHint(Component.translatable("screen.rivencraft.notebook.search")); diff --git a/src/main/java/net/dnorberg/rivencraft/gametest/WritingDataGameTests.java b/src/main/java/net/dnorberg/rivencraft/gametest/WritingDataGameTests.java index ae5a3c1..fed17ee 100644 --- a/src/main/java/net/dnorberg/rivencraft/gametest/WritingDataGameTests.java +++ b/src/main/java/net/dnorberg/rivencraft/gametest/WritingDataGameTests.java @@ -22,6 +22,7 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.world.InteractionHand; +import net.minecraft.world.inventory.ClickType; import net.neoforged.neoforge.gametest.GameTestHolder; import net.neoforged.neoforge.gametest.PrefixGameTestTemplate; @@ -176,6 +177,29 @@ public final class WritingDataGameTests { helper.succeed(); } + @GameTest(template = "empty") + public static void notebookMenuSurvivesInventoryStackReplacementAndClicks(GameTestHelper helper) { + var player = helper.makeMockServerPlayerInLevel(); + player.setItemInHand(InteractionHand.MAIN_HAND, new ItemStack(ModItems.NOTEBOOK.get())); + NotebookMenu menu = new NotebookMenu(8, player.getInventory(), InteractionHand.MAIN_HAND); + + // Slot synchronization may replace the ItemStack object while the Notebook remains held. + player.setItemInHand(InteractionHand.MAIN_HAND, player.getMainHandItem().copy()); + helper.assertTrue(menu.stillValid(player), + "Replacing the held stack object must not close an open Notebook menu"); + menu.getSlot(0).set(PageItem.createSymbolPage(reference("rivencraft:terrain/standard"))); + helper.assertTrue(player.getMainHandItem().has(ModDataComponents.NOTEBOOK_CONTENTS.get()), + "Page edits must persist to the current held Notebook stack"); + + player.getInventory().setItem(9, new ItemStack(Items.DIRT)); + menu.clicked(NotebookMenu.NOTEBOOK_SLOTS, 0, ClickType.PICKUP, player); + helper.assertTrue(menu.getCarried().is(Items.DIRT), + "Clicking a player inventory item must pick it up without closing the Notebook"); + helper.assertTrue(menu.stillValid(player), + "Normal inventory clicks must leave the Notebook menu valid"); + helper.succeed(); + } + private static SymbolReference reference(String id) { return new SymbolReference(ResourceLocation.parse(id)); } diff --git a/src/main/java/net/dnorberg/rivencraft/menu/NotebookMenu.java b/src/main/java/net/dnorberg/rivencraft/menu/NotebookMenu.java index 8e17066..80829d6 100644 --- a/src/main/java/net/dnorberg/rivencraft/menu/NotebookMenu.java +++ b/src/main/java/net/dnorberg/rivencraft/menu/NotebookMenu.java @@ -26,7 +26,7 @@ public final class NotebookMenu extends AbstractContainerMenu { private static final int PLAYER_INVENTORY_START = NOTEBOOK_SLOTS; private final Inventory playerInventory; private final InteractionHand hand; - private final ItemStack notebook; + private final int openedHotbarSlot; private final NotebookContainer contents; public NotebookMenu(int containerId, Inventory inventory, RegistryFriendlyByteBuf data) { @@ -37,8 +37,8 @@ public final class NotebookMenu extends AbstractContainerMenu { super(ModMenus.NOTEBOOK.get(), containerId); this.playerInventory = inventory; this.hand = hand; - this.notebook = inventory.player.getItemInHand(hand); - this.contents = new NotebookContainer(notebook); + this.openedHotbarSlot = inventory.selected; + this.contents = new NotebookContainer(inventory, hand); for (int row = 0; row < 3; row++) { for (int column = 0; column < 9; column++) { @@ -58,14 +58,16 @@ public final class NotebookMenu extends AbstractContainerMenu { } private Slot playerSlot(int inventoryIndex, int x, int y) { - boolean locked = hand == InteractionHand.MAIN_HAND && inventoryIndex == playerInventory.selected; + boolean locked = hand == InteractionHand.MAIN_HAND && inventoryIndex == openedHotbarSlot; return locked ? new LockedSlot(playerInventory, inventoryIndex, x, y) : new Slot(playerInventory, inventoryIndex, x, y); } @Override public boolean stillValid(Player player) { - return player.isAlive() && player.getItemInHand(hand) == notebook && notebook.is(ModItems.NOTEBOOK.get()); + return player.isAlive() + && (hand == InteractionHand.OFF_HAND || player.getInventory().selected == openedHotbarSlot) + && player.getItemInHand(hand).is(ModItems.NOTEBOOK.get()); } @Override @@ -135,10 +137,16 @@ public final class NotebookMenu extends AbstractContainerMenu { @Override public void clicked(int slotId, int button, ClickType clickType, Player player) { - super.clicked(slotId, button, clickType, player); if (!stillValid(player)) { player.closeContainer(); + return; } + if (clickType == ClickType.SWAP + && (button == openedHotbarSlot && hand == InteractionHand.MAIN_HAND + || button == 40 && hand == InteractionHand.OFF_HAND)) { + return; + } + super.clicked(slotId, button, clickType, player); } private static final class PageSlot extends Slot { @@ -160,12 +168,15 @@ public final class NotebookMenu extends AbstractContainerMenu { } private static final class NotebookContainer extends SimpleContainer { - private final ItemStack notebook; + private final Inventory inventory; + private final InteractionHand hand; private boolean loading; - private NotebookContainer(ItemStack notebook) { + private NotebookContainer(Inventory inventory, InteractionHand hand) { super(NOTEBOOK_SLOTS); - this.notebook = notebook; + this.inventory = inventory; + this.hand = hand; + ItemStack notebook = inventory.player.getItemInHand(hand); loading = true; List saved = notebook.getOrDefault( ModDataComponents.NOTEBOOK_CONTENTS.get(), NotebookContents.EMPTY).pages(); @@ -187,7 +198,8 @@ public final class NotebookMenu extends AbstractContainerMenu { @Override public void setChanged() { super.setChanged(); - if (loading || notebook.isEmpty()) { + ItemStack notebook = inventory.player.getItemInHand(hand); + if (loading || !notebook.is(ModItems.NOTEBOOK.get())) { return; } NonNullList saved = NonNullList.withSize(NOTEBOOK_SLOTS, ItemStack.EMPTY);