mirror of
https://github.com/lukasabbe/bookshelf-inspector.git
synced 2026-04-30 10:40:53 +00:00
Init
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
package me.lukasabbe.bookshelfinspector;
|
||||
|
||||
import me.lukasabbe.bookshelfinspector.network.BookShelfInventoryPayload;
|
||||
import me.lukasabbe.bookshelfinspector.network.BookShelfInventoryRequestPayload;
|
||||
import me.lukasabbe.bookshelfinspector.network.ModCheckPayload;
|
||||
import me.lukasabbe.bookshelfinspector.util.BookshelfTools;
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry;
|
||||
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
|
||||
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class Bookshelfinspector implements ModInitializer {
|
||||
public static MinecraftServer serverInstance;
|
||||
public final static String MOD_ID = "bookshelfinspector";
|
||||
|
||||
public static Logger LOGGER = Logger.getLogger(MOD_ID);
|
||||
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
PayloadTypeRegistry.playC2S().register(BookShelfInventoryRequestPayload.ID,BookShelfInventoryRequestPayload.CODEC);
|
||||
PayloadTypeRegistry.playS2C().register(BookShelfInventoryPayload.ID,BookShelfInventoryPayload.CODEC);
|
||||
PayloadTypeRegistry.playS2C().register(ModCheckPayload.ID, ModCheckPayload.CODEC);
|
||||
|
||||
|
||||
ServerPlayNetworking.registerGlobalReceiver(BookShelfInventoryRequestPayload.ID,((payload, context) -> context.server().execute(() -> {
|
||||
if(Bookshelfinspector.serverInstance == null) return;
|
||||
|
||||
ItemStack stack = BookshelfTools.getItemById(payload.pos(),payload.slotNum(),context.player());
|
||||
if(stack == null){
|
||||
ServerPlayNetworking.send(context.player(), new BookShelfInventoryPayload(Items.AIR.getDefaultStack(), payload.pos(), payload.slotNum()));
|
||||
return;
|
||||
}
|
||||
ServerPlayNetworking.send(context.player(), new BookShelfInventoryPayload(stack, payload.pos(), payload.slotNum()));
|
||||
})));
|
||||
|
||||
ServerPlayConnectionEvents.JOIN.register(((handler, sender, server) -> {
|
||||
serverInstance = server;
|
||||
ServerPlayNetworking.send(handler.player, new ModCheckPayload(true));
|
||||
}));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package me.lukasabbe.bookshelfinspector;
|
||||
|
||||
import me.lukasabbe.bookshelfinspector.data.BookData;
|
||||
import me.lukasabbe.bookshelfinspector.network.BookShelfInventoryPayload;
|
||||
import me.lukasabbe.bookshelfinspector.network.ModCheckPayload;
|
||||
import net.fabricmc.api.ClientModInitializer;
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.util.hit.HitResult;
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
public class BookshelfinspectorClient implements ClientModInitializer {
|
||||
|
||||
public static BookData currentBookData = new BookData(ItemStack.EMPTY, null, -1);
|
||||
public static boolean isCurrentBookDataToggled = false;
|
||||
public static boolean modAvailable = false;
|
||||
public static HitResult latestHit;
|
||||
|
||||
@Override
|
||||
public void onInitializeClient() {
|
||||
ClientPlayNetworking.registerGlobalReceiver(BookShelfInventoryPayload.ID,
|
||||
((payload, context) ->
|
||||
context.client().execute(() ->{
|
||||
if(payload.itemStack().isOf(Items.AIR))
|
||||
isCurrentBookDataToggled = false;
|
||||
else{
|
||||
BookshelfinspectorClient.isCurrentBookDataToggled = true;
|
||||
currentBookData = new BookData(payload.itemStack(),payload.pos(),payload.slotNum());
|
||||
}
|
||||
})));
|
||||
|
||||
ClientPlayNetworking.registerGlobalReceiver(ModCheckPayload.ID,
|
||||
(payload, context) -> context.client().execute(() ->{
|
||||
Bookshelfinspector.LOGGER.info("Connected to server");
|
||||
modAvailable = true;
|
||||
}));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package me.lukasabbe.bookshelfinspector.data;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
public class BookData {
|
||||
public ItemStack itemStack;
|
||||
public BlockPos pos;
|
||||
public int slotId;
|
||||
|
||||
public BookData(ItemStack itemStack, BlockPos pos, int slotId) {
|
||||
this.itemStack = itemStack;
|
||||
this.pos = pos;
|
||||
this.slotId = slotId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package me.lukasabbe.bookshelfinspector.mixin;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.ChiseledBookshelfBlock;
|
||||
import net.minecraft.util.hit.BlockHitResult;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
|
||||
import java.util.OptionalInt;
|
||||
|
||||
@Mixin(ChiseledBookshelfBlock.class)
|
||||
public interface BookshelfInvoker {
|
||||
@Invoker("getSlotForHitPos")
|
||||
OptionalInt invokerGetSlotForHitPos(BlockHitResult hit, BlockState state);
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package me.lukasabbe.bookshelfinspector.mixin;
|
||||
|
||||
import me.lukasabbe.bookshelfinspector.BookshelfinspectorClient;
|
||||
import me.lukasabbe.bookshelfinspector.data.BookData;
|
||||
import me.lukasabbe.bookshelfinspector.network.BookShelfInventoryRequestPayload;
|
||||
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.ChiseledBookshelfBlock;
|
||||
import net.minecraft.block.entity.BlockEntityType;
|
||||
import net.minecraft.block.entity.ChiseledBookshelfBlockEntity;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.network.ClientPlayerEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.hit.BlockHitResult;
|
||||
import net.minecraft.util.hit.HitResult;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.OptionalInt;
|
||||
|
||||
@Mixin(ClientPlayerEntity.class)
|
||||
public class BookshelfMixin{
|
||||
|
||||
@Shadow @Final protected MinecraftClient client;
|
||||
|
||||
@Inject(method = "tick", at= @At(value = "INVOKE", target = "Ljava/util/List;iterator()Ljava/util/Iterator;"))
|
||||
public void injectTick(CallbackInfo ci){
|
||||
bookShelfInspect();
|
||||
}
|
||||
|
||||
@Unique
|
||||
public void bookShelfInspect(){
|
||||
if(!BookshelfinspectorClient.modAvailable) return;
|
||||
|
||||
if(client.cameraEntity == null || client.player == null) return;
|
||||
|
||||
HitResult hit = client.cameraEntity.raycast(20f,0f,false);
|
||||
final HitResult.Type type = hit.getType();
|
||||
if(type != HitResult.Type.BLOCK) return;
|
||||
final BlockHitResult blockHitResult = (BlockHitResult) hit;
|
||||
BlockPos pos = blockHitResult.getBlockPos();
|
||||
|
||||
Optional<ChiseledBookshelfBlockEntity> optionalChiseledBookshelfBlockEntity = client.player.getWorld().getBlockEntity(pos, BlockEntityType.CHISELED_BOOKSHELF);
|
||||
if(optionalChiseledBookshelfBlockEntity.isEmpty()){
|
||||
BookshelfinspectorClient.isCurrentBookDataToggled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
final BlockState blockState = client.player.getWorld().getBlockState(pos);
|
||||
|
||||
ChiseledBookshelfBlock bookshelfBlock = (ChiseledBookshelfBlock) blockState.getBlock();
|
||||
|
||||
OptionalInt optionalInt = ((BookshelfInvoker)bookshelfBlock).invokerGetSlotForHitPos(blockHitResult,blockState);
|
||||
if(optionalInt.isEmpty()) {
|
||||
BookshelfinspectorClient.isCurrentBookDataToggled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
BookshelfinspectorClient.latestHit = hit;
|
||||
|
||||
final BookData currentBookData = BookshelfinspectorClient.currentBookData;
|
||||
if(currentBookData.itemStack == ItemStack.EMPTY || currentBookData.slotId!=optionalInt.getAsInt() || currentBookData.pos != pos){
|
||||
ClientPlayNetworking.send(new BookShelfInventoryRequestPayload(pos, optionalInt.getAsInt()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package me.lukasabbe.bookshelfinspector.mixin;
|
||||
|
||||
import me.lukasabbe.bookshelfinspector.Bookshelfinspector;
|
||||
import me.lukasabbe.bookshelfinspector.BookshelfinspectorClient;
|
||||
import me.lukasabbe.bookshelfinspector.data.BookData;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.DrawContext;
|
||||
import net.minecraft.client.gui.hud.InGameHud;
|
||||
import net.minecraft.client.render.RenderTickCounter;
|
||||
import net.minecraft.component.DataComponentTypes;
|
||||
import net.minecraft.enchantment.Enchantment;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.registry.entry.RegistryEntry;
|
||||
import net.minecraft.text.Text;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(InGameHud.class)
|
||||
|
||||
public class InGameHudMixin {
|
||||
@Shadow @Final private MinecraftClient client;
|
||||
|
||||
@Inject(method = "render",at=@At("RETURN"))
|
||||
public void render(DrawContext context, RenderTickCounter tickCounter, CallbackInfo ci){
|
||||
if(!BookshelfinspectorClient.modAvailable) return;
|
||||
|
||||
if(client.options.hudHidden) return;
|
||||
|
||||
if(BookshelfinspectorClient.isCurrentBookDataToggled){
|
||||
final BookData currentBookData = BookshelfinspectorClient.currentBookData;
|
||||
int screenWidth = client.getWindow().getScaledWidth();
|
||||
int screenHeight = client.getWindow().getScaledHeight();
|
||||
int x = screenWidth / 2;
|
||||
int y = screenHeight / 2;
|
||||
final ItemStack itemStack = currentBookData.itemStack;
|
||||
int color = 0xFFFFFFFF;
|
||||
if(itemStack.getRarity().getFormatting().getColorValue() != null){
|
||||
color = itemStack.getRarity().getFormatting().getColorValue();
|
||||
}
|
||||
context.drawCenteredTextWithShadow(client.textRenderer, itemStack.getName(), x,y+10, color);
|
||||
|
||||
var storedComponets = itemStack.getComponents().get(DataComponentTypes.STORED_ENCHANTMENTS);
|
||||
if(storedComponets != null){
|
||||
int i = 20;
|
||||
for(RegistryEntry<Enchantment> enchantment : storedComponets.getEnchantments()){
|
||||
context.drawCenteredTextWithShadow(client.textRenderer, enchantment.value().description(), x,y+i, 0xFFFFFFFF);
|
||||
i+=10;
|
||||
}
|
||||
}
|
||||
|
||||
var writtenBookContentComponent = itemStack.getComponents().get(DataComponentTypes.WRITTEN_BOOK_CONTENT);
|
||||
|
||||
if(writtenBookContentComponent != null){
|
||||
context.drawCenteredTextWithShadow(client.textRenderer, Text.translatableWithFallback("bookshelfinspector.text.book","By ").append(writtenBookContentComponent.author()), x,y+20, 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package me.lukasabbe.bookshelfinspector.network;
|
||||
|
||||
import me.lukasabbe.bookshelfinspector.Bookshelfinspector;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
public class BookShelfInspectorNetworkConstants {
|
||||
public static final Identifier BOOK_SHELF_INVENTORY_REQUEST_PACKET_ID = Identifier.of(Bookshelfinspector.MOD_ID,"book_shelf_inventory_request");
|
||||
public static final Identifier BOOK_SHELF_INVENTORY_PACKET_ID = Identifier.of(Bookshelfinspector.MOD_ID,"book_shelf_inventory");
|
||||
public static final Identifier MOD_CHECK_PACKET_ID = Identifier.of(Bookshelfinspector.MOD_ID,"mod_check");
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package me.lukasabbe.bookshelfinspector.network;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.network.RegistryByteBuf;
|
||||
import net.minecraft.network.codec.PacketCodec;
|
||||
import net.minecraft.network.codec.PacketCodecs;
|
||||
import net.minecraft.network.packet.CustomPayload;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
public record BookShelfInventoryPayload(ItemStack itemStack, BlockPos pos, int slotNum) implements CustomPayload{
|
||||
public static final CustomPayload.Id<BookShelfInventoryPayload> ID = new CustomPayload.Id<>(BookShelfInspectorNetworkConstants.BOOK_SHELF_INVENTORY_PACKET_ID);
|
||||
public static final PacketCodec<RegistryByteBuf, BookShelfInventoryPayload> CODEC = PacketCodec.tuple(
|
||||
ItemStack.OPTIONAL_PACKET_CODEC, BookShelfInventoryPayload::itemStack,
|
||||
BlockPos.PACKET_CODEC, BookShelfInventoryPayload::pos,
|
||||
PacketCodecs.INTEGER, BookShelfInventoryPayload::slotNum,
|
||||
BookShelfInventoryPayload::new);
|
||||
|
||||
@Override
|
||||
public CustomPayload.Id<? extends CustomPayload> getId() {
|
||||
return ID;
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package me.lukasabbe.bookshelfinspector.network;
|
||||
|
||||
import net.minecraft.network.RegistryByteBuf;
|
||||
import net.minecraft.network.codec.PacketCodec;
|
||||
import net.minecraft.network.codec.PacketCodecs;
|
||||
import net.minecraft.network.packet.CustomPayload;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
public record BookShelfInventoryRequestPayload(BlockPos pos, int slotNum) implements CustomPayload {
|
||||
|
||||
public static final CustomPayload.Id<BookShelfInventoryRequestPayload> ID = new CustomPayload.Id<>(BookShelfInspectorNetworkConstants.BOOK_SHELF_INVENTORY_REQUEST_PACKET_ID);
|
||||
|
||||
public static final PacketCodec<RegistryByteBuf, BookShelfInventoryRequestPayload> CODEC = PacketCodec.tuple(
|
||||
BlockPos.PACKET_CODEC,BookShelfInventoryRequestPayload::pos,
|
||||
PacketCodecs.INTEGER, BookShelfInventoryRequestPayload::slotNum,
|
||||
BookShelfInventoryRequestPayload::new);
|
||||
|
||||
@Override
|
||||
public Id<? extends CustomPayload> getId() {
|
||||
return ID;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package me.lukasabbe.bookshelfinspector.network;
|
||||
|
||||
import net.minecraft.network.RegistryByteBuf;
|
||||
import net.minecraft.network.codec.PacketCodec;
|
||||
import net.minecraft.network.codec.PacketCodecs;
|
||||
import net.minecraft.network.packet.CustomPayload;
|
||||
|
||||
public record ModCheckPayload(boolean modActivated) implements CustomPayload {
|
||||
|
||||
public static final CustomPayload.Id<ModCheckPayload> ID = new CustomPayload.Id<>(BookShelfInspectorNetworkConstants.MOD_CHECK_PACKET_ID);
|
||||
|
||||
public static final PacketCodec<RegistryByteBuf, ModCheckPayload> CODEC = PacketCodec.tuple(
|
||||
PacketCodecs.BOOL, ModCheckPayload::modActivated,
|
||||
ModCheckPayload::new
|
||||
);
|
||||
|
||||
@Override
|
||||
public Id<? extends CustomPayload> getId() {
|
||||
return ID;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package me.lukasabbe.bookshelfinspector.util;
|
||||
|
||||
import me.lukasabbe.bookshelfinspector.Bookshelfinspector;
|
||||
import net.minecraft.block.entity.BlockEntityType;
|
||||
import net.minecraft.block.entity.ChiseledBookshelfBlockEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class BookshelfTools {
|
||||
public static ItemStack getItemById(BlockPos pos, int slotNum, PlayerEntity player){
|
||||
final World world = Bookshelfinspector.serverInstance.getPlayerManager().getPlayer(player.getUuid()).getWorld();
|
||||
|
||||
if(world == null) return null;
|
||||
Optional<ChiseledBookshelfBlockEntity> blockEntityOptional = world.getBlockEntity(pos,BlockEntityType.CHISELED_BOOKSHELF);
|
||||
if(blockEntityOptional.isEmpty()) return null;
|
||||
|
||||
ChiseledBookshelfBlockEntity blockEntity = blockEntityOptional.get();
|
||||
|
||||
final ItemStack stack = blockEntity.getStack(slotNum);
|
||||
if(stack.isEmpty()) return null;
|
||||
|
||||
return stack;
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 60 KiB |
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"bookshelfinspector.text.book" : "By "
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"bookshelfinspector.text.book" : "Av "
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"required": true,
|
||||
"minVersion": "0.8",
|
||||
"package": "me.lukasabbe.bookshelfinspector.mixin",
|
||||
"compatibilityLevel": "JAVA_21",
|
||||
"mixins": [
|
||||
],
|
||||
"client": [
|
||||
"InGameHudMixin",
|
||||
"BookshelfInvoker",
|
||||
"BookshelfMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"id": "bookshelfinspector",
|
||||
"version": "${version}",
|
||||
"name": "Bookshelfinspector",
|
||||
"description": "Inspect any book in a chiseled bookshelf.",
|
||||
"authors": ["Lukasabbe"],
|
||||
"contact": {},
|
||||
"license": "MIT",
|
||||
"icon": "assets/bookshelfinspector/icon.png",
|
||||
"environment": "*",
|
||||
"entrypoints": {
|
||||
"client": [
|
||||
"me.lukasabbe.bookshelfinspector.BookshelfinspectorClient"
|
||||
],
|
||||
"main": [
|
||||
"me.lukasabbe.bookshelfinspector.Bookshelfinspector"
|
||||
]
|
||||
},
|
||||
"mixins": [
|
||||
"bookshelfinspector.mixins.json"
|
||||
],
|
||||
"depends": {
|
||||
"fabricloader": ">=${loader_version}",
|
||||
"minecraft": ">=${minecraft_version}",
|
||||
"fabric-api-base": "*",
|
||||
"fabric-networking-api-v1": "*",
|
||||
"fabric-lifecycle-events-v1": "*"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user