Add shelf inspection

This commit is contained in:
Ismael Magro
2025-10-22 19:49:27 +02:00
parent 61decc1efc
commit fce406a858
18 changed files with 256 additions and 15 deletions
@@ -13,4 +13,5 @@ public class Constants {
public static final ResourceLocation BOOK_SHELF_INVENTORY_PACKET_ID = ResourceLocation.fromNamespaceAndPath(MOD_ID,"book_shelf_inventory");
public static final ResourceLocation MOD_CHECK_PACKET_ID = ResourceLocation.fromNamespaceAndPath(MOD_ID,"mod_check");
public static final ResourceLocation LECTERN_INVENTORY_REQUEST_PACKET_ID = ResourceLocation.fromNamespaceAndPath(MOD_ID, "lectern_inventory_request");
public static final ResourceLocation SHELF_INVENTORY_REQUEST_PACKET_ID = ResourceLocation.fromNamespaceAndPath(MOD_ID,"shelf_inventory_request");
}
@@ -14,6 +14,8 @@ import java.util.Map;
public class Config {
public boolean lecternToggle = true;
public boolean shelfToggle = true;
public boolean shelfDisplayNormal = true;
public int scale = 10;
public boolean useRoman = false;
@@ -26,6 +28,12 @@ public class Config {
if(configMap.containsKey("lectern-toggle")){
lecternToggle = (boolean) configMap.get("lectern-toggle");
}
if(configMap.containsKey("shelf-toggle")){
shelfToggle = (boolean) configMap.get("shelf-toggle");
}
if(configMap.containsKey("shelf-display-normal")){
shelfDisplayNormal = (boolean) configMap.get("shelf-display-normal");
}
if(configMap.containsKey("scale")){
scale = (int) configMap.get("scale");
}
@@ -55,6 +63,8 @@ public class Config {
try{
Map<String, Object> configMap = yaml.load(new FileReader(configPath.toFile()));
configMap.put("lectern-toggle",lecternToggle);
configMap.put("shelf-toggle",shelfToggle);
configMap.put("shelf-display-normal",shelfDisplayNormal);
configMap.put("scale",scale);
configMap.put("roman", useRoman);
FileWriter writer = new FileWriter(configPath.toString());
@@ -1,10 +1,12 @@
package com.lukasabbe.bookshelfinspector.data;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.block.state.BlockState;
public class BookShelfData {
public boolean isCurrentBookDataToggled = false;
public BlockPos latestPos = null;
public BlockState latestBlockState = null;
public boolean requestSent = false;
public int currentSlotInt = -1;
}
@@ -8,4 +8,5 @@ import net.minecraft.world.level.block.Block;
public class Tags {
public static final TagKey<Block> CHISELED_BOOKSHELVES = TagKey.create(Registries.BLOCK, ResourceLocation.fromNamespaceAndPath("c", "chiseled_bookshelves"));
public static final TagKey<Block> LECTERNS = TagKey.create(Registries.BLOCK, ResourceLocation.fromNamespaceAndPath("c", "lectern"));
public static final TagKey<Block> SHELVES = TagKey.create(Registries.BLOCK, ResourceLocation.fromNamespaceAndPath("c", "shelves"));
}
@@ -4,18 +4,21 @@ import com.lukasabbe.bookshelfinspector.network.client.BookShelfInventoryHandler
import com.lukasabbe.bookshelfinspector.network.client.ModServerPayloadHandler;
import com.lukasabbe.bookshelfinspector.network.server.BookShelfInventoryRequestServerPayloadHandler;
import com.lukasabbe.bookshelfinspector.network.server.LecternInventoryRequestServerPayloadHandler;
import com.lukasabbe.bookshelfinspector.network.server.ShelfInventoryRequestServerPayloadHandler;
public class Handlers {
public BookShelfInventoryHandlerServer bookShelfInventoryHandlerServer;
public ModServerPayloadHandler modServerPayloadHandler;
public BookShelfInventoryRequestServerPayloadHandler bookShelfInventoryRequestServerPayloadHandler;
public LecternInventoryRequestServerPayloadHandler lecternInventoryRequestServerPayloadHandler;
public ShelfInventoryRequestServerPayloadHandler shelfInventoryRequestServerPayloadHandler;
public Handlers(){
bookShelfInventoryHandlerServer = new BookShelfInventoryHandlerServer();
modServerPayloadHandler = new ModServerPayloadHandler();
bookShelfInventoryRequestServerPayloadHandler = new BookShelfInventoryRequestServerPayloadHandler();
lecternInventoryRequestServerPayloadHandler = new LecternInventoryRequestServerPayloadHandler();
shelfInventoryRequestServerPayloadHandler = new ShelfInventoryRequestServerPayloadHandler();
}
}
@@ -0,0 +1,22 @@
package com.lukasabbe.bookshelfinspector.network.packets;
import com.lukasabbe.bookshelfinspector.Constants;
import net.minecraft.core.BlockPos;
import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.network.codec.ByteBufCodecs;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
import org.jetbrains.annotations.NotNull;
public record ShelfInventoryRequestPayload(BlockPos pos, int slotNum) implements CustomPacketPayload {
public static final Type<ShelfInventoryRequestPayload> ID = new Type<>(Constants.SHELF_INVENTORY_REQUEST_PACKET_ID);
public static final StreamCodec<RegistryFriendlyByteBuf, ShelfInventoryRequestPayload> CODEC = StreamCodec.composite(
BlockPos.STREAM_CODEC, ShelfInventoryRequestPayload::pos,
ByteBufCodecs.INT, ShelfInventoryRequestPayload::slotNum,
ShelfInventoryRequestPayload::new);
@Override
public @NotNull Type<? extends CustomPacketPayload> type() { return ID; }
}
@@ -0,0 +1,27 @@
package com.lukasabbe.bookshelfinspector.network.server;
import com.lukasabbe.bookshelfinspector.BookshelfInspector;
import com.lukasabbe.bookshelfinspector.network.packets.BookShelfInventoryPayload;
import com.lukasabbe.bookshelfinspector.network.packets.ShelfInventoryRequestPayload;
import com.lukasabbe.bookshelfinspector.platform.Services;
import com.lukasabbe.bookshelfinspector.platform.handlers.ServerPayloadHandler;
import com.lukasabbe.bookshelfinspector.util.BlockTools;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
public class ShelfInventoryRequestServerPayloadHandler implements ServerPayloadHandler<ShelfInventoryRequestPayload> {
@Override
public void receive(ShelfInventoryRequestPayload shelfInventoryRequestPayload, ServerPlayer player) {
if(BookshelfInspector.serverInstance == null) return;
ItemStack stack = BlockTools.getItemInShelf(shelfInventoryRequestPayload.pos(),shelfInventoryRequestPayload.slotNum(), player.level());
if(stack == null){
Services.NETWORK_HELPER.sendPacketFromServer(player, new BookShelfInventoryPayload(Items.AIR.getDefaultInstance(), shelfInventoryRequestPayload.pos(), shelfInventoryRequestPayload.slotNum()));
return;
}
Services.NETWORK_HELPER.sendPacketFromServer(player, new BookShelfInventoryPayload(stack, shelfInventoryRequestPayload.pos(), shelfInventoryRequestPayload.slotNum()));
}
}
@@ -2,6 +2,8 @@ package com.lukasabbe.bookshelfinspector.renderer;
import com.lukasabbe.bookshelfinspector.BookshelfInspectorClient;
import com.lukasabbe.bookshelfinspector.data.BookData;
import com.lukasabbe.bookshelfinspector.data.Tags;
import com.lukasabbe.bookshelfinspector.util.ItemTools;
import com.lukasabbe.bookshelfinspector.util.RomanNumerals;
import net.minecraft.ChatFormatting;
import net.minecraft.client.Minecraft;
@@ -14,7 +16,10 @@ import net.minecraft.network.chat.ComponentUtils;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.network.chat.Style;
import net.minecraft.tags.EnchantmentTags;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.effect.MobEffectUtil;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.alchemy.PotionContents;
import net.minecraft.world.item.enchantment.Enchantment;
import net.minecraft.world.item.enchantment.ItemEnchantments;
import org.joml.Matrix3x2fStack;
@@ -41,14 +46,32 @@ public class HudRenderer {
}
float scaleFactor = ((float) BookshelfInspectorClient.config.scale /10);
drawScaledText(context, itemStack.getHoverName(), x,y+((int)(10*scaleFactor)), color, client.font);
if(!BookshelfInspectorClient.bookShelfData.latestBlockState.is(Tags.SHELVES) || BookshelfInspectorClient.config.shelfDisplayNormal || !ItemTools.isNormalStack(itemStack)) {
final MutableComponent itemName = itemStack.getHoverName().copy();
ItemEnchantments storedComponents = itemStack.getComponents().get(DataComponents.STORED_ENCHANTMENTS);
if(storedComponents != null){
drawScaledText(context, itemName, x,y+((int)(10*scaleFactor)), color, client.font);
// Render item count
if (itemStack.isStackable()) {
float rightEdge = x + (client.font.width(itemName) / 2f) * scaleFactor;
float spacing = 9 * scaleFactor;
int nextX = (int) (rightEdge + spacing);
final MutableComponent count = Component.empty();
count.append(" (" + itemStack.getCount() + ")");
ComponentUtils.mergeStyles(count, Style.EMPTY.withColor(ChatFormatting.GRAY));
drawScaledText(context, count, nextX,y+((int)(10*scaleFactor)), color, client.font);
}
}
// Render enchantments
ItemEnchantments itemEnchantments = ItemTools.getItemEnchantments(itemStack);
if(itemEnchantments != null){
int i = ((int)(20*scaleFactor));
for(Holder<Enchantment> enchantment : storedComponents.keySet()){
for(Holder<Enchantment> enchantment : itemEnchantments.keySet()){
String lvl = "";
final int level = storedComponents.getLevel(enchantment);
final int level = itemEnchantments.getLevel(enchantment);
if(level != 1)
lvl = String.valueOf(level);
final MutableComponent enchantmentText;
@@ -70,6 +93,29 @@ public class HudRenderer {
}
}
// Render potion components
PotionContents itemPotionContents = ItemTools.getPotionContents(itemStack);
if (itemPotionContents != null) {
int i = ((int)(20*scaleFactor));
for (MobEffectInstance effect : itemPotionContents.getAllEffects()) {
final MutableComponent potionText;
int amplifier = effect.getAmplifier();
potionText = effect.getEffect().value().getDisplayName().copy();
if (amplifier > 0)
potionText.append(" " + RomanNumerals.toRoman(amplifier));
potionText.append(" (" + MobEffectUtil.formatDuration(effect, 1, 20).getString() + ")");
if(!effect.getEffect().value().isBeneficial()) {
ComponentUtils.mergeStyles(potionText, Style.EMPTY.withColor(ChatFormatting.RED));
}else {
ComponentUtils.mergeStyles(potionText, Style.EMPTY.withColor(ChatFormatting.GRAY));
}
drawScaledText(context, potionText, x, y + i, 0xFFFFFFFF, client.font);
i += (int) (10 * scaleFactor);
}
}
var writtenBookContentComponent = itemStack.getComponents().get(DataComponents.WRITTEN_BOOK_CONTENT);
if(writtenBookContentComponent != null){
@@ -5,10 +5,12 @@ import com.lukasabbe.bookshelfinspector.data.BookData;
import com.lukasabbe.bookshelfinspector.data.Tags;
import com.lukasabbe.bookshelfinspector.network.packets.BookShelfInventoryRequestPayload;
import com.lukasabbe.bookshelfinspector.network.packets.LecternInventoryRequestPayload;
import com.lukasabbe.bookshelfinspector.network.packets.ShelfInventoryRequestPayload;
import com.lukasabbe.bookshelfinspector.platform.Services;
import net.minecraft.client.Minecraft;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.block.ChiseledBookShelfBlock;
import net.minecraft.world.level.block.ShelfBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.HitResult;
@@ -45,19 +47,29 @@ public class Inspector {
}
bookShelfData.latestPos = pos;
if(client.player.level().getBlockState(pos).is(Tags.CHISELED_BOOKSHELVES)){
BlockState blockState = client.player.level().getBlockState(pos);
bookShelfData.latestBlockState = blockState;
if(blockState.is(Tags.CHISELED_BOOKSHELVES)){
bookShelfInspect(pos, blockHitResult, client);
}else if(client.player.level().getBlockState(pos).is(Tags.LECTERNS) && config.lecternToggle){
lecternInspect(pos);
}else{
return;
}
if(blockState.is(Tags.LECTERNS) && config.lecternToggle){
lecternInspect(pos);
return;
}
if(blockState.is(Tags.SHELVES) && config.shelfToggle){
shelfInspect(pos, blockHitResult, client);
return;
}
// No match
bookShelfData.requestSent = false; // Just for servers that don't have the latest version of mod
if(!bookShelfData.isCurrentBookDataToggled) return;
resetBookShelfData();
}
}
private void lecternInspect(BlockPos pos){
@@ -109,6 +121,38 @@ public class Inspector {
}
}
private void shelfInspect(BlockPos pos, BlockHitResult blockHitResult, Minecraft client){
final BlockState blockState = client.player.level().getBlockState(pos);
ShelfBlock shelfBlock = (ShelfBlock) blockState.getBlock();
OptionalInt optionalInt = shelfBlock.getHitSlot(blockHitResult, blockState.getValue(ShelfBlock.FACING));
// If the position is empty, return
if (optionalInt.isEmpty()) {
resetBookShelfData();
return;
}
final BookData currentBookData = BookshelfInspectorClient.currentBookData;
final int temp = bookShelfData.currentSlotInt;
final int slotNum = optionalInt.getAsInt();
bookShelfData.currentSlotInt = slotNum;
if (currentBookData.slotId != slotNum && !bookShelfData.requestSent) {
bookShelfData.requestSent = true;
Services.NETWORK_HELPER.sendPacketFromClient(new ShelfInventoryRequestPayload(pos, slotNum));
}
else {
if(temp == slotNum)
bookShelfData.isCurrentBookDataToggled = currentBookData.slotId != -2;
else{
bookShelfData.isCurrentBookDataToggled = false;
BookshelfInspectorClient.currentBookData = BookData.empty();
}
}
}
private void resetBookShelfData(){
if(!bookShelfData.isCurrentBookDataToggled) return;
@@ -6,6 +6,7 @@ import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.ChiseledBookShelfBlockEntity;
import net.minecraft.world.level.block.entity.LecternBlockEntity;
import net.minecraft.world.level.block.entity.ShelfBlockEntity;
public class BlockTools {
public static ItemStack getBookInChiseledBookShelf(BlockPos pos, int slotNum, Level world){
@@ -23,4 +24,14 @@ public class BlockTools {
if(blockEntity instanceof LecternBlockEntity lecternBlockEntity) return lecternBlockEntity.getBook();
return null;
}
public static ItemStack getItemInShelf(BlockPos pos, int slotNum, Level world){
final BlockEntity blockEntity = world.getBlockEntity(pos);
if (blockEntity instanceof ShelfBlockEntity shelfBlock) {
final ItemStack stack = shelfBlock.getItem(slotNum);
if (stack.isEmpty()) return null;
return stack;
}
return null;
}
}
@@ -0,0 +1,31 @@
package com.lukasabbe.bookshelfinspector.util;
import com.google.common.collect.Iterables;
import net.minecraft.core.component.DataComponents;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.alchemy.PotionContents;
import net.minecraft.world.item.enchantment.ItemEnchantments;
import java.util.Optional;
public class ItemTools {
public static ItemEnchantments getItemEnchantments(ItemStack itemStack) {
return Optional
.ofNullable(itemStack.getComponents().get(DataComponents.STORED_ENCHANTMENTS)) // STORED_ENCHANTMENTS is for books
.orElse(itemStack.getComponents().get(DataComponents.ENCHANTMENTS));// ENCHANTMENTS is for items that apply the enchantment
}
public static PotionContents getPotionContents(ItemStack itemStack) {
return itemStack.getComponents().get(DataComponents.POTION_CONTENTS);
}
public static boolean isNormalStack(ItemStack itemStack) {
if (!itemStack.getHoverName().equals(itemStack.getItemName())) return false;
ItemEnchantments itemEnchantments = getItemEnchantments(itemStack);
if (itemEnchantments != null && !itemEnchantments.isEmpty()) return false;
PotionContents itemPotionContents = getPotionContents(itemStack);
return itemPotionContents == null || Iterables.size(itemPotionContents.getAllEffects()) == 0;
}
}
@@ -3,6 +3,10 @@
"bookshelfinspector.config.category": "Settings",
"bookshelfinspector.config.lectern.toggle": "Turn OFF or ON lectern support",
"bookshelfinspector.config.lectern.toggle.tooltip": "This will turn OFF/ON the visibility of lectern inspection",
"bookshelfinspector.config.shelf.toggle": "Turn OFF or ON shelf support",
"bookshelfinspector.config.shelf.toggle.tooltip": "This will turn OFF/ON the visibility of shelf inspection",
"bookshelfinspector.config.shelf.display.normal": "Turn OFF or ON shelf normal item visibility",
"bookshelfinspector.config.shelf.display.normal.tooltip": "This will turn OFF/ON the visibility of normal items (unenchanted, unrenamed) on shelves",
"bookshelfinspector.config.scale": "Change the scale of the text",
"bookshelfinspector.config.scale.tooltip": "Change the scale of the text by dragging the slider",
"bookshelfinspector.config.roman_scale": "Use roman numerals!",
@@ -1,3 +1,5 @@
lectern-toggle: true
shelf-toggle: true
shelf-display-normal: true
scale: 10
roman: false
@@ -0,0 +1,6 @@
{
"replace": false,
"values": [
"#minecraft:wooden_shelves"
]
}
@@ -3,6 +3,7 @@ package com.lukasabbe.bookshelfinspector;
import com.lukasabbe.bookshelfinspector.network.packets.BookShelfInventoryPayload;
import com.lukasabbe.bookshelfinspector.network.packets.BookShelfInventoryRequestPayload;
import com.lukasabbe.bookshelfinspector.network.packets.LecternInventoryRequestPayload;
import com.lukasabbe.bookshelfinspector.network.packets.ShelfInventoryRequestPayload;
import com.lukasabbe.bookshelfinspector.network.packets.ModCheckPayload;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry;
@@ -15,6 +16,7 @@ public class BookshelfInspectorFabric implements ModInitializer {
PayloadTypeRegistry.playC2S().register(BookShelfInventoryRequestPayload.ID, BookShelfInventoryRequestPayload.CODEC);
PayloadTypeRegistry.playC2S().register(LecternInventoryRequestPayload.ID, LecternInventoryRequestPayload.CODEC);
PayloadTypeRegistry.playC2S().register(ShelfInventoryRequestPayload.ID, ShelfInventoryRequestPayload.CODEC);
PayloadTypeRegistry.playS2C().register(BookShelfInventoryPayload.ID, BookShelfInventoryPayload.CODEC);
PayloadTypeRegistry.playS2C().register(ModCheckPayload.ID, ModCheckPayload.CODEC);
@@ -24,6 +26,9 @@ public class BookshelfInspectorFabric implements ModInitializer {
ServerPlayNetworking.registerGlobalReceiver(
LecternInventoryRequestPayload.ID,
((payload, context) -> BookshelfInspector.networkHandlers.lecternInventoryRequestServerPayloadHandler.receive(payload, context.player())));
ServerPlayNetworking.registerGlobalReceiver(
ShelfInventoryRequestPayload.ID,
(payload, context) -> BookshelfInspector.networkHandlers.shelfInventoryRequestServerPayloadHandler.receive(payload, context.player()));
BookshelfInspector.init();
}
@@ -24,6 +24,16 @@ public class ModMenu implements ModMenuApi {
.setTooltip(Component.translatable("bookshelfinspector.config.lectern.toggle.tooltip"))
.setDefaultValue(true)
.setSaveConsumer(val -> BookshelfInspectorClient.config.lecternToggle = val).build())
.addEntry(entryBuilder
.startBooleanToggle(Component.translatable("bookshelfinspector.config.shelf.toggle"), BookshelfInspectorClient.config.shelfToggle)
.setTooltip(Component.translatable("bookshelfinspector.config.shelf.toggle.tooltip"))
.setDefaultValue(true)
.setSaveConsumer(val -> BookshelfInspectorClient.config.shelfToggle = val).build())
.addEntry(entryBuilder
.startBooleanToggle(Component.translatable("bookshelfinspector.config.shelf.display.normal"), BookshelfInspectorClient.config.shelfDisplayNormal)
.setTooltip(Component.translatable("bookshelfinspector.config.shelf.display.normal.tooltip"))
.setDefaultValue(true)
.setSaveConsumer(val -> BookshelfInspectorClient.config.shelfDisplayNormal = val).build())
.addEntry(entryBuilder
.startIntSlider(Component.translatable("bookshelfinspector.config.scale"),BookshelfInspectorClient.config.scale,0,20)
.setTooltip(Component.translatable("bookshelfinspector.config.scale.tooltip"))
@@ -21,6 +21,16 @@ public class ClothConfigGenerator {
.setTooltip(Component.translatable("bookshelfinspector.config.lectern.toggle.tooltip"))
.setDefaultValue(true)
.setSaveConsumer(val -> BookshelfInspectorClient.config.lecternToggle = val).build())
.addEntry(entryBuilder
.startBooleanToggle(Component.translatable("bookshelfinspector.config.shelf.toggle"), BookshelfInspectorClient.config.shelfToggle)
.setTooltip(Component.translatable("bookshelfinspector.config.shelf.toggle.tooltip"))
.setDefaultValue(true)
.setSaveConsumer(val -> BookshelfInspectorClient.config.shelfToggle = val).build())
.addEntry(entryBuilder
.startBooleanToggle(Component.translatable("bookshelfinspector.config.shelf.display.normal"), BookshelfInspectorClient.config.shelfDisplayNormal)
.setTooltip(Component.translatable("bookshelfinspector.config.shelf.display.normal.tooltip"))
.setDefaultValue(true)
.setSaveConsumer(val -> BookshelfInspectorClient.config.shelfDisplayNormal = val).build())
.addEntry(entryBuilder
.startIntSlider(Component.translatable("bookshelfinspector.config.scale"),BookshelfInspectorClient.config.scale,0,20)
.setTooltip(Component.translatable("bookshelfinspector.config.scale.tooltip"))
@@ -5,6 +5,7 @@ import com.lukasabbe.bookshelfinspector.Constants;
import com.lukasabbe.bookshelfinspector.network.packets.BookShelfInventoryPayload;
import com.lukasabbe.bookshelfinspector.network.packets.BookShelfInventoryRequestPayload;
import com.lukasabbe.bookshelfinspector.network.packets.LecternInventoryRequestPayload;
import com.lukasabbe.bookshelfinspector.network.packets.ShelfInventoryRequestPayload;
import com.lukasabbe.bookshelfinspector.network.packets.ModCheckPayload;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.server.level.ServerPlayer;
@@ -37,6 +38,11 @@ public class NetworkHandler {
LecternInventoryRequestPayload.CODEC,
((payload, context) -> BookshelfInspector.networkHandlers.lecternInventoryRequestServerPayloadHandler.receive(payload, (ServerPlayer) context.player()))
);
registrar.playToServer(
ShelfInventoryRequestPayload.ID,
ShelfInventoryRequestPayload.CODEC,
((payload, context) -> BookshelfInspector.networkHandlers.shelfInventoryRequestServerPayloadHandler.receive(payload, (ServerPlayer) context.player()))
);
}
}