From 7f9cf2a4a54ee3fb281e4e15c7abcbe302137630 Mon Sep 17 00:00:00 2001 From: Dustin Norberg Date: Thu, 24 Sep 2026 14:36:49 -0400 Subject: [PATCH] Fix Writing Desk GUI and two-block rendering --- NOTICE | 2 + README.md | 4 + docs/ASSET_PROVENANCE.md | 4 +- gradle.properties | 2 +- .../rivencraft/block/WritingDeskBlock.java | 45 ++++++++--- .../block/entity/WritingDeskBlockEntity.java | 35 ++++++++- .../rivencraft/client/ClientEvents.java | 1 + .../client/WritingDeskRenderer.java | 55 ++++++++++++++ .../client/screen/WritingDeskScreen.java | 18 +++-- .../gametest/WritingDeskGameTests.java | 56 ++++++++++++++ .../rivencraft/menu/WritingDeskMenu.java | 1 + .../rivencraft/registry/ModBlocks.java | 2 +- .../rivencraft/blockstates/writing_desk.json | 12 ++- .../rivencraft/models/block/writing_desk.json | 70 ++---------------- .../models/block/writing_desk_extension.json | 11 +++ .../rivencraft/models/item/writing_desk.json | 3 +- .../textures/block/writing_desk_inlay.png | Bin 0 -> 5369 bytes .../textures/block/writing_desk_wood.png | Bin 0 -> 3093 bytes .../textures/gui/writing_desk_legacy.png | Bin 0 -> 2118 bytes 19 files changed, 231 insertions(+), 90 deletions(-) create mode 100644 src/main/java/net/dnorberg/rivencraft/client/WritingDeskRenderer.java create mode 100644 src/main/resources/assets/rivencraft/models/block/writing_desk_extension.json create mode 100644 src/main/resources/assets/rivencraft/textures/block/writing_desk_inlay.png create mode 100644 src/main/resources/assets/rivencraft/textures/block/writing_desk_wood.png create mode 100644 src/main/resources/assets/rivencraft/textures/gui/writing_desk_legacy.png diff --git a/NOTICE b/NOTICE index 2d85d7f..ebbedae 100644 --- a/NOTICE +++ b/NOTICE @@ -14,6 +14,8 @@ The Writing Desk item texture is copied from Legacy's assets/mystcraft/textures/items/writingdesk.png under the same license. The Writing Desk block texture is copied from Legacy's assets/mystcraft/textures/entity/desk.png under the same license. +The Writing Desk GUI atlas is copied from Legacy's assets/mystcraft/gui/writingdesk.png +under the same license; desk wood and inlay textures are cropped from desk.png. The initial build layout is derived from the official NeoForge 1.21.1 ModDevGradle MDK: https://github.com/NeoForgeMDKs/MDK-1.21.1-ModDevGradle diff --git a/README.md b/README.md index b38667e..632e486 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,10 @@ The spent vial returns a glass bottle. Server owners can adjust the symbol-copy and link-panel costs in the `writing` section of `rivencraft-server.toml`. The Writing Desk can copy a selected written page from its collection tabs. The Writing Desk is now craftable from planks, a glass bottle, and a feather. +It occupies two adjacent blocks, with one shared inventory; loaded paper and +the selected page appear on its Legacy-inspired model. +Desks placed before 0.3.6.1 keep their old one-block footprint until broken +and placed again; leave an adjacent space when replacing one. Its four collection tabs, paper input, ink vial input, empty glass-bottle return, 16-unit ink meter, and inventory persist through world saves; breaking it drops stored contents. The desk screen is a diff --git a/docs/ASSET_PROVENANCE.md b/docs/ASSET_PROVENANCE.md index 5ca85d7..47fa911 100644 --- a/docs/ASSET_PROVENANCE.md +++ b/docs/ASSET_PROVENANCE.md @@ -9,7 +9,9 @@ project's GNU LGPL v3 license. Rivencraft itself uses the same license. | `assets/rivencraft/textures/item/page.png` | `assets/mystcraft/textures/items/page_background.png` | `9bc8ddc061845df0cd5ea47f4fdef773cff786ae` | Namespace/path rename only | | `assets/rivencraft/textures/gui/notebook_pages.png` | `assets/mystcraft/gui/bookui_pagel.png` | `9bc8ddc061845df0cd5ea47f4fdef773cff786ae` | Namespace/path rename only; Notebook draws the native 30×40 page at atlas coordinates `(156, 0)` | | `assets/rivencraft/textures/item/writing_desk.png` | `assets/mystcraft/textures/items/writingdesk.png` | `9bc8ddc061845df0cd5ea47f4fdef773cff786ae` | Namespace/path rename only | -| `assets/rivencraft/textures/block/writing_desk.png` | `assets/mystcraft/textures/entity/desk.png` | `9bc8ddc061845df0cd5ea47f4fdef773cff786ae` | Namespace/path rename only; single-block model adapts the desk geometry and UV regions from `ModelWritingDesk` | +| `assets/rivencraft/textures/block/writing_desk.png` | `assets/mystcraft/textures/entity/desk.png` | `9bc8ddc061845df0cd5ea47f4fdef773cff786ae` | Namespace/path rename only | +| `assets/rivencraft/textures/block/writing_desk_wood.png` and `writing_desk_inlay.png` | `assets/mystcraft/textures/entity/desk.png` | `9bc8ddc061845df0cd5ea47f4fdef773cff786ae` | Cropped opaque wood and red inlay regions for the two-block model | +| `assets/rivencraft/textures/gui/writing_desk_legacy.png` | `assets/mystcraft/gui/writingdesk.png` | `9bc8ddc061845df0cd5ea47f4fdef773cff786ae` | Namespace/path rename only; solid GUI backing sampled from Legacy atlas | | `assets/rivencraft/textures/item/linking_book_unwritten.png` | `assets/mystcraft/textures/items/unlinked.png` | `9bc8ddc061845df0cd5ea47f4fdef773cff786ae` | Namespace/path rename only | | `assets/rivencraft/textures/item/page_link_panel.png` | `page_background.png` and `PageBuilder.BasicPageSprite` | `9bc8ddc061845df0cd5ea47f4fdef773cff786ae` | Reproduces the legacy 160 px scale, black panel at `(25,30)`–`(135,75)`, and 128 px resample | | `assets/rivencraft/textures/item/page_symbol*.png` and `page_unresolved.png` | `page_background.png`, `textures/symbolcomponents.png`, `WordData`, `ModSymbols`, and `PageBuilder.PageSprite` | `9bc8ddc061845df0cd5ea47f4fdef773cff786ae` | Static 1.21.1 renditions of the legacy runtime-composed four-word symbol pages; `normal_time` uses the legacy Full Length poem | diff --git a/gradle.properties b/gradle.properties index e380cad..c79688c 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.6.0 +mod_version=0.3.6.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/block/WritingDeskBlock.java b/src/main/java/net/dnorberg/rivencraft/block/WritingDeskBlock.java index 76d74ca..79224c6 100644 --- a/src/main/java/net/dnorberg/rivencraft/block/WritingDeskBlock.java +++ b/src/main/java/net/dnorberg/rivencraft/block/WritingDeskBlock.java @@ -5,6 +5,7 @@ import net.dnorberg.rivencraft.block.entity.WritingDeskBlockEntity; import net.dnorberg.rivencraft.menu.WritingDeskMenu; import net.dnorberg.rivencraft.writing.WritingDeskCatalog; import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.Containers; @@ -19,48 +20,72 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.StateDefinition; import net.minecraft.world.level.block.state.properties.BlockStateProperties; import net.minecraft.world.level.block.state.properties.DirectionProperty; +import net.minecraft.world.level.block.state.properties.BooleanProperty; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.entity.LivingEntity; +import org.jetbrains.annotations.Nullable; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.phys.BlockHitResult; public final class WritingDeskBlock extends BaseEntityBlock { public static final MapCodec CODEC = simpleCodec(WritingDeskBlock::new); public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING; + public static final BooleanProperty EXTENSION = BooleanProperty.create("extension"); public WritingDeskBlock(Properties properties) { super(properties); - registerDefaultState(stateDefinition.any().setValue(FACING, net.minecraft.core.Direction.NORTH)); + registerDefaultState(stateDefinition.any().setValue(FACING, Direction.NORTH).setValue(EXTENSION, false)); } @Override public MapCodec codec() { return CODEC; } @Override protected void createBlockStateDefinition(StateDefinition.Builder builder) { - builder.add(FACING); + builder.add(FACING, EXTENSION); } @Override public BlockState getStateForPlacement(BlockPlaceContext context) { - return defaultBlockState().setValue(FACING, context.getHorizontalDirection().getOpposite()); + Direction facing = context.getHorizontalDirection().getOpposite(); + BlockPos extension = context.getClickedPos().relative(facing.getClockWise()); + return context.getLevel().getBlockState(extension).canBeReplaced(context) + ? defaultBlockState().setValue(FACING, facing) : null; + } + @Override public void setPlacedBy(Level level, BlockPos pos, BlockState state, + @Nullable LivingEntity placer, ItemStack stack) { + super.setPlacedBy(level, pos, state, placer, stack); + level.setBlock(pos.relative(state.getValue(FACING).getClockWise()), + state.setValue(EXTENSION, true), 3); } @Override protected RenderShape getRenderShape(BlockState state) { return RenderShape.MODEL; } @Override public BlockEntity newBlockEntity(BlockPos pos, BlockState state) { - return new WritingDeskBlockEntity(pos, state); + return state.getValue(EXTENSION) ? null : new WritingDeskBlockEntity(pos, state); } @Override protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hit) { + BlockPos controller = state.getValue(EXTENSION) + ? pos.relative(state.getValue(FACING).getCounterClockWise()) : pos; if (!level.isClientSide && player instanceof ServerPlayer serverPlayer - && level.getBlockEntity(pos) instanceof WritingDeskBlockEntity desk) { + && level.getBlockEntity(controller) instanceof WritingDeskBlockEntity desk) { serverPlayer.openMenu(new SimpleMenuProvider( (id, inventory, ignored) -> new WritingDeskMenu(id, inventory, desk), Component.translatable("container.rivencraft.writing_desk")), buffer -> { - buffer.writeBlockPos(pos); + buffer.writeBlockPos(controller); WritingDeskCatalog.write(buffer, WritingDeskCatalog.available(desk)); }); } return InteractionResult.sidedSuccess(level.isClientSide); } @Override protected void onRemove(BlockState state, Level level, BlockPos pos, BlockState replacement, boolean moving) { - if (!state.is(replacement.getBlock()) && !level.isClientSide - && level.getBlockEntity(pos) instanceof WritingDeskBlockEntity desk) { - Containers.dropContents(level, pos, desk); - level.updateNeighbourForOutputSignal(pos, this); + if (!state.is(replacement.getBlock())) { + if (!level.isClientSide && !state.getValue(EXTENSION) + && level.getBlockEntity(pos) instanceof WritingDeskBlockEntity desk) { + Containers.dropContents(level, pos, desk); + level.updateNeighbourForOutputSignal(pos, this); + } + BlockPos other = pos.relative(state.getValue(FACING).getClockWise(), + state.getValue(EXTENSION) ? -1 : 1); + BlockState otherState = level.getBlockState(other); + if (otherState.is(this) && otherState.getValue(EXTENSION) != state.getValue(EXTENSION)) { + level.setBlock(other, net.minecraft.world.level.block.Blocks.AIR.defaultBlockState(), 35); + } } super.onRemove(state, level, pos, replacement, moving); } diff --git a/src/main/java/net/dnorberg/rivencraft/block/entity/WritingDeskBlockEntity.java b/src/main/java/net/dnorberg/rivencraft/block/entity/WritingDeskBlockEntity.java index d817a95..906c7d3 100644 --- a/src/main/java/net/dnorberg/rivencraft/block/entity/WritingDeskBlockEntity.java +++ b/src/main/java/net/dnorberg/rivencraft/block/entity/WritingDeskBlockEntity.java @@ -8,6 +8,9 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.HolderLookup; import net.minecraft.core.NonNullList; import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientGamePacketListener; +import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; import net.minecraft.world.Container; import net.minecraft.world.ContainerHelper; import net.minecraft.world.entity.player.Player; @@ -28,6 +31,7 @@ public final class WritingDeskBlockEntity extends BlockEntity implements Contain private NonNullList items = NonNullList.withSize(SIZE, ItemStack.EMPTY); private int activeCollection; private int inkRemaining; + private ItemStack displayPage = ItemStack.EMPTY; public WritingDeskBlockEntity(BlockPos pos, BlockState state) { super(ModBlockEntities.WRITING_DESK.get(), pos, state); @@ -35,6 +39,14 @@ public final class WritingDeskBlockEntity extends BlockEntity implements Contain public int activeCollection() { return activeCollection; } public int inkRemaining() { return inkRemaining; } + public ItemStack displayPage() { return displayPage; } + public void setDisplayPage(ItemStack page) { + ItemStack next = page.isEmpty() ? ItemStack.EMPTY : page.copyWithCount(1); + if (!ItemStack.matches(displayPage, next)) { + displayPage = next; + setChanged(); + } + } public void setActiveCollection(int index) { if (index >= 0 && index < COLLECTIONS && activeCollection != index) { activeCollection = index; @@ -47,13 +59,17 @@ public final class WritingDeskBlockEntity extends BlockEntity implements Contain @Override public ItemStack getItem(int slot) { return items.get(slot); } @Override public ItemStack removeItem(int slot, int amount) { ItemStack removed = ContainerHelper.removeItem(items, slot, amount); - if (!removed.isEmpty()) setChanged(); + if (!removed.isEmpty()) { + if (slot < COLLECTIONS) displayPage = ItemStack.EMPTY; + setChanged(); + } return removed; } @Override public ItemStack removeItemNoUpdate(int slot) { return ContainerHelper.takeItem(items, slot); } @Override public void setItem(int slot, ItemStack stack) { items.set(slot, stack); if (stack.getCount() > getMaxStackSize()) stack.setCount(getMaxStackSize()); + if (slot < COLLECTIONS) displayPage = ItemStack.EMPTY; setChanged(); } @Override public boolean stillValid(Player player) { @@ -107,6 +123,7 @@ public final class WritingDeskBlockEntity extends BlockEntity implements Contain items.clear(); items = NonNullList.withSize(SIZE, ItemStack.EMPTY); inkRemaining = 0; + displayPage = ItemStack.EMPTY; setChanged(); } @Override protected void loadAdditional(CompoundTag tag, HolderLookup.Provider registries) { @@ -115,11 +132,27 @@ public final class WritingDeskBlockEntity extends BlockEntity implements Contain ContainerHelper.loadAllItems(tag, items, registries); activeCollection = Math.clamp(tag.getInt("ActiveCollection"), 0, COLLECTIONS - 1); inkRemaining = Math.clamp(tag.getInt("InkRemaining"), 0, InkVialItem.CAPACITY); + displayPage = tag.contains("DisplayPage", CompoundTag.TAG_COMPOUND) + ? ItemStack.parse(registries, tag.getCompound("DisplayPage")).orElse(ItemStack.EMPTY) + : ItemStack.EMPTY; } @Override protected void saveAdditional(CompoundTag tag, HolderLookup.Provider registries) { super.saveAdditional(tag, registries); ContainerHelper.saveAllItems(tag, items, registries); tag.putInt("ActiveCollection", activeCollection); tag.putInt("InkRemaining", inkRemaining); + if (!displayPage.isEmpty()) tag.put("DisplayPage", displayPage.save(registries)); + } + @Override public Packet getUpdatePacket() { + return ClientboundBlockEntityDataPacket.create(this); + } + @Override public CompoundTag getUpdateTag(HolderLookup.Provider registries) { + return saveWithoutMetadata(registries); + } + @Override public void setChanged() { + super.setChanged(); + if (level != null && !level.isClientSide) { + level.sendBlockUpdated(worldPosition, getBlockState(), getBlockState(), 2); + } } } diff --git a/src/main/java/net/dnorberg/rivencraft/client/ClientEvents.java b/src/main/java/net/dnorberg/rivencraft/client/ClientEvents.java index 32f4b92..2d580d5 100644 --- a/src/main/java/net/dnorberg/rivencraft/client/ClientEvents.java +++ b/src/main/java/net/dnorberg/rivencraft/client/ClientEvents.java @@ -25,6 +25,7 @@ public final class ClientEvents { @SubscribeEvent public static void registerRenderers(EntityRenderersEvent.RegisterRenderers event) { event.registerBlockEntityRenderer(ModBlockEntities.BOOK_STAND.get(), BookStandRenderer::new); + event.registerBlockEntityRenderer(ModBlockEntities.WRITING_DESK.get(), WritingDeskRenderer::new); } @SubscribeEvent diff --git a/src/main/java/net/dnorberg/rivencraft/client/WritingDeskRenderer.java b/src/main/java/net/dnorberg/rivencraft/client/WritingDeskRenderer.java new file mode 100644 index 0000000..0eb0761 --- /dev/null +++ b/src/main/java/net/dnorberg/rivencraft/client/WritingDeskRenderer.java @@ -0,0 +1,55 @@ +package net.dnorberg.rivencraft.client; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Axis; +import net.dnorberg.rivencraft.block.WritingDeskBlock; +import net.dnorberg.rivencraft.block.entity.WritingDeskBlockEntity; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.world.item.ItemDisplayContext; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; + +/** Visible selected page and loaded paper, as on the Legacy desk. */ +public final class WritingDeskRenderer implements BlockEntityRenderer { + public WritingDeskRenderer(BlockEntityRendererProvider.Context context) {} + + @Override public void render(WritingDeskBlockEntity desk, float partialTick, PoseStack pose, + MultiBufferSource buffers, int light, int overlay) { + int paper = desk.getItem(WritingDeskBlockEntity.PAPER).getCount(); + ItemStack page = desk.displayPage(); + if (paper == 0 && page.isEmpty()) return; + pose.pushPose(); + pose.translate(0.5, 0, 0.5); + pose.mulPose(Axis.YP.rotationDegrees( + 180.0F - desk.getBlockState().getValue(WritingDeskBlock.FACING).toYRot())); + if (paper > 0) { + ItemStack sheet = new ItemStack(Items.PAPER); + int layers = Math.min(4, 1 + paper / 16); + for (int i = 0; i < layers; i++) { + drawFlat(desk, sheet, pose, buffers, light, overlay, 1.22, 0.27 + i * 0.008, -0.14, 0.55F); + } + } + if (!page.isEmpty()) { + drawFlat(desk, page, pose, buffers, light, overlay, 1.0, 0.572, 0.0, 0.8F); + } + pose.popPose(); + } + + private static void drawFlat(WritingDeskBlockEntity desk, ItemStack stack, PoseStack pose, + MultiBufferSource buffers, int light, int overlay, + double x, double y, double z, float scale) { + pose.pushPose(); + pose.translate(x, y, z); + pose.mulPose(Axis.XP.rotationDegrees(90)); + pose.scale(scale, scale, scale); + Minecraft.getInstance().getItemRenderer().renderStatic(stack, ItemDisplayContext.FIXED, + light, overlay, pose, buffers, desk.getLevel(), 0); + pose.popPose(); + } + + @Override public boolean shouldRenderOffScreen(WritingDeskBlockEntity blockEntity) { return true; } + @Override public int getViewDistance() { return 64; } +} 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 314744f..c0fd52c 100644 --- a/src/main/java/net/dnorberg/rivencraft/client/screen/WritingDeskScreen.java +++ b/src/main/java/net/dnorberg/rivencraft/client/screen/WritingDeskScreen.java @@ -23,6 +23,8 @@ import net.minecraft.world.item.ItemStack; public final class WritingDeskScreen extends AbstractContainerScreen { private static final ResourceLocation PAGE_ATLAS = ResourceLocation.fromNamespaceAndPath( Rivencraft.MOD_ID, "textures/gui/notebook_pages.png"); + private static final ResourceLocation LEGACY_DESK = ResourceLocation.fromNamespaceAndPath( + Rivencraft.MOD_ID, "textures/gui/writing_desk_legacy.png"); private int lastCollection = -1; private int selectedPage; private int scrollRows; @@ -80,19 +82,21 @@ public final class WritingDeskScreen extends AbstractContainerScreen e.getItem().is(block.asItem())) + .mapToInt(e -> e.getItem().getCount()).sum(); + int paper = drops.stream().filter(e -> e.getItem().is(Items.PAPER)) + .mapToInt(e -> e.getItem().getCount()).sum(); + helper.assertValueEqual(desks, 1, "Breaking either half must drop one desk"); + helper.assertValueEqual(paper, 7, "Breaking either half must drop stored paper once"); + helper.succeed(); + } + + @GameTest(template = "empty") + public static void breakingControllerRemovesExtensionWithoutDuplicateDesk(GameTestHelper helper) { + BlockPos pos = helper.absolutePos(new BlockPos(1, 1, 1)); + var block = ModBlocks.WRITING_DESK.get(); + var state = block.defaultBlockState().setValue(WritingDeskBlock.FACING, Direction.NORTH); + helper.getLevel().setBlock(pos, state, 3); + block.setPlacedBy(helper.getLevel(), pos, state, null, new ItemStack(block)); + BlockPos extension = pos.relative(Direction.EAST); + helper.getLevel().destroyBlock(pos, true); + helper.assertTrue(helper.getLevel().getBlockState(extension).isAir(), + "Breaking the controller must remove the extension"); + var drops = helper.getLevel().getEntitiesOfClass(ItemEntity.class, new AABB(pos).inflate(3)); + int desks = drops.stream().filter(e -> e.getItem().is(block.asItem())) + .mapToInt(e -> e.getItem().getCount()).sum(); + helper.assertValueEqual(desks, 1, "Controller break must drop exactly one desk"); + helper.succeed(); + } + + @GameTest(template = "empty") + public static void openDeskDoesNotOccludeTerrain(GameTestHelper helper) { + helper.assertFalse(ModBlocks.WRITING_DESK.get().defaultBlockState().canOcclude(), + "Open shelves must not cull terrain behind the desk"); + helper.succeed(); + } } diff --git a/src/main/java/net/dnorberg/rivencraft/menu/WritingDeskMenu.java b/src/main/java/net/dnorberg/rivencraft/menu/WritingDeskMenu.java index 172b6f4..34a9942 100644 --- a/src/main/java/net/dnorberg/rivencraft/menu/WritingDeskMenu.java +++ b/src/main/java/net/dnorberg/rivencraft/menu/WritingDeskMenu.java @@ -181,6 +181,7 @@ public final class WritingDeskMenu extends AbstractContainerMenu { private void refreshOutput() { if (clientSide) return; + if (blockEntity != null) blockEntity.setDisplayPage(selectedSource()); ItemStack preview = canCopy() ? selectedSource().copyWithCount(1) : ItemStack.EMPTY; if (!ItemStack.matches(result.getItem(0), preview)) result.setItem(0, preview); } diff --git a/src/main/java/net/dnorberg/rivencraft/registry/ModBlocks.java b/src/main/java/net/dnorberg/rivencraft/registry/ModBlocks.java index 248f520..5ecd3f5 100644 --- a/src/main/java/net/dnorberg/rivencraft/registry/ModBlocks.java +++ b/src/main/java/net/dnorberg/rivencraft/registry/ModBlocks.java @@ -19,7 +19,7 @@ public final class ModBlocks { ); public static final DeferredBlock WRITING_DESK = BLOCKS.registerBlock( "writing_desk", WritingDeskBlock::new, - BlockBehaviour.Properties.ofFullCopy(Blocks.CRAFTING_TABLE) + BlockBehaviour.Properties.ofFullCopy(Blocks.CRAFTING_TABLE).noOcclusion() ); private ModBlocks() { diff --git a/src/main/resources/assets/rivencraft/blockstates/writing_desk.json b/src/main/resources/assets/rivencraft/blockstates/writing_desk.json index b860a13..b8e2086 100644 --- a/src/main/resources/assets/rivencraft/blockstates/writing_desk.json +++ b/src/main/resources/assets/rivencraft/blockstates/writing_desk.json @@ -1,8 +1,12 @@ { "variants": { - "facing=north": { "model": "rivencraft:block/writing_desk" }, - "facing=east": { "model": "rivencraft:block/writing_desk", "y": 90 }, - "facing=south": { "model": "rivencraft:block/writing_desk", "y": 180 }, - "facing=west": { "model": "rivencraft:block/writing_desk", "y": 270 } + "facing=north,extension=false": {"model":"rivencraft:block/writing_desk"}, + "facing=east,extension=false": {"model":"rivencraft:block/writing_desk","y":90}, + "facing=south,extension=false": {"model":"rivencraft:block/writing_desk","y":180}, + "facing=west,extension=false": {"model":"rivencraft:block/writing_desk","y":270}, + "facing=north,extension=true": {"model":"rivencraft:block/writing_desk_extension"}, + "facing=east,extension=true": {"model":"rivencraft:block/writing_desk_extension","y":90}, + "facing=south,extension=true": {"model":"rivencraft:block/writing_desk_extension","y":180}, + "facing=west,extension=true": {"model":"rivencraft:block/writing_desk_extension","y":270} } } diff --git a/src/main/resources/assets/rivencraft/models/block/writing_desk.json b/src/main/resources/assets/rivencraft/models/block/writing_desk.json index 84ad793..f095c27 100644 --- a/src/main/resources/assets/rivencraft/models/block/writing_desk.json +++ b/src/main/resources/assets/rivencraft/models/block/writing_desk.json @@ -1,69 +1,11 @@ { "parent": "minecraft:block/block", - "ambientocclusion": false, - "textures": { - "particle": "rivencraft:block/writing_desk", - "desk": "rivencraft:block/writing_desk" - }, + "textures": {"wood":"rivencraft:block/writing_desk_wood","inlay":"rivencraft:block/writing_desk_inlay","particle":"rivencraft:block/writing_desk_wood"}, "elements": [ - { - "from": [0, 8, 0], "to": [16, 9, 16], - "faces": { - "up": {"uv": [1, 0, 3, 2], "texture": "#desk"}, - "down": {"uv": [1, 2, 3, 4], "texture": "#desk"}, - "north": {"uv": [1, 0, 3, 0.125], "texture": "#desk"}, - "south": {"uv": [1, 0, 3, 0.125], "texture": "#desk"}, - "east": {"uv": [1, 0, 3, 0.125], "texture": "#desk"}, - "west": {"uv": [1, 0, 3, 0.125], "texture": "#desk"} - } - }, - { - "from": [0, 0, 1], "to": [2, 8, 15], - "faces": { - "north": {"uv": [5.625, 0.125, 5.875, 2], "texture": "#desk"}, - "south": {"uv": [5.625, 0.125, 5.875, 2], "texture": "#desk"}, - "east": {"uv": [5.625, 0.125, 5.875, 2], "texture": "#desk"}, - "west": {"uv": [5.625, 0.125, 5.875, 2], "texture": "#desk"} - } - }, - { - "from": [14, 0, 1], "to": [16, 8, 15], - "faces": { - "north": {"uv": [5.625, 0.125, 5.875, 2], "texture": "#desk"}, - "south": {"uv": [5.625, 0.125, 5.875, 2], "texture": "#desk"}, - "east": {"uv": [5.625, 0.125, 5.875, 2], "texture": "#desk"}, - "west": {"uv": [5.625, 0.125, 5.875, 2], "texture": "#desk"} - } - }, - { - "from": [1, 3, 2], "to": [15, 4, 14], - "faces": { - "up": {"uv": [0, 4.25, 3.75, 6.125], "texture": "#desk"}, - "down": {"uv": [0, 4.25, 3.75, 6.125], "texture": "#desk"}, - "north": {"uv": [0, 4.25, 3.75, 4.5], "texture": "#desk"}, - "south": {"uv": [0, 4.25, 3.75, 4.5], "texture": "#desk"}, - "east": {"uv": [0, 4.25, 3.75, 4.5], "texture": "#desk"}, - "west": {"uv": [0, 4.25, 3.75, 4.5], "texture": "#desk"} - } - }, - { - "from": [1, 9, 14], "to": [15, 15, 16], - "faces": { - "north": {"uv": [8, 0, 11.75, 2], "texture": "#desk"}, - "south": {"uv": [8, 0, 11.75, 2], "texture": "#desk"}, - "east": {"uv": [8, 0, 8.25, 2], "texture": "#desk"}, - "west": {"uv": [8, 0, 8.25, 2], "texture": "#desk"}, - "up": {"uv": [8, 0, 11.75, 0.25], "texture": "#desk"} - } - }, - { - "from": [1, 12, 9], "to": [15, 13, 15], - "faces": { - "up": {"uv": [8, 3.625, 11.75, 4.375], "texture": "#desk"}, - "down": {"uv": [8, 3.625, 11.75, 4.375], "texture": "#desk"}, - "north": {"uv": [8, 3.625, 11.75, 3.75], "texture": "#desk"}, - "south": {"uv": [8, 3.625, 11.75, 3.75], "texture": "#desk"} - } - } + {"from":[0,0,1],"to":[16,1,15],"faces":{"up":{"texture":"#wood"},"down":{"texture":"#wood"},"north":{"texture":"#wood"},"south":{"texture":"#wood"},"east":{"texture":"#wood"},"west":{"texture":"#wood"}}}, + {"from":[0,8,0],"to":[16,9,16],"faces":{"up":{"texture":"#inlay"},"down":{"texture":"#wood"},"north":{"texture":"#wood"},"south":{"texture":"#wood"},"east":{"texture":"#wood"},"west":{"texture":"#wood"}}}, + {"from":[0,0,1],"to":[1,8,15],"faces":{"up":{"texture":"#wood"},"down":{"texture":"#wood"},"north":{"texture":"#wood"},"south":{"texture":"#wood"},"east":{"texture":"#wood"},"west":{"texture":"#wood"}}}, + {"from":[1,3,1],"to":[16,4,15],"faces":{"up":{"texture":"#wood"},"down":{"texture":"#wood"},"north":{"texture":"#wood"},"south":{"texture":"#wood"},"east":{"texture":"#wood"},"west":{"texture":"#wood"}}}, + {"from":[0,9,15],"to":[16,15,16],"faces":{"up":{"texture":"#wood"},"down":{"texture":"#wood"},"north":{"texture":"#wood"},"south":{"texture":"#wood"},"east":{"texture":"#wood"},"west":{"texture":"#wood"}}} ] } diff --git a/src/main/resources/assets/rivencraft/models/block/writing_desk_extension.json b/src/main/resources/assets/rivencraft/models/block/writing_desk_extension.json new file mode 100644 index 0000000..12685bf --- /dev/null +++ b/src/main/resources/assets/rivencraft/models/block/writing_desk_extension.json @@ -0,0 +1,11 @@ +{ + "parent": "minecraft:block/block", + "textures": {"wood":"rivencraft:block/writing_desk_wood","inlay":"rivencraft:block/writing_desk_inlay","particle":"rivencraft:block/writing_desk_wood"}, + "elements": [ + {"from":[0,0,1],"to":[16,1,15],"faces":{"up":{"texture":"#wood"},"down":{"texture":"#wood"},"north":{"texture":"#wood"},"south":{"texture":"#wood"},"east":{"texture":"#wood"},"west":{"texture":"#wood"}}}, + {"from":[0,8,0],"to":[16,9,16],"faces":{"up":{"texture":"#wood"},"down":{"texture":"#wood"},"north":{"texture":"#wood"},"south":{"texture":"#wood"},"east":{"texture":"#wood"},"west":{"texture":"#wood"}}}, + {"from":[15,0,1],"to":[16,8,15],"faces":{"up":{"texture":"#wood"},"down":{"texture":"#wood"},"north":{"texture":"#wood"},"south":{"texture":"#wood"},"east":{"texture":"#wood"},"west":{"texture":"#wood"}}}, + {"from":[0,3,1],"to":[15,4,15],"faces":{"up":{"texture":"#wood"},"down":{"texture":"#wood"},"north":{"texture":"#wood"},"south":{"texture":"#wood"},"east":{"texture":"#wood"},"west":{"texture":"#wood"}}}, + {"from":[0,9,15],"to":[16,15,16],"faces":{"up":{"texture":"#wood"},"down":{"texture":"#wood"},"north":{"texture":"#wood"},"south":{"texture":"#wood"},"east":{"texture":"#wood"},"west":{"texture":"#wood"}}} + ] +} diff --git a/src/main/resources/assets/rivencraft/models/item/writing_desk.json b/src/main/resources/assets/rivencraft/models/item/writing_desk.json index 7d99ef8..9dc2eda 100644 --- a/src/main/resources/assets/rivencraft/models/item/writing_desk.json +++ b/src/main/resources/assets/rivencraft/models/item/writing_desk.json @@ -1,3 +1,4 @@ { - "parent": "rivencraft:block/writing_desk" + "parent": "minecraft:item/generated", + "textures": {"layer0": "rivencraft:item/writing_desk"} } diff --git a/src/main/resources/assets/rivencraft/textures/block/writing_desk_inlay.png b/src/main/resources/assets/rivencraft/textures/block/writing_desk_inlay.png new file mode 100644 index 0000000000000000000000000000000000000000..205f1a82234bb4095ca9ae89f79723ecf90efb1b GIT binary patch literal 5369 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/rivencraft/textures/gui/writing_desk_legacy.png b/src/main/resources/assets/rivencraft/textures/gui/writing_desk_legacy.png new file mode 100644 index 0000000000000000000000000000000000000000..32cea7ad01d90f78f9928e785229cf205935e749 GIT binary patch literal 2118 zcma)+dpy+X9>>4GpP6aS2(ulR+0jK&xlAWQs1CC(WloaZZ9_w{2)JRkk0H`sX9o+#C#Sj4^LGfZ9xw&6Ci*ny)5B%n(!-@$ZX!|xtFjqcj>>NHQ zl)ptd`$Yk$-&b~|>ffQG3USd<#tx@NJqT5kV01V}gQ-v&8IE6ga=J%*c7#he=@Q)D zJH%wFS#*ADa-kwc9jzL;Hh^p8KEB}7D)bVK^S8yg4{c|PqYs_^vBic?7=F4s)F*Z} zBj_f1zHIze=&C*9=RfY3u>0kb@AC5UdS_}}8Vl!gB<#%ibu`D++o~%cN)i`3Wmb*P z?uO~g(!gRe$I&5*rg>jQ%Z>8Pgg0=B=hUYxX z%o+Hx7e7oSGT&6IdwC@l9PCY8@p+b$nSLfJUH%?rf zZM7xGIXUI)PrA01z;=8xWoSOVq~p!L{$q77YH;sNCZAS!hf$bbR-7MknB_Fp?JmZS7D2^VX2YJm&A-NG2M zA7i@P^A(ZsP{#I;`EVd8mGN<;W`$ziS$fYHoQ=f8TjW3cN!T}wLs~6S1TOv4*0yfC zj`rA1GszNsPgT%Vm$Q~#3NHf%gGtvIMK;)p|NNuCx0HrlFnfF*Msj@ zM9S>6FD^K%9q|NuGpR2k@qwj#cnFKhv@_2}mxjAf-OS3NQdUUL8~qmv9Wbx?)I+!+ z&BR*6bLBnZwO^pv>g0wc4y@V$Rq!p&omqMdF{KuOF=$&iJzW^zh4f|a`3=DSw=ey% z3R-2jJFA;%_je8Kn&Hw$Q3unmK#9lp8ecZ+0j6VvU4=W$w)ALz_}W*c5Baj@d6!f(M*hjky=t(A7bcz60vaPd zZTtW8TE@S7gE^_7(bd0+@rbPv3gs;Hf5!aYE7N_9JXP+pQPcbI?9fK5{5KVLpKsmV zExfmEExM0{&Dn|8<#MiH*)4q+@mVO)(@8+_Ze}l0nDQ$3MK+3A{+aWN4Qh*Jn;3R+ zIx8kw0j=WVnUe=Iy;eE&+Av7k6M4$LIV52(`A+(Dh3{Z?Qov3c%&msCrWUl

;G%RzCzDaoQn;suSuuWxUk?Q9+*$&FhpIwg+nUeI2UTcq06Z8`s`jV3fbP0Q0cfoAyN;uF78S3*Z?BWb$ zC1Fyb_r})U_^~x`W=qtv6 zo)LztuBkD14m=$SC;YvT{hYJuR+qs1H0BywM3h`)6jL!V* ubmoLpw<;8>=;3q|SZxUTR4x34Mw7&U=V?D`<7?@l{F>q9>d3ceo%#huoNsIZ literal 0 HcmV?d00001