Display book names above book stands
Build / build (push) Canceled after 0s

This commit is contained in:
dnorberg committed 2026-09-21 07:53:43 -04:00
1 parent d7fb1855a8
commit ec82296624
4 files changed
+60 -4

No files matched your search

+5 -1
View File
@@ -52,7 +52,8 @@ the symbol grammar is introduced.
explicit link activation. explicit link activation.
- [x] Ponder dependency and isolated destination-preview level boundary. - [x] Ponder dependency and isolated destination-preview level boundary.
- [ ] Server-provided destination snapshots rendered as rotating Ponder scenes. - [ ] Server-provided destination snapshots rendered as rotating Ponder scenes.
- [ ] Book Stand floating names and opening the stored book screen. - [x] Book Stand floating names synchronized from the stored book stack.
- [ ] Open the stored book screen from a Book Stand.
- [ ] Automated in-game tests for binding, persistence, and travel. - [ ] Automated in-game tests for binding, persistence, and travel.
The temporary shapeless Linking Book recipe makes the linking subsystem easy The temporary shapeless Linking Book recipe makes the linking subsystem easy
@@ -96,6 +97,9 @@ the world remains sharp behind it.
Version 0.1.8 renders all Linking Book destination details in the same dark ink Version 0.1.8 renders all Linking Book destination details in the same dark ink
color as the book name for consistent contrast against the parchment. color as the book name for consistent contrast against the parchment.
Version 0.1.9 synchronizes the Book Stand's stored stack to clients and renders
its display name as a camera-facing label above the book.
The preview code is separated behind a renderer interface and uses an isolated The preview code is separated behind a renderer interface and uses an isolated
Ponder level. The first iteration supplies the animated loading boundary; the Ponder level. The first iteration supplies the animated loading boundary; the
next iteration will add server-authoritative snapshot transport and populate next iteration will add server-authoritative snapshot transport and populate
+1 -1
View File
@@ -33,7 +33,7 @@ mod_name=Rivencraft
# The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. # 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 mod_license=LGPL-3.0-or-later
# The mod version. See https://semver.org/ # The mod version. See https://semver.org/
mod_version=0.1.8 mod_version=0.1.9
# The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # 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. # This should match the base package used for the mod sources.
# See https://maven.apache.org/guides/mini/guide-naming-conventions.html # See https://maven.apache.org/guides/mini/guide-naming-conventions.html
@@ -4,6 +4,9 @@ import net.dnorberg.rivencraft.registry.ModBlockEntities;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.HolderLookup; import net.minecraft.core.HolderLookup;
import net.minecraft.nbt.CompoundTag; 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.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
@@ -22,16 +25,33 @@ public final class BookStandBlockEntity extends BlockEntity {
public void setBook(ItemStack book) { public void setBook(ItemStack book) {
this.book = book; this.book = book;
setChanged(); setChangedAndSync();
} }
public ItemStack takeBook() { public ItemStack takeBook() {
ItemStack result = book; ItemStack result = book;
book = ItemStack.EMPTY; book = ItemStack.EMPTY;
setChanged(); setChangedAndSync();
return result; return result;
} }
@Override
public Packet<ClientGamePacketListener> getUpdatePacket() {
return ClientboundBlockEntityDataPacket.create(this);
}
@Override
public CompoundTag getUpdateTag(HolderLookup.Provider registries) {
return saveWithoutMetadata(registries);
}
private void setChangedAndSync() {
setChanged();
if (level != null && !level.isClientSide) {
level.sendBlockUpdated(worldPosition, getBlockState(), getBlockState(), 2);
}
}
@Override @Override
protected void loadAdditional(CompoundTag tag, HolderLookup.Provider registries) { protected void loadAdditional(CompoundTag tag, HolderLookup.Provider registries) {
super.loadAdditional(tag, registries); super.loadAdditional(tag, registries);
@@ -7,18 +7,27 @@ import net.dnorberg.rivencraft.block.BookStandBlock;
import net.dnorberg.rivencraft.block.entity.BookStandBlockEntity; import net.dnorberg.rivencraft.block.entity.BookStandBlockEntity;
import net.minecraft.client.model.BookModel; import net.minecraft.client.model.BookModel;
import net.minecraft.client.model.geom.ModelLayers; import net.minecraft.client.model.geom.ModelLayers;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Font;
import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
import net.minecraft.client.renderer.blockentity.EnchantTableRenderer; import net.minecraft.client.renderer.blockentity.EnchantTableRenderer;
import net.minecraft.client.renderer.entity.EntityRenderDispatcher;
import net.minecraft.network.chat.Component;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import org.joml.Matrix4f;
public final class BookStandRenderer implements BlockEntityRenderer<BookStandBlockEntity> { public final class BookStandRenderer implements BlockEntityRenderer<BookStandBlockEntity> {
private final BookModel bookModel; private final BookModel bookModel;
private final Font font;
private final EntityRenderDispatcher entityRenderer;
public BookStandRenderer(BlockEntityRendererProvider.Context context) { public BookStandRenderer(BlockEntityRendererProvider.Context context) {
bookModel = new BookModel(context.bakeLayer(ModelLayers.BOOK)); bookModel = new BookModel(context.bakeLayer(ModelLayers.BOOK));
font = context.getFont();
entityRenderer = context.getEntityRenderer();
} }
@Override @Override
@@ -45,5 +54,28 @@ public final class BookStandRenderer implements BlockEntityRenderer<BookStandBlo
VertexConsumer consumer = EnchantTableRenderer.BOOK_LOCATION.buffer(bufferSource, RenderType::entitySolid); VertexConsumer consumer = EnchantTableRenderer.BOOK_LOCATION.buffer(bufferSource, RenderType::entitySolid);
bookModel.render(poseStack, consumer, packedLight, packedOverlay, -1); bookModel.render(poseStack, consumer, packedLight, packedOverlay, -1);
poseStack.popPose(); poseStack.popPose();
if (!blockEntity.getBook().isEmpty()) {
renderName(blockEntity.getBook().getHoverName(), poseStack, bufferSource, packedLight);
}
}
private void renderName(
Component name,
PoseStack poseStack,
MultiBufferSource bufferSource,
int packedLight
) {
poseStack.pushPose();
poseStack.translate(0.5F, 1.6F, 0.5F);
poseStack.mulPose(entityRenderer.cameraOrientation());
poseStack.scale(-0.025F, -0.025F, 0.025F);
Matrix4f matrix = poseStack.last().pose();
float x = -font.width(name) / 2.0F;
int background = (int)(Minecraft.getInstance().options.getBackgroundOpacity(0.25F) * 255.0F) << 24;
font.drawInBatch(name, x, 0.0F, 0xFFFFFFFF, false, matrix, bufferSource,
Font.DisplayMode.NORMAL, background, packedLight);
poseStack.popPose();
} }
} }