lectern support

This commit is contained in:
lukasabbe
2024-10-20 20:57:29 +02:00
parent cbbd1fc429
commit 552b11b70e
18 changed files with 313 additions and 70 deletions
@@ -1,19 +1,17 @@
package me.lukasabbe.bookshelfinspector;
import io.netty.buffer.Unpooled;
import me.lukasabbe.bookshelfinspector.network.BookShelfInventoryPayload;
import me.lukasabbe.bookshelfinspector.network.BookShelfInventoryRequestPayload;
import me.lukasabbe.bookshelfinspector.network.LecternInventoryRequestPayload;
import me.lukasabbe.bookshelfinspector.network.ModCheckPayload;
import me.lukasabbe.bookshelfinspector.util.BookshelfTools;
import me.lukasabbe.bookshelfinspector.util.LecternTools;
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.network.RegistryByteBuf;
import net.minecraft.network.codec.PacketCodec;
import net.minecraft.registry.DynamicRegistryManager;
import net.minecraft.server.MinecraftServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -27,10 +25,10 @@ public class Bookshelfinspector implements ModInitializer {
@Override
public void onInitialize() {
PayloadTypeRegistry.playC2S().register(BookShelfInventoryRequestPayload.ID,BookShelfInventoryRequestPayload.CODEC);
PayloadTypeRegistry.playC2S().register(LecternInventoryRequestPayload.ID, LecternInventoryRequestPayload.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;
@@ -40,7 +38,18 @@ public class Bookshelfinspector implements ModInitializer {
return;
}
ServerPlayNetworking.send(context.player(), new BookShelfInventoryPayload(stack, payload.pos(), payload.slotNum()));
new RegistryByteBuf(Unpooled.buffer(), DynamicRegistryManager.EMPTY);
})));
ServerPlayNetworking.registerGlobalReceiver(LecternInventoryRequestPayload.ID, ((payload, context) -> context.server().execute(() ->{
if(Bookshelfinspector.serverInstance == null) return;
ItemStack stack = LecternTools.getItemStack(payload.pos(), context.player());
if(stack == null){
ServerPlayNetworking.send(context.player(), new BookShelfInventoryPayload(Items.AIR.getDefaultStack(), payload.pos(), 0));
return;
}
ServerPlayNetworking.send(context.player(), new BookShelfInventoryPayload(stack, payload.pos(), 0));
})));
ServerPlayConnectionEvents.JOIN.register(((handler, sender, server) -> {
@@ -1,5 +1,6 @@
package me.lukasabbe.bookshelfinspector;
import me.lukasabbe.bookshelfinspector.config.Config;
import me.lukasabbe.bookshelfinspector.data.BookData;
import me.lukasabbe.bookshelfinspector.data.BookShelfData;
import me.lukasabbe.bookshelfinspector.network.BookShelfInventoryPayload;
@@ -17,9 +18,11 @@ public class BookshelfinspectorClient implements ClientModInitializer {
public static BookData currentBookData = BookData.empty();
public static BookShelfData bookShelfData = new BookShelfData();
public static boolean modAvailable = false;
public static Config config = new Config();
@Override
public void onInitializeClient() {
config.loadConfig();
ClientPlayNetworking.registerGlobalReceiver(BookShelfInventoryPayload.ID,
((payload, context) ->
context.client().execute(() ->{
@@ -0,0 +1,61 @@
package me.lukasabbe.bookshelfinspector.config;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.fabricmc.loader.api.FabricLoader;
import org.yaml.snakeyaml.Yaml;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Map;
@Environment(EnvType.CLIENT)
public class Config {
public boolean lecternToggle = true;
public void loadConfig(){
Path configPath = FabricLoader.getInstance().getConfigDir().resolve("bookshelfinspector-config.yml");
if(!Files.exists(configPath))createConfig(configPath);
Yaml yaml = new Yaml();
try{
Map<String, Object> configMap = yaml.load(new FileReader(configPath.toFile()));
if(configMap.containsKey("lectern-toggle")){
lecternToggle = (boolean) configMap.get("lectern-toggle");
}
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
}
private void createConfig(Path configPath){
FabricLoader.getInstance().getModContainer("bookshelfinspector").ifPresent(modContainer -> {
Path path = modContainer.findPath("bookshelfinspector-config.yml").orElseThrow();
try {
Files.copy(path,configPath);
} catch (IOException e) {
throw new RuntimeException(e);
}
});
}
public void saveConfig(){
Path configPath = FabricLoader.getInstance().getConfigDir().resolve("bookshelfinspector-config.yml");
if(!Files.exists(configPath))createConfig(configPath);
Yaml yaml = new Yaml();
try{
Map<String, Object> configMap = yaml.load(new FileReader(configPath.toFile()));
configMap.put("lectern-toggle",lecternToggle);
FileWriter writer = new FileWriter(configPath.toString());
yaml.dump(configMap,writer);
writer.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
@@ -0,0 +1,34 @@
package me.lukasabbe.bookshelfinspector.config;
import com.terraformersmc.modmenu.api.ConfigScreenFactory;
import com.terraformersmc.modmenu.api.ModMenuApi;
import me.lukasabbe.bookshelfinspector.BookshelfinspectorClient;
import me.shedaniel.clothconfig2.api.ConfigBuilder;
import me.shedaniel.clothconfig2.api.ConfigEntryBuilder;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.text.Text;
@Environment(EnvType.CLIENT)
public class ModMenu implements ModMenuApi {
@Override
public ConfigScreenFactory<?> getModConfigScreenFactory() {
return parent -> {
ConfigBuilder builder = ConfigBuilder
.create()
.setParentScreen(parent)
.setTitle(Text.translatable("bookshelfinspector.config.title"));
ConfigEntryBuilder entryBuilder = builder.entryBuilder();
builder
.getOrCreateCategory(Text.translatable("bookshelfinspector.config.category"))
.addEntry(entryBuilder
.startBooleanToggle(Text.translatable("bookshelfinspector.config.lectern.toggle"), BookshelfinspectorClient.config.lecternToggle)
.setTooltip(Text.translatable("bookshelfinspector.config.lectern.toggle.tooltip"))
.setDefaultValue(true)
.setSaveConsumer(val -> BookshelfinspectorClient.config.lecternToggle = val).build());
builder.setSavingRunnable(BookshelfinspectorClient.config::saveConfig);
return builder.build();
};
}
}
@@ -1,7 +1,10 @@
package me.lukasabbe.bookshelfinspector.data;
import net.minecraft.util.math.BlockPos;
public class BookShelfData {
public boolean isCurrentBookDataToggled = false;
public BlockPos latestPos = null;
public boolean requestSent = false;
public int currentSlotInt = -1;
}
@@ -1,18 +1,8 @@
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 me.lukasabbe.bookshelfinspector.util.Inspector;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientPlayerEntity;
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;
@@ -21,63 +11,18 @@ 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;
@Unique
private final Inspector inspector = new Inspector();
@Inject(method = "tick", at= @At(value = "INVOKE", target = "Ljava/util/List;iterator()Ljava/util/Iterator;"))
public void injectTick(CallbackInfo ci){
bookShelfInspect();
inspector.inspect(client);
}
@Unique
public void bookShelfInspect(){
if(!BookshelfinspectorClient.modAvailable) return;
if(client.cameraEntity == null || client.player == null) return;
HitResult hit = client.cameraEntity.raycast(5f,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.bookShelfData.isCurrentBookDataToggled = false;
BookshelfinspectorClient.currentBookData = BookData.empty();
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.bookShelfData.isCurrentBookDataToggled = false;
return;
}
final BookData currentBookData = BookshelfinspectorClient.currentBookData;
int temp = BookshelfinspectorClient.bookShelfData.currentSlotInt;
final int slotNum = optionalInt.getAsInt();
BookshelfinspectorClient.bookShelfData.currentSlotInt = slotNum;
if(currentBookData.slotId!= slotNum && currentBookData.slotId!=-2 && !BookshelfinspectorClient.bookShelfData.requestSent){
BookshelfinspectorClient.bookShelfData.requestSent = true;
ClientPlayNetworking.send(new BookShelfInventoryRequestPayload(pos, slotNum));
}
else {
if(temp == slotNum)
BookshelfinspectorClient.bookShelfData.isCurrentBookDataToggled = currentBookData.slotId != -2;
else
BookshelfinspectorClient.currentBookData = BookData.empty();
}
}
}
@@ -7,4 +7,5 @@ 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");
public static final Identifier LECTERN_INVENTORY_REQUEST_PACKET_ID = Identifier.of(Bookshelfinspector.MOD_ID, "lectern_inventory_request");
}
@@ -0,0 +1,19 @@
package me.lukasabbe.bookshelfinspector.network;
import net.minecraft.network.RegistryByteBuf;
import net.minecraft.network.codec.PacketCodec;
import net.minecraft.network.packet.CustomPayload;
import net.minecraft.util.math.BlockPos;
public record LecternInventoryRequestPayload(BlockPos pos) implements CustomPayload{
public static final CustomPayload.Id<LecternInventoryRequestPayload> ID = new CustomPayload.Id<>(BookShelfInspectorNetworkConstants.LECTERN_INVENTORY_REQUEST_PACKET_ID);
public static final PacketCodec<RegistryByteBuf, LecternInventoryRequestPayload> CODEC = PacketCodec.tuple(
BlockPos.PACKET_CODEC,LecternInventoryRequestPayload::pos,
LecternInventoryRequestPayload::new);
@Override
public CustomPayload.Id<? extends CustomPayload> getId() {
return ID;
}
}
@@ -0,0 +1,110 @@
package me.lukasabbe.bookshelfinspector.util;
import me.lukasabbe.bookshelfinspector.BookshelfinspectorClient;
import me.lukasabbe.bookshelfinspector.data.BookData;
import me.lukasabbe.bookshelfinspector.mixin.BookshelfInvoker;
import me.lukasabbe.bookshelfinspector.network.BookShelfInventoryRequestPayload;
import me.lukasabbe.bookshelfinspector.network.LecternInventoryRequestPayload;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.ChiseledBookshelfBlock;
import net.minecraft.block.entity.BlockEntityType;
import net.minecraft.block.entity.ChiseledBookshelfBlockEntity;
import net.minecraft.block.entity.LecternBlockEntity;
import net.minecraft.client.MinecraftClient;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.hit.HitResult;
import net.minecraft.util.math.BlockPos;
import java.util.Optional;
import java.util.OptionalInt;
@Environment(EnvType.CLIENT)
public class Inspector {
public void inspect(MinecraftClient client){
if(!BookshelfinspectorClient.modAvailable) return;
if(client.cameraEntity == null || client.player == null) return;
HitResult hit = client.cameraEntity.raycast(5f,0f,false);
final HitResult.Type type = hit.getType();
if(type != HitResult.Type.BLOCK) {
BookshelfinspectorClient.bookShelfData.isCurrentBookDataToggled = false;
BookshelfinspectorClient.currentBookData = BookData.empty();
}
final BlockHitResult blockHitResult = (BlockHitResult) hit;
BlockPos pos = blockHitResult.getBlockPos();
if(client.player.getWorld().getBlockState(pos).isOf(Blocks.CHISELED_BOOKSHELF)){
bookShelfInspect(pos, blockHitResult, client);
}else if(client.player.getWorld().getBlockState(pos).isOf(Blocks.LECTERN) && BookshelfinspectorClient.config.lecternToggle){
lecternInspect(pos, client);
}else{
BookshelfinspectorClient.bookShelfData.isCurrentBookDataToggled = false;
BookshelfinspectorClient.currentBookData = BookData.empty();
BookshelfinspectorClient.bookShelfData.latestPos = null;
BookshelfinspectorClient.bookShelfData.requestSent = false;
}
}
private void lecternInspect(BlockPos pos, MinecraftClient client){
Optional<LecternBlockEntity> optionalLecternBlockEntity = client.player.getWorld().getBlockEntity(pos, BlockEntityType.LECTERN);
if(optionalLecternBlockEntity.isEmpty()){
BookshelfinspectorClient.bookShelfData.isCurrentBookDataToggled = false;
BookshelfinspectorClient.currentBookData = BookData.empty();
return;
}
if(BookshelfinspectorClient.bookShelfData.latestPos != null && BookshelfinspectorClient.bookShelfData.latestPos.equals(pos)){
return;
}
if(!BookshelfinspectorClient.bookShelfData.requestSent){
BookshelfinspectorClient.bookShelfData.requestSent = true;
ClientPlayNetworking.send(new LecternInventoryRequestPayload(pos));
BookshelfinspectorClient.bookShelfData.latestPos = pos;
}
}
private void bookShelfInspect(BlockPos pos, BlockHitResult blockHitResult, MinecraftClient client){
Optional<ChiseledBookshelfBlockEntity> optionalChiseledBookshelfBlockEntity = client.player.getWorld().getBlockEntity(pos, BlockEntityType.CHISELED_BOOKSHELF);
if(optionalChiseledBookshelfBlockEntity.isEmpty()){
BookshelfinspectorClient.bookShelfData.isCurrentBookDataToggled = false;
BookshelfinspectorClient.currentBookData = BookData.empty();
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.bookShelfData.isCurrentBookDataToggled = false;
return;
}
final BookData currentBookData = BookshelfinspectorClient.currentBookData;
int temp = BookshelfinspectorClient.bookShelfData.currentSlotInt;
final int slotNum = optionalInt.getAsInt();
BookshelfinspectorClient.bookShelfData.currentSlotInt = slotNum;
if(currentBookData.slotId!= slotNum && currentBookData.slotId!=-2 && !BookshelfinspectorClient.bookShelfData.requestSent){
BookshelfinspectorClient.bookShelfData.requestSent = true;
ClientPlayNetworking.send(new BookShelfInventoryRequestPayload(pos, slotNum));
}
else {
if(temp == slotNum)
BookshelfinspectorClient.bookShelfData.isCurrentBookDataToggled = currentBookData.slotId != -2;
else{
BookshelfinspectorClient.bookShelfData.isCurrentBookDataToggled = false;
BookshelfinspectorClient.currentBookData = BookData.empty();
}
}
}
}
@@ -0,0 +1,25 @@
package me.lukasabbe.bookshelfinspector.util;
import me.lukasabbe.bookshelfinspector.Bookshelfinspector;
import net.minecraft.block.entity.BlockEntityType;
import net.minecraft.block.entity.LecternBlockEntity;
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 LecternTools {
public static ItemStack getItemStack(BlockPos pos, PlayerEntity player){
final World world = Bookshelfinspector.serverInstance.getPlayerManager().getPlayer(player.getUuid()).getWorld();
if(world == null) return null;
Optional<LecternBlockEntity> blockEntityOptional = world.getBlockEntity(pos, BlockEntityType.LECTERN);
if(blockEntityOptional.isEmpty()) return null;
LecternBlockEntity lecternBlock = blockEntityOptional.get();
return lecternBlock.getBook();
}
}
@@ -0,0 +1,6 @@
{
"bookshelfinspector.config.title": "Bookshelf Inspector Config",
"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"
}
@@ -0,0 +1,6 @@
{
"bookshelfinspector.config.title": "Bookshelf Inspector Config",
"bookshelfinspector.config.category": "Inställningar",
"bookshelfinspector.config.lectern.toggle": "Stäng AV eller PÅ läspulpet stöd",
"bookshelfinspector.config.lectern.toggle.tooltip": "Denna inställning kommer stänga av eller på synligeten av läspulpet inspection"
}
@@ -0,0 +1 @@
lectern-toggle: true
+3
View File
@@ -15,6 +15,9 @@
],
"main": [
"me.lukasabbe.bookshelfinspector.Bookshelfinspector"
],
"modmenu": [
"me.lukasabbe.bookshelfinspector.config.ModMenu"
]
},
"mixins": [