Refine Writing Desk GUI to match Legacy layout
Build / build (push) Canceled after 0s

This commit is contained in:
dnorberg committed 2026-09-24 14:54:42 -04:00
1 parent 7f9cf2a4a5
commit e2e348d5c5
5 files changed
+216 -138

No files matched your search

@@ -2,7 +2,8 @@ package net.dnorberg.rivencraft.client.screen;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.ArrayList;
import java.util.Comparator;
import net.dnorberg.rivencraft.Rivencraft;
import net.dnorberg.rivencraft.item.PageItem;
import net.dnorberg.rivencraft.menu.WritingDeskMenu;
@@ -29,56 +30,83 @@ public final class WritingDeskScreen extends AbstractContainerScreen<WritingDesk
private int selectedPage;
private int scrollRows;
private boolean allMode;
private ResourceLocation selectedSymbol;
private boolean sortAlphabetically;
private int selectedCollection = -1;
private ResourceLocation selectedCategory;
private EditBox search;
private Button categoryButton;
private Button allButton;
private Button sortButton;
private boolean draggingScrollbar;
private record DisplayPage(int collection, int index, ItemStack stack) {}
public WritingDeskScreen(WritingDeskMenu menu, Inventory inventory, Component title) {
super(menu, inventory, title);
imageWidth = 398;
imageHeight = 176;
titleLabelX = 222;
inventoryLabelX = 224;
inventoryLabelY = 79;
}
@Override protected void init() {
super.init();
addRenderableWidget(Button.builder(Component.literal("ALL"), button -> {
allMode = true;
sortButton = addRenderableWidget(Button.builder(Component.literal("AZ"), button -> {
sortAlphabetically = !sortAlphabetically;
scrollRows = 0;
}).bounds(leftPos + 48, topPos - 18, 29, 18).build());
categoryButton = addRenderableWidget(Button.builder(Component.literal("All types"), button -> {
}).bounds(leftPos + 58, topPos - 18, 20, 18).build());
allButton = addRenderableWidget(Button.builder(Component.literal("ALL"), button -> {
allMode = !allMode;
scrollRows = 0;
if (!allMode) {
selectedCollection = -1;
selectedPage = 0;
if (minecraft != null && minecraft.gameMode != null)
minecraft.gameMode.handleInventoryButtonClick(menu.containerId, menu.activeCollection());
}
}).bounds(leftPos + 80, topPos - 18, 28, 18).build());
search = new EditBox(font, leftPos + 110, topPos - 18, 86, 18,
Component.translatable("screen.rivencraft.writing_desk.search"));
search.setMaxLength(64);
search.setHint(Component.translatable("screen.rivencraft.writing_desk.search"));
search.setResponder(value -> scrollRows = 0);
addRenderableWidget(search);
categoryButton = addRenderableWidget(Button.builder(Component.literal("C"), button -> {
List<ResourceLocation> categories = menu.catalog().stream()
.map(SymbolDisplayMetadata::category).distinct().sorted().toList();
int next = selectedCategory == null ? 0 : categories.indexOf(selectedCategory) + 1;
selectedCategory = next >= categories.size() ? null : categories.get(next);
categoryButton.setMessage(Component.literal(selectedCategory == null
? "All types" : selectedCategory.getPath()));
allMode = true;
categoryButton.setMessage(Component.literal(selectedCategory == null ? "C" : "C*"));
scrollRows = 0;
}).bounds(leftPos + 79, topPos - 18, 66, 18).build());
search = new EditBox(font, leftPos + 147, topPos - 18, 69, 18,
Component.translatable("screen.rivencraft.writing_desk.search"));
search.setMaxLength(64);
search.setHint(Component.translatable("screen.rivencraft.writing_desk.search"));
search.setResponder(value -> {
allMode = true;
scrollRows = 0;
});
addRenderableWidget(search);
}).bounds(leftPos + 198, topPos - 18, 18, 18).build());
}
private List<SymbolDisplayMetadata> filteredCatalog() {
private List<DisplayPage> filteredPages() {
String query = search == null ? "" : search.getValue().trim().toLowerCase(Locale.ROOT);
return menu.catalog().stream()
.filter(entry -> selectedCategory == null || selectedCategory.equals(entry.category()))
.filter(entry -> query.isEmpty()
|| entry.id().toString().toLowerCase(Locale.ROOT).contains(query)
|| Component.translatable(entry.nameTranslationKey()).getString()
.toLowerCase(Locale.ROOT).contains(query))
.toList();
List<DisplayPage> entries = new ArrayList<>();
int from = allMode ? 0 : menu.activeCollection();
int until = allMode ? 4 : from + 1;
for (int collection = from; collection < until; collection++) {
List<ItemStack> pages = pages(collection);
int last = -1;
for (int i = 0; i < pages.size(); i++) if (!pages.get(i).isEmpty()) last = i;
for (int i = 0; i <= last; i++) {
ItemStack page = pages.get(i);
if (page.isEmpty() && (allMode || sortAlphabetically || !query.isEmpty() || selectedCategory != null)) continue;
if (!page.isEmpty() && !query.isEmpty()
&& !page.getHoverName().getString().toLowerCase(Locale.ROOT).contains(query)
&& !PageItem.content(page).symbol().map(symbol -> symbol.id().toString()
.toLowerCase(Locale.ROOT).contains(query)).orElse(false)) continue;
if (!page.isEmpty() && selectedCategory != null) {
ResourceLocation id = PageItem.content(page).symbol().map(symbol -> symbol.id()).orElse(null);
if (menu.catalog().stream().noneMatch(metadata -> metadata.id().equals(id)
&& metadata.category().equals(selectedCategory))) continue;
}
entries.add(new DisplayPage(collection, i, page));
}
}
if (sortAlphabetically) entries.sort(Comparator
.comparing((DisplayPage entry) -> entry.stack().getHoverName().getString(), String.CASE_INSENSITIVE_ORDER)
.thenComparingInt(DisplayPage::collection).thenComparingInt(DisplayPage::index));
return entries;
}
@Override public void renderBackground(GuiGraphics graphics, int mouseX, int mouseY, float partialTick) {
@@ -90,28 +118,40 @@ public final class WritingDeskScreen extends AbstractContainerScreen<WritingDesk
@Override protected void renderBg(GuiGraphics graphics, float partialTick, int mouseX, int mouseY) {
int x = leftPos;
int y = topPos;
// Use textured backing: GUI fills may depth-test behind the world with some renderers.
graphics.fill(x + 56, y + 14, x + 206, y + 168, 0xAA201B18);
graphics.blit(LEGACY_DESK, x, y + 5, 56, 9, 0, 166, 56, 9, 256, 256);
graphics.blit(LEGACY_DESK, x, y + 166, 56, 9, 0, 215, 56, 9, 256, 256);
graphics.blit(LEGACY_DESK, x + 218, y + 4, 178, 170, 64, 8, 16, 16, 256, 256);
for (int i = 0; i < 4; i++) {
graphics.blit(LEGACY_DESK, x + 6, y + 16 + i * 37,
34, 32, 0, 166, 56, 54, 256, 256);
if (i == menu.activeCollection())
graphics.renderOutline(x + 6, y + 16 + i * 37, 34, 32, 0xFF7777B6);
slotFrame(graphics, 12, 20 + i * 37);
graphics.blit(LEGACY_DESK, x, y + 16 + i * 37,
56, 36, 0, 166, 56, 54, 256, 256);
if (i == menu.activeCollection() && !allMode)
graphics.fill(x + 2, y + 18 + i * 37, x + 54, y + 46 + i * 37, 0x885858CC);
graphics.drawString(font, new String[]{"I", "II", "III", "IV"}[i],
x + 8, y + 25 + i * 37, 0xFF181818, false);
slotFrame(graphics, 36, 20 + i * 37);
}
slotFrame(graphics, 370, 20);
slotFrame(graphics, 228, 20);
graphics.blit(LEGACY_DESK, x + 206, y + 14, 10, 130, 177, 0, 12, 166, 256, 256);
int totalRows = (filteredPages().size() + 4) / 5;
int maxScroll = Math.max(0, totalRows - 3);
scrollRows = Math.clamp(scrollRows, 0, maxScroll);
int thumbHeight = Math.max(14, 126 * 3 / Math.max(3, totalRows));
int thumbY = y + 16 + (maxScroll == 0 ? 0 : scrollRows * (126 - thumbHeight) / maxScroll);
graphics.fill(x + 207, thumbY, x + 215, thumbY + thumbHeight, 0xFFB7B7B7);
graphics.renderOutline(x + 207, thumbY, 8, thumbHeight, 0xFF424242);
slotFrame(graphics, 370, 9);
slotFrame(graphics, 228, 9);
slotFrame(graphics, 228, 57);
slotFrame(graphics, 370, 57);
graphics.fill(x + 350, y + 20, x + 364, y + 75, 0xFF303035);
graphics.fill(x + 352, y + 22, x + 362, y + 73, 0xFF15151B);
graphics.fill(x + 350, y + 9, x + 364, y + 64, 0xFF303035);
graphics.fill(x + 352, y + 11, x + 362, y + 62, 0xFF15151B);
int filled = 51 * menu.inkRemaining() / 16;
if (filled > 0) graphics.fill(x + 352, y + 73 - filled, x + 362, y + 73, 0xFF6666AA);
graphics.renderOutline(x + 350, y + 20, 14, 55, 0xFF484848);
if (filled > 0) graphics.fill(x + 352, y + 62 - filled, x + 362, y + 62, 0xFF6666AA);
graphics.renderOutline(x + 350, y + 9, 14, 55, 0xFF484848);
for (int row = 0; row < 3; row++) {
for (int column = 0; column < 9; column++) slotFrame(graphics, 224 + column * 18, 91 + row * 18);
for (int column = 0; column < 9; column++) slotFrame(graphics, 224 + column * 18, 79 + row * 18);
}
for (int column = 0; column < 9; column++) slotFrame(graphics, 224 + column * 18, 149);
for (int column = 0; column < 9; column++) slotFrame(graphics, 224 + column * 18, 137);
}
private void slotFrame(GuiGraphics graphics, int x, int y) {
@@ -122,22 +162,29 @@ public final class WritingDeskScreen extends AbstractContainerScreen<WritingDesk
}
@Override protected void renderLabels(GuiGraphics graphics, int mouseX, int mouseY) {
graphics.drawString(font, playerInventoryTitle, inventoryLabelX, inventoryLabelY, 0x404040, false);
// Legacy leaves the inventory grid unlabeled.
}
@Override public void render(GuiGraphics graphics, int mouseX, int mouseY, float partialTick) {
super.render(graphics, mouseX, mouseY, partialTick);
if (sortAlphabetically) graphics.renderOutline(leftPos + 58, topPos - 18, 20, 18, 0xFFFFD061);
if (allMode) graphics.renderOutline(leftPos + 80, topPos - 18, 28, 18, 0xFFFFD061);
renderCollection(graphics);
renderTooltip(graphics, mouseX, mouseY);
if (mouseX >= leftPos + 350 && mouseX < leftPos + 364
&& mouseY >= topPos + 20 && mouseY < topPos + 75) {
&& mouseY >= topPos + 9 && mouseY < topPos + 64) {
graphics.renderTooltip(font, Component.translatable("screen.rivencraft.writing_desk.ink",
menu.inkRemaining(), 16), mouseX, mouseY);
}
if (mouseX >= leftPos + 198 && mouseX < leftPos + 216
&& mouseY >= topPos - 18 && mouseY < topPos) {
graphics.renderTooltip(font, Component.literal(selectedCategory == null
? "All categories" : selectedCategory.toString()), mouseX, mouseY);
}
}
private List<ItemStack> pages() {
ItemStack collection = menu.getSlot(menu.activeCollection()).getItem();
private List<ItemStack> pages(int collectionIndex) {
ItemStack collection = menu.getSlot(collectionIndex).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();
@@ -146,73 +193,34 @@ public final class WritingDeskScreen extends AbstractContainerScreen<WritingDesk
}
private void renderCollection(GuiGraphics graphics) {
if (allMode) {
renderCatalog(graphics);
return;
}
List<ItemStack> pages = pages();
if (lastCollection != menu.activeCollection()) {
lastCollection = menu.activeCollection();
scrollRows = 0;
selectedPage = 0;
selectedCollection = -1;
}
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++) {
List<DisplayPage> entries = filteredPages();
for (int i = scrollRows * 5; i < entries.size() && 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;
DisplayPage entry = entries.get(i);
ItemStack page = entry.stack();
int x = leftPos + 58 + column * 29;
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 renderCatalog(GuiGraphics graphics) {
List<SymbolDisplayMetadata> filtered = filteredCatalog();
if (filtered.isEmpty()) {
graphics.drawString(font, Component.translatable("screen.rivencraft.writing_desk.no_symbols"),
leftPos + 52, topPos + 24, 0xFFC4B8A3, false);
}
for (int i = scrollRows * 5; i < filtered.size() && i < scrollRows * 5 + 15; i++) {
SymbolDisplayMetadata entry = filtered.get(i);
int x = leftPos + 48 + (i % 5) * 31;
int y = topPos + 18 + (i / 5 - scrollRows) * 41;
drawSymbolPage(graphics, entry.id(), x, y);
if (Objects.equals(entry.id(), selectedSymbol)) {
int active = selectedCollection >= 0 ? selectedCollection : menu.activeCollection();
if (entry.collection() == active && entry.index() == selectedPage && !page.isEmpty())
graphics.renderOutline(x, y, 30, 40, 0xFFFFD061);
}
}
SymbolDisplayMetadata selected = menu.catalog().stream()
.filter(entry -> Objects.equals(entry.id(), selectedSymbol)).findFirst().orElse(null);
if (selected == null) return;
graphics.pose().pushPose();
graphics.pose().translate(leftPos + 294, topPos + 12, 0);
graphics.pose().scale(1.35F, 1.35F, 1.0F);
drawSymbolPage(graphics, selected.id(), 0, 0);
graphics.pose().popPose();
String title = font.plainSubstrByWidth(
Component.translatable(selected.nameTranslationKey()).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 drawSymbolPage(GuiGraphics graphics, ResourceLocation id, int x, int y) {
graphics.blit(PAGE_ATLAS, x, y, 30, 40, 156, 0, 30, 40, 256, 256);
graphics.blit(NotebookScreen.symbolTexture(id), x + 1, y + 6,
28, 28, 16, 16, 96, 96, 128, 128);
int active = selectedCollection >= 0 ? selectedCollection : menu.activeCollection();
List<ItemStack> source = pages(active);
if (selectedPage >= source.size() || source.get(selectedPage).isEmpty()) return;
ItemStack selected = source.get(selectedPage);
drawPage(graphics, selected, leftPos + 253, topPos + 10);
String title = font.plainSubstrByWidth(selected.getHoverName().getString(), 84);
graphics.fill(leftPos + 251, topPos + 58, leftPos + 342, topPos + 73, 0xFF202020);
graphics.drawString(font, title, leftPos + 254, topPos + 61, 0xFFE0E0E0, false);
}
private void drawPage(GuiGraphics graphics, ItemStack page, int x, int y) {
@@ -228,41 +236,40 @@ public final class WritingDeskScreen extends AbstractContainerScreen<WritingDesk
@Override public boolean mouseClicked(double mouseX, double mouseY, int button) {
if (button == 0) {
int x = (int) mouseX - leftPos - 48;
if (mouseX >= leftPos + 206 && mouseX < leftPos + 217
&& mouseY >= topPos + 14 && mouseY < topPos + 144) {
draggingScrollbar = true;
setScrollFromMouse(mouseY);
return true;
}
int x = (int) mouseX - leftPos - 58;
int y = (int) mouseY - topPos - 18;
if (x >= 0 && x < 155 && y >= 0 && y < 123) {
int column = x / 31;
if (x >= 0 && x < 145 && y >= 0 && y < 123) {
int column = x / 29;
int row = y / 41;
int index = (row + scrollRows) * 5 + column;
if (allMode) {
List<SymbolDisplayMetadata> filtered = filteredCatalog();
if (x % 31 < 30 && y % 41 < 40 && index < filtered.size()) {
SymbolDisplayMetadata entry = filtered.get(index);
selectedSymbol = entry.id();
int serverIndex = menu.catalog().indexOf(entry);
if (serverIndex >= 0 && minecraft != null && minecraft.gameMode != null) {
minecraft.gameMode.handleInventoryButtonClick(menu.containerId, 100 + serverIndex);
}
}
} else {
List<ItemStack> pages = pages();
if (x % 31 < 30 && y % 41 < 40 && index < pages.size()
&& !pages.get(index).isEmpty()) {
selectedPage = index;
List<DisplayPage> entries = filteredPages();
if (y % 41 < 40 && index < entries.size()) {
DisplayPage entry = entries.get(index);
if (!entry.stack().isEmpty()) {
selectedCollection = entry.collection();
selectedPage = entry.index();
if (minecraft != null && minecraft.gameMode != null) {
minecraft.gameMode.handleInventoryButtonClick(menu.containerId, 16 + index);
int id = allMode ? 1000 + entry.collection() * NotebookContents.MAX_PAGES + entry.index()
: 16 + entry.index();
minecraft.gameMode.handleInventoryButtonClick(menu.containerId, id);
}
}
}
return true;
}
}
if (button == 0 && mouseX >= leftPos + 29 && mouseX < leftPos + 40) {
if (button == 0 && mouseX >= leftPos && mouseX < leftPos + 35) {
for (int i = 0; i < 4; i++) {
int top = topPos + 16 + i * 37;
if (mouseY >= top && mouseY < top + 32) {
if (mouseY >= top && mouseY < top + 36) {
allMode = false;
selectedSymbol = null;
selectedCollection = -1;
if (minecraft != null && minecraft.gameMode != null) {
minecraft.gameMode.handleInventoryButtonClick(menu.containerId, i);
}
@@ -274,15 +281,37 @@ public final class WritingDeskScreen extends AbstractContainerScreen<WritingDesk
}
@Override public boolean mouseScrolled(double mouseX, double mouseY, double scrollX, double scrollY) {
if (mouseX >= leftPos + 48 && mouseX < leftPos + 203
if (mouseX >= leftPos + 58 && mouseX < leftPos + 217
&& mouseY >= topPos + 18 && mouseY < topPos + 141) {
int rows = ((allMode ? filteredCatalog().size() : pages().size()) + 4) / 5;
int rows = (filteredPages().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);
}
private void setScrollFromMouse(double mouseY) {
int rows = (filteredPages().size() + 4) / 5;
int max = Math.max(0, rows - 3);
scrollRows = Math.clamp((int) Math.round((mouseY - topPos - 16) * max / 126.0), 0, max);
}
@Override public boolean mouseDragged(double mouseX, double mouseY, int button, double dragX, double dragY) {
if (button == 0 && draggingScrollbar) {
setScrollFromMouse(mouseY);
return true;
}
return super.mouseDragged(mouseX, mouseY, button, dragX, dragY);
}
@Override public boolean mouseReleased(double mouseX, double mouseY, int button) {
if (button == 0 && draggingScrollbar) {
draggingScrollbar = false;
return true;
}
return super.mouseReleased(mouseX, mouseY, button);
}
@Override public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
if (search != null && search.isFocused()) {
if (keyCode == 256) {
@@ -321,4 +321,33 @@ public final class WritingDeskGameTests {
"Open shelves must not cull terrain behind the desk");
helper.succeed();
}
@GameTest(template = "empty")
public static void allPagesSelectionUsesTheRequestedPhysicalTab(GameTestHelper helper) {
BlockPos pos = helper.absolutePos(new BlockPos(1, 1, 1));
helper.getLevel().setBlock(pos, ModBlocks.WRITING_DESK.get().defaultBlockState(), 3);
WritingDeskBlockEntity desk = (WritingDeskBlockEntity) helper.getLevel().getBlockEntity(pos);
ItemStack first = PageItem.createLinkPanelPage();
ItemStack second = PageItem.createSymbolPage(new SymbolReference(
ResourceLocation.parse("rivencraft:terrain/standard")));
desk.setItem(0, first);
ItemStack notebook = new ItemStack(ModItems.NOTEBOOK.get());
notebook.set(ModDataComponents.NOTEBOOK_CONTENTS.get(),
new NotebookContents(List.of(ItemStack.EMPTY, second)));
desk.setItem(1, notebook);
desk.setItem(WritingDeskBlockEntity.PAPER, new ItemStack(Items.PAPER));
desk.setItem(WritingDeskBlockEntity.INK, new ItemStack(ModItems.INK_VIAL.get()));
var player = helper.makeMockServerPlayerInLevel();
player.moveTo(pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5);
WritingDeskMenu menu = new WritingDeskMenu(1, player.getInventory(), desk);
helper.assertFalse(menu.clickMenuButton(player, 1000 + 2 * NotebookContents.MAX_PAGES),
"ALL view must reject empty cross-tab positions");
helper.assertTrue(menu.clickMenuButton(player, 1000 + NotebookContents.MAX_PAGES + 1),
"ALL view must accept the populated second tab page");
helper.assertTrue(ItemStack.matches(menu.getSlot(WritingDeskMenu.COPY_RESULT).getItem(), second),
"Copy preview must match the physical page selected from the other tab");
helper.assertValueEqual(desk.activeCollection(), 0,
"Selecting from ALL must not silently change the active tab");
helper.succeed();
}
}
@@ -37,6 +37,7 @@ public final class WritingDeskMenu extends AbstractContainerMenu {
private int syncedActiveCollection;
private int syncedInkRemaining;
private int selectedPage;
private int selectedCollection = -1;
private ResourceLocation selectedSymbol;
private List<SymbolDisplayMetadata> catalog = List.of();
private final ServerPlayer serverViewer;
@@ -65,20 +66,20 @@ public final class WritingDeskMenu extends AbstractContainerMenu {
@Override public void set(int value) { syncedInkRemaining = value; }
});
for (int i = 0; i < WritingDeskBlockEntity.COLLECTIONS; i++) {
addSlot(new DeskSlot(desk, i, 12, 20 + i * 37, 1));
addSlot(new DeskSlot(desk, i, 36, 20 + i * 37, 1));
}
addSlot(new DeskSlot(desk, WritingDeskBlockEntity.INK, 370, 20, 16));
addSlot(new DeskSlot(desk, WritingDeskBlockEntity.INK, 370, 9, 16));
addSlot(new DeskSlot(desk, WritingDeskBlockEntity.RETURN, 370, 57, 64));
addSlot(new DeskSlot(desk, WritingDeskBlockEntity.PAPER, 228, 20, 64));
addSlot(new DeskSlot(desk, WritingDeskBlockEntity.PAPER, 228, 9, 64));
addSlot(new DeskSlot(desk, WritingDeskBlockEntity.LEGACY_OUTPUT, -1000, -1000, 64));
addSlot(new CopySlot(result, 0, 228, 57));
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));
addSlot(new Slot(inventory, column + row * 9 + 9, 224 + column * 18, 79 + row * 18));
}
}
for (int column = 0; column < 9; column++) {
addSlot(new Slot(inventory, column, 224 + column * 18, 149));
addSlot(new Slot(inventory, column, 224 + column * 18, 137));
}
}
@@ -92,9 +93,19 @@ public final class WritingDeskMenu extends AbstractContainerMenu {
if (id >= 0 && id < WritingDeskBlockEntity.COLLECTIONS) {
blockEntity.setActiveCollection(id);
selectedPage = 0;
selectedCollection = -1;
selectedSymbol = null;
} else if (id >= 16 && id < 16 + NotebookContents.MAX_PAGES) {
selectedPage = id - 16;
selectedCollection = -1;
selectedSymbol = null;
} else if (id >= 1000 && id < 1000 + WritingDeskBlockEntity.COLLECTIONS * NotebookContents.MAX_PAGES) {
int offset = id - 1000;
int collection = offset / NotebookContents.MAX_PAGES;
int page = offset % NotebookContents.MAX_PAGES;
if (pageAt(collection, page).isEmpty()) return false;
selectedCollection = collection;
selectedPage = page;
selectedSymbol = null;
} else if (id >= 100 && id < 100 + catalog.size()) {
if (!catalog.equals(WritingDeskCatalog.available(blockEntity))) {
@@ -162,12 +173,20 @@ public final class WritingDeskMenu extends AbstractContainerMenu {
.anyMatch(entry -> entry.id().equals(selectedSymbol))
? PageItem.createSymbolPage(reference) : ItemStack.EMPTY;
}
ItemStack collection = desk.getItem(blockEntity == null ? syncedActiveCollection : blockEntity.activeCollection());
if (collection.is(ModItems.PAGE.get())) return selectedPage == 0 ? collection : ItemStack.EMPTY;
int collectionIndex = selectedCollection >= 0 ? selectedCollection
: blockEntity == null ? syncedActiveCollection : blockEntity.activeCollection();
return pageAt(collectionIndex, selectedPage);
}
private ItemStack pageAt(int collectionIndex, int pageIndex) {
if (collectionIndex < 0 || collectionIndex >= WritingDeskBlockEntity.COLLECTIONS
|| pageIndex < 0 || pageIndex >= NotebookContents.MAX_PAGES) return ItemStack.EMPTY;
ItemStack collection = desk.getItem(collectionIndex);
if (collection.is(ModItems.PAGE.get())) return pageIndex == 0 ? collection : ItemStack.EMPTY;
if (collection.is(ModItems.NOTEBOOK.get())) {
List<ItemStack> pages = collection.getOrDefault(
ModDataComponents.NOTEBOOK_CONTENTS.get(), NotebookContents.EMPTY).pages();
return selectedPage < pages.size() ? pages.get(selectedPage) : ItemStack.EMPTY;
return pageIndex < pages.size() ? pages.get(pageIndex) : ItemStack.EMPTY;
}
return ItemStack.EMPTY;
}