Skip to content

Commit

Permalink
lectern support
Browse files Browse the repository at this point in the history
  • Loading branch information
lukasabbe committed Oct 20, 2024
1 parent cbbd1fc commit 552b11b
Show file tree
Hide file tree
Showing 18 changed files with 313 additions and 70 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ Written book:
Normal book:
![Example 3. with a normal book](./images/2024-09-20_22.38.19.png)

lectern:
![Example 4. with a lectern with a book](./images/lectern_support.png)

# Multiplayer

This mod will need to be on the server to work in multiplayer.
Expand Down
15 changes: 12 additions & 3 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ base {
}


repositories {}
repositories {
maven { url "https://maven.shedaniel.me/" }
maven { url "https://maven.terraformersmc.com/releases/" }
}

dependencies {
// To change the versions see the gradle.properties file
Expand All @@ -22,12 +25,18 @@ dependencies {
Set<String> apiMudules = [
"fabric-api-base",
"fabric-networking-api-v1",
"fabric-lifecycle-events-v1"
"fabric-lifecycle-events-v1",
"fabric-resource-loader-v0"
]

apiMudules.forEach {
include(modImplementation(fabricApi.module(it,project.fabric_version)))
modImplementation(fabricApi.module(it,project.fabric_version))
}

modApi "me.shedaniel.cloth:cloth-config-fabric:${project.cloth_config}"
modApi "com.terraformersmc:modmenu:${project.modmenu}"

include(implementation "org.yaml:snakeyaml:${project.YAML_snake}")
}

processResources {
Expand Down
7 changes: 6 additions & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,14 @@ minecraft_version=1.21
yarn_mappings=1.21+build.9
loader_version=0.16.5
# Mod Properties
mod_version=1.4+1.21

mod_version=1.5+1.21
maven_group=me.lukasabbe
archives_base_name=Bookshelfinspector

# Dependencies
fabric_version=0.104.0+1.21.1
cloth_config=15.0.140
modmenu=11.0.3
YAML_snake=2.2

Binary file added images/lectern_support.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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;

Expand All @@ -40,7 +38,18 @@ public void onInitialize() {
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) -> {
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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(() ->{
Expand Down
61 changes: 61 additions & 0 deletions src/main/java/me/lukasabbe/bookshelfinspector/config/Config.java
Original file line number Diff line number Diff line change
@@ -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);
}
}
}
34 changes: 34 additions & 0 deletions src/main/java/me/lukasabbe/bookshelfinspector/config/ModMenu.java
Original file line number Diff line number Diff line change
@@ -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();
};
}
}
Original file line number Diff line number Diff line change
@@ -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;
}
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -21,63 +11,18 @@
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();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}
Original file line number Diff line number Diff line change
@@ -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;
}
}
Loading

0 comments on commit 552b11b

Please sign in to comment.