Show Writing Desk page previews like Legacy
Build / build (push) Canceled after 0s

This commit is contained in:
dnorberg committed 2026-09-24 05:17:31 -04:00
1 parent 972aeaaed6
commit 385741027a
5 files changed
+106 -9

No files matched your search

+2
View File
@@ -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
+1 -1
View File
@@ -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.
@@ -271,7 +271,7 @@ public final class NotebookScreen extends AbstractContainerScreen<NotebookMenu>
}
}
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;
@@ -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<WritingDeskMenu> {
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<WritingDesk
i == menu.activeCollection() ? 0xFF7777B6 : 0xFF999999);
slotFrame(graphics, 12, 20 + i * 37);
}
slotFrame(graphics, 370, 20);
slotFrame(graphics, 228, 20);
slotFrame(graphics, 266, 20);
slotFrame(graphics, 304, 20);
slotFrame(graphics, 342, 20);
slotFrame(graphics, 228, 57);
slotFrame(graphics, 370, 57);
for (int row = 0; row < 3; row++) {
for (int column = 0; column < 9; column++) slotFrame(graphics, 224 + column * 18, 91 + row * 18);
}
@@ -46,12 +60,83 @@ public final class WritingDeskScreen extends AbstractContainerScreen<WritingDesk
leftPos + x + 16, topPos + y + 16, 0xFF858585);
}
@Override protected void renderLabels(GuiGraphics graphics, int mouseX, int mouseY) {
graphics.drawString(font, playerInventoryTitle, inventoryLabelX, inventoryLabelY, 0x404040, false);
}
@Override public void render(GuiGraphics graphics, int mouseX, int mouseY, float partialTick) {
super.render(graphics, mouseX, mouseY, partialTick);
renderCollection(graphics);
renderTooltip(graphics, mouseX, mouseY);
}
private List<ItemStack> 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<ItemStack> 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<ItemStack> 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<WritingDesk
}
return super.mouseClicked(mouseX, mouseY, button);
}
@Override public boolean mouseScrolled(double mouseX, double mouseY, double scrollX, double scrollY) {
if (mouseX >= 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);
}
}
@@ -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));