Public Access
This commit is contained in:
1 parent
e511e7c10b
commit
7f9cf2a4a5
19 files changed
+231
-90
No files matched your search
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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 |
|
||||
|
||||
+1
-1
@@ -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.
|
||||
|
||||
@@ -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<WritingDeskBlock> 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<? extends BaseEntityBlock> codec() { return CODEC; }
|
||||
@Override protected void createBlockStateDefinition(StateDefinition.Builder<net.minecraft.world.level.block.Block, BlockState> 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);
|
||||
}
|
||||
|
||||
@@ -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<ItemStack> 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<ClientGamePacketListener> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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<WritingDeskBlockEntity> {
|
||||
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; }
|
||||
}
|
||||
@@ -23,6 +23,8 @@ import net.minecraft.world.item.ItemStack;
|
||||
public final class WritingDeskScreen extends AbstractContainerScreen<WritingDeskMenu> {
|
||||
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<WritingDesk
|
||||
}
|
||||
|
||||
@Override public void renderBackground(GuiGraphics graphics, int mouseX, int mouseY, float partialTick) {
|
||||
// Legacy leaves the world visible around the desk instead of dimming it.
|
||||
// Keep the world visible, but still draw our GUI backing. The vanilla
|
||||
// container implementation normally calls renderBg from this method.
|
||||
renderBg(graphics, partialTick, mouseX, mouseY);
|
||||
}
|
||||
|
||||
@Override protected void renderBg(GuiGraphics graphics, float partialTick, int mouseX, int mouseY) {
|
||||
int x = leftPos;
|
||||
int y = topPos;
|
||||
graphics.fill(x + 4, y + 8, x + 216, y + 174, 0xFF383230);
|
||||
graphics.fill(x + 44, y + 14, x + 210, y + 170, 0xFF221B1A);
|
||||
graphics.fill(x + 218, y + 4, x + 396, y + 174, 0xFF555454);
|
||||
graphics.fill(x + 220, y + 6, x + 394, y + 172, 0xFFB7B7B7);
|
||||
// Use textured backing: GUI fills may depth-test behind the world with some renderers.
|
||||
graphics.blit(LEGACY_DESK, x + 218, y + 4, 178, 170, 64, 8, 16, 16, 256, 256);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
graphics.fill(x + 6, y + 16 + i * 37, x + 40, y + 48 + i * 37,
|
||||
i == menu.activeCollection() ? 0xFF7777B6 : 0xFF999999);
|
||||
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);
|
||||
}
|
||||
slotFrame(graphics, 370, 20);
|
||||
|
||||
@@ -3,6 +3,7 @@ package net.dnorberg.rivencraft.gametest;
|
||||
import java.util.List;
|
||||
import net.dnorberg.rivencraft.Rivencraft;
|
||||
import net.dnorberg.rivencraft.block.entity.WritingDeskBlockEntity;
|
||||
import net.dnorberg.rivencraft.block.WritingDeskBlock;
|
||||
import net.dnorberg.rivencraft.menu.WritingDeskMenu;
|
||||
import net.dnorberg.rivencraft.item.PageItem;
|
||||
import net.dnorberg.rivencraft.registry.ModBlocks;
|
||||
@@ -12,6 +13,7 @@ import net.dnorberg.rivencraft.writing.NotebookContents;
|
||||
import net.dnorberg.rivencraft.writing.SymbolReference;
|
||||
import net.dnorberg.rivencraft.writing.WritingDeskCatalog;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.gametest.framework.GameTest;
|
||||
import net.minecraft.gametest.framework.GameTestHelper;
|
||||
@@ -265,4 +267,58 @@ public final class WritingDeskGameTests {
|
||||
"Rejected copy must preserve ink vial");
|
||||
helper.succeed();
|
||||
}
|
||||
|
||||
@GameTest(template = "empty")
|
||||
public static void twoBlockDeskSharesOneInventoryAndBreaksTogether(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.assertTrue(helper.getLevel().getBlockState(extension).is(block),
|
||||
"Placing a desk must reserve the adjacent second block");
|
||||
helper.assertTrue(helper.getLevel().getBlockState(extension).getValue(WritingDeskBlock.EXTENSION),
|
||||
"Adjacent half must be marked as an extension");
|
||||
WritingDeskBlockEntity desk = (WritingDeskBlockEntity) helper.getLevel().getBlockEntity(pos);
|
||||
helper.assertTrue(helper.getLevel().getBlockEntity(extension) == null,
|
||||
"Extension must not duplicate the inventory");
|
||||
desk.setItem(WritingDeskBlockEntity.PAPER, new ItemStack(Items.PAPER, 7));
|
||||
helper.getLevel().destroyBlock(extension, true);
|
||||
helper.assertTrue(helper.getLevel().getBlockState(pos).isAir(),
|
||||
"Breaking the extension must remove the controller");
|
||||
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();
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ public final class ModBlocks {
|
||||
);
|
||||
public static final DeferredBlock<WritingDeskBlock> WRITING_DESK = BLOCKS.registerBlock(
|
||||
"writing_desk", WritingDeskBlock::new,
|
||||
BlockBehaviour.Properties.ofFullCopy(Blocks.CRAFTING_TABLE)
|
||||
BlockBehaviour.Properties.ofFullCopy(Blocks.CRAFTING_TABLE).noOcclusion()
|
||||
);
|
||||
|
||||
private ModBlocks() {
|
||||
|
||||
@@ -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}
|
||||
}
|
||||
}
|
||||
@@ -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"}}}
|
||||
]
|
||||
}
|
||||
@@ -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"}}}
|
||||
]
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
{
|
||||
"parent": "rivencraft:block/writing_desk"
|
||||
"parent": "minecraft:item/generated",
|
||||
"textures": {"layer0": "rivencraft:item/writing_desk"}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 5.2 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 3.0 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.1 KiB |
Reference in new issue
Block a user