diff --git a/README.md b/README.md index eff9e1d..4a40527 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,8 @@ Its four collection tabs, ink/source/page work slots, and inventory persist through world saves; breaking it drops stored contents. The desk screen is a functional foundation styled after Legacy's left tabs, central writing surface, and right inventory. Transcription controls are not implemented yet. +Selecting a stored page on the desk surface shows its Legacy-proportioned +portrait preview and name above the player inventory. ## Linking Book diff --git a/gradle.properties b/gradle.properties index 368aa99..b131bdf 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.5.0 +mod_version=0.3.5.1 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 81ebcbb..979cc55 100644 --- a/src/main/java/net/dnorberg/rivencraft/client/screen/NotebookScreen.java +++ b/src/main/java/net/dnorberg/rivencraft/client/screen/NotebookScreen.java @@ -271,7 +271,7 @@ public final class NotebookScreen extends AbstractContainerScreen } } - private static ResourceLocation symbolTexture(ItemStack page) { + static ResourceLocation symbolTexture(ItemStack page) { var content = PageItem.content(page); if (content.kind() == net.dnorberg.rivencraft.writing.PageContent.Kind.UNRESOLVED_SYMBOL) { return UNRESOLVED_SYMBOL; diff --git a/src/main/java/net/dnorberg/rivencraft/client/screen/WritingDeskScreen.java b/src/main/java/net/dnorberg/rivencraft/client/screen/WritingDeskScreen.java index 6698c2d..7fe538e 100644 --- a/src/main/java/net/dnorberg/rivencraft/client/screen/WritingDeskScreen.java +++ b/src/main/java/net/dnorberg/rivencraft/client/screen/WritingDeskScreen.java @@ -1,13 +1,27 @@ package net.dnorberg.rivencraft.client.screen; +import java.util.List; +import net.dnorberg.rivencraft.Rivencraft; +import net.dnorberg.rivencraft.item.PageItem; import net.dnorberg.rivencraft.menu.WritingDeskMenu; +import net.dnorberg.rivencraft.registry.ModDataComponents; +import net.dnorberg.rivencraft.registry.ModItems; +import net.dnorberg.rivencraft.writing.NotebookContents; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.item.ItemStack; /** Functional storage surface; full Legacy transcription controls are a later Milestone 4 slice. */ public final class WritingDeskScreen extends AbstractContainerScreen { + private static final ResourceLocation PAGE_ATLAS = ResourceLocation.fromNamespaceAndPath( + Rivencraft.MOD_ID, "textures/gui/notebook_pages.png"); + private int lastCollection = -1; + private int selectedPage; + private int scrollRows; + public WritingDeskScreen(WritingDeskMenu menu, Inventory inventory, Component title) { super(menu, inventory, title); imageWidth = 398; @@ -29,10 +43,10 @@ public final class WritingDeskScreen extends AbstractContainerScreen pages() { + ItemStack collection = menu.getSlot(menu.activeCollection()).getItem(); + if (collection.is(ModItems.PAGE.get())) return List.of(collection); + if (collection.is(ModItems.NOTEBOOK.get())) { + return collection.getOrDefault(ModDataComponents.NOTEBOOK_CONTENTS.get(), NotebookContents.EMPTY).pages(); + } + return List.of(); + } + + private void renderCollection(GuiGraphics graphics) { + List pages = pages(); + if (lastCollection != menu.activeCollection()) { + lastCollection = menu.activeCollection(); + scrollRows = 0; + selectedPage = 0; + } + int last = -1; + for (int i = 0; i < pages.size(); i++) if (!pages.get(i).isEmpty()) last = i; + for (int i = scrollRows * 5; i <= last && i < scrollRows * 5 + 15; i++) { + int column = i % 5; + int row = i / 5 - scrollRows; + ItemStack page = pages.get(i); + int x = leftPos + 48 + column * 31; + int y = topPos + 18 + row * 41; + drawPage(graphics, page, x, y); + if (page.isEmpty()) graphics.fill(x, y, x + 30, y + 40, 0xB8000000); + if (i == selectedPage && !page.isEmpty()) graphics.renderOutline(x, y, 30, 40, 0xFFFFD061); + } + if (selectedPage >= pages.size() || pages.get(selectedPage).isEmpty()) return; + ItemStack selected = pages.get(selectedPage); + graphics.pose().pushPose(); + graphics.pose().translate(leftPos + 294, topPos + 12, 0); + graphics.pose().scale(1.35F, 1.35F, 1.0F); + drawPage(graphics, selected, 0, 0); + graphics.pose().popPose(); + String title = font.plainSubstrByWidth(selected.getHoverName().getString(), 112); + graphics.fill(leftPos + 251, topPos + 64, leftPos + 365, topPos + 77, 0xFF202020); + graphics.drawString(font, title, leftPos + 254, topPos + 67, 0xFFE0E0E0, false); + } + + private void drawPage(GuiGraphics graphics, ItemStack page, int x, int y) { + graphics.blit(PAGE_ATLAS, x, y, 30, 40, 156, 0, 30, 40, 256, 256); + if (page.isEmpty()) return; + switch (PageItem.content(page).kind()) { + case BLANK -> { } + case LINK_PANEL -> graphics.fill(x + 5, y + 6, x + 25, y + 20, 0xFF000000); + case SYMBOL, UNRESOLVED_SYMBOL -> graphics.blit(NotebookScreen.symbolTexture(page), x + 1, y + 6, + 28, 28, 16, 16, 96, 96, 128, 128); + } + } + @Override public boolean mouseClicked(double mouseX, double mouseY, int button) { + if (button == 0) { + int x = (int) mouseX - leftPos - 48; + int y = (int) mouseY - topPos - 18; + if (x >= 0 && x < 155 && y >= 0 && y < 123) { + int column = x / 31; + int row = y / 41; + int index = (row + scrollRows) * 5 + column; + List pages = pages(); + if (x % 31 < 30 && y % 41 < 40 && index < pages.size() + && !pages.get(index).isEmpty()) { + selectedPage = index; + } + return true; + } + } if (button == 0 && mouseX >= leftPos + 29 && mouseX < leftPos + 40) { for (int i = 0; i < 4; i++) { int top = topPos + 16 + i * 37; @@ -65,4 +150,14 @@ public final class WritingDeskScreen extends AbstractContainerScreen= leftPos + 48 && mouseX < leftPos + 203 + && mouseY >= topPos + 18 && mouseY < topPos + 141) { + int rows = (pages().size() + 4) / 5; + scrollRows = Math.clamp(scrollRows - (int) Math.signum(scrollY), 0, Math.max(0, rows - 3)); + return true; + } + return super.mouseScrolled(mouseX, mouseY, scrollX, scrollY); + } } diff --git a/src/main/java/net/dnorberg/rivencraft/menu/WritingDeskMenu.java b/src/main/java/net/dnorberg/rivencraft/menu/WritingDeskMenu.java index 916e713..5e8f5cd 100644 --- a/src/main/java/net/dnorberg/rivencraft/menu/WritingDeskMenu.java +++ b/src/main/java/net/dnorberg/rivencraft/menu/WritingDeskMenu.java @@ -36,10 +36,10 @@ public final class WritingDeskMenu extends AbstractContainerMenu { for (int i = 0; i < WritingDeskBlockEntity.COLLECTIONS; i++) { addSlot(new DeskSlot(desk, i, 12, 20 + i * 37, 1)); } - addSlot(new DeskSlot(desk, WritingDeskBlockEntity.INK, 228, 20, 1)); - addSlot(new DeskSlot(desk, WritingDeskBlockEntity.SOURCE, 266, 20, 1)); - addSlot(new DeskSlot(desk, WritingDeskBlockEntity.PAPER, 304, 20, 64)); - addSlot(new DeskSlot(desk, WritingDeskBlockEntity.OUTPUT, 342, 20, 64)); + addSlot(new DeskSlot(desk, WritingDeskBlockEntity.INK, 370, 20, 1)); + addSlot(new DeskSlot(desk, WritingDeskBlockEntity.SOURCE, 228, 20, 1)); + addSlot(new DeskSlot(desk, WritingDeskBlockEntity.PAPER, 228, 57, 64)); + addSlot(new DeskSlot(desk, WritingDeskBlockEntity.OUTPUT, 370, 57, 64)); for (int row = 0; row < 3; row++) { for (int column = 0; column < 9; column++) { addSlot(new Slot(inventory, column + row * 9 + 9, 224 + column * 18, 91 + row * 18));