From eb477d71c1226a4e51ceb137164f6d25e864da32 Mon Sep 17 00:00:00 2001 From: Mrbysco Date: Wed, 24 Apr 2024 19:38:30 +0200 Subject: [PATCH 01/25] Port to 1.20.5 --- .github/workflows/gradle.yml | 2 +- Fabric/build.gradle | 10 +-- .../client/FabricClientInitializer.java | 6 +- .../fabric/common/FabricModInitializer.java | 8 +++ .../network/FabricMessageOpenBookGui.java | 31 ++------- .../FabricMessageReloadBookContents.java | 17 ++--- Fabric/src/main/resources/fabric.mod.json | 6 +- .../resources/patchouli_fabric.mixins.json | 2 +- Jenkinsfile | 2 +- NeoForge/build.gradle | 6 +- .../client/NeoForgeClientInitializer.java | 22 ++++--- .../common/NeoForgeModInitializer.java | 13 +++- .../common/NeoForgePatchouliConfig.java | 6 +- .../NeoForgeMessageReloadBookContents.java | 28 --------- .../network/NeoForgeNetworkHandler.java | 30 ++++++--- .../handler/NeoForgeClientPayloadHandler.java | 18 +++--- .../neoforge/xplat/NeoForgeXplatImpl.java | 7 +-- .../{mods.toml => neoforge.mods.toml} | 4 +- Xplat/build.gradle | 2 +- .../patchouli/client/book/BookIcon.java | 2 +- .../book/LiquidBlockVertexConsumer.java | 2 +- .../IngredientVariableSerializer.java | 5 +- .../variable/ItemStackVariableSerializer.java | 7 ++- .../TextComponentVariableSerializer.java | 6 +- .../MultiblockVisualizationHandler.java | 7 ++- .../client/jei/PatchouliJeiPlugin.java | 6 +- .../patchouli/common/item/ItemModBook.java | 16 ++--- .../common/item/PatchouliDataComponents.java | 21 +++++++ .../common/recipe/ShapedBookRecipe.java | 35 ++++++----- .../common/recipe/ShapelessBookRecipe.java | 39 ++++++------ .../patchouli/common/util/ItemStackUtil.java | 59 +++++++++--------- .../common/util/SerializationUtil.java | 1 - .../mixin/AccessorComponentSerializer.java | 17 +++++ .../mixin/client/MixinLevelRenderer.java | 4 +- .../patchouli/network/MessageOpenBookGui.java | 20 +++--- .../network/MessageReloadBookContents.java | 27 ++++++++ .../en_us/entries/recipe_mapping/recipe.json | 2 +- .../intro/en_us/categories/one.json | 2 +- .../en_us/entries/not_a_pig.json | 2 +- .../en_us/entries/intro/smelttest.json | 2 +- Xplat/src/main/resources/pack.mcmeta | 2 +- .../resources/patchouli_xplat.mixins.json | 7 ++- build.gradle | 6 +- gradle.properties | 2 +- gradle/wrapper/gradle-wrapper.jar | Bin 59536 -> 62076 bytes gradle/wrapper/gradle-wrapper.properties | 3 +- gradlew | 25 +++++--- gradlew.bat | 15 +++-- settings.gradle | 6 +- 49 files changed, 319 insertions(+), 249 deletions(-) delete mode 100644 NeoForge/src/main/java/vazkii/patchouli/neoforge/network/NeoForgeMessageReloadBookContents.java rename NeoForge/src/main/resources/META-INF/{mods.toml => neoforge.mods.toml} (89%) create mode 100644 Xplat/src/main/java/vazkii/patchouli/common/item/PatchouliDataComponents.java create mode 100644 Xplat/src/main/java/vazkii/patchouli/mixin/AccessorComponentSerializer.java rename NeoForge/src/main/java/vazkii/patchouli/neoforge/network/NeoForgeMessageOpenBookGui.java => Xplat/src/main/java/vazkii/patchouli/network/MessageOpenBookGui.java (56%) create mode 100644 Xplat/src/main/java/vazkii/patchouli/network/MessageReloadBookContents.java diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 3af486f9f..0965479be 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -11,7 +11,7 @@ jobs: uses: actions/setup-java@v2 with: distribution: 'adopt' - java-version: '17' + java-version: '21' - name: Validate gradlew integrity uses: gradle/wrapper-validation-action@v1 - name: Restore cache diff --git a/Fabric/build.gradle b/Fabric/build.gradle index b172490b4..0e8c02dd4 100644 --- a/Fabric/build.gradle +++ b/Fabric/build.gradle @@ -61,15 +61,15 @@ dependencies { minecraft "com.mojang:minecraft:${mc_version}" mappings loom.officialMojangMappings() - modImplementation "net.fabricmc:fabric-loader:0.15.3" + modImplementation "net.fabricmc:fabric-loader:0.15.10" - modImplementation "net.fabricmc.fabric-api:fabric-api:0.92.1+1.20.4" + modImplementation "net.fabricmc.fabric-api:fabric-api:0.97.6+1.20.5" compileOnly project(":Xplat") - modCompileOnly "mezz.jei:jei-1.20.4-common-api:17.0.0.30" + modCompileOnly "mezz.jei:jei-1.20.4-common-api:17.3.0.49" - modCompileOnly("me.shedaniel:RoughlyEnoughItems-api-fabric:14.0.688") { transitive = false } - modCompileOnly("me.shedaniel.cloth:cloth-config-fabric:13.0.121") { transitive = false } + modCompileOnly("me.shedaniel:RoughlyEnoughItems-api-fabric:13.1.713") { transitive = false } + modCompileOnly("me.shedaniel.cloth:cloth-config-fabric:14.0.125") { transitive = false } } compileJava { diff --git a/Fabric/src/main/java/vazkii/patchouli/fabric/client/FabricClientInitializer.java b/Fabric/src/main/java/vazkii/patchouli/fabric/client/FabricClientInitializer.java index 55b650314..dfb412879 100644 --- a/Fabric/src/main/java/vazkii/patchouli/fabric/client/FabricClientInitializer.java +++ b/Fabric/src/main/java/vazkii/patchouli/fabric/client/FabricClientInitializer.java @@ -33,6 +33,8 @@ import vazkii.patchouli.common.item.PatchouliItems; import vazkii.patchouli.fabric.network.FabricMessageOpenBookGui; import vazkii.patchouli.fabric.network.FabricMessageReloadBookContents; +import vazkii.patchouli.network.MessageOpenBookGui; +import vazkii.patchouli.network.MessageReloadBookContents; import org.jetbrains.annotations.Nullable; @@ -50,8 +52,8 @@ public void onInitializeClient() { UseBlockCallback.EVENT.register(MultiblockVisualizationHandler::onPlayerInteract); ClientTickEvents.END_CLIENT_TICK.register(MultiblockVisualizationHandler::onClientTick); HudRenderCallback.EVENT.register(MultiblockVisualizationHandler::onRenderHUD); - ClientPlayNetworking.registerGlobalReceiver(FabricMessageOpenBookGui.ID, FabricMessageOpenBookGui::handle); - ClientPlayNetworking.registerGlobalReceiver(FabricMessageReloadBookContents.ID, FabricMessageReloadBookContents::handle); + ClientPlayNetworking.registerGlobalReceiver(MessageOpenBookGui.TYPE, FabricMessageOpenBookGui::handle); + ClientPlayNetworking.registerGlobalReceiver(MessageReloadBookContents.TYPE, FabricMessageReloadBookContents::handle); ModelLoadingPlugin.register(pluginContext -> { for (Book book : BookRegistry.INSTANCE.books.values()) { diff --git a/Fabric/src/main/java/vazkii/patchouli/fabric/common/FabricModInitializer.java b/Fabric/src/main/java/vazkii/patchouli/fabric/common/FabricModInitializer.java index 7a830a8d6..390dc27a9 100644 --- a/Fabric/src/main/java/vazkii/patchouli/fabric/common/FabricModInitializer.java +++ b/Fabric/src/main/java/vazkii/patchouli/fabric/common/FabricModInitializer.java @@ -5,6 +5,7 @@ import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; import net.fabricmc.fabric.api.event.player.UseBlockCallback; import net.fabricmc.fabric.api.itemgroup.v1.ItemGroupEvents; +import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; import net.minecraft.core.Registry; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.Registries; @@ -18,7 +19,10 @@ import vazkii.patchouli.common.handler.LecternEventHandler; import vazkii.patchouli.common.handler.ReloadContentsHandler; import vazkii.patchouli.common.item.ItemModBook; +import vazkii.patchouli.common.item.PatchouliDataComponents; import vazkii.patchouli.common.item.PatchouliItems; +import vazkii.patchouli.network.MessageOpenBookGui; +import vazkii.patchouli.network.MessageReloadBookContents; public class FabricModInitializer implements ModInitializer { @Override @@ -26,10 +30,14 @@ public void onInitialize() { PatchouliSounds.submitRegistrations((id, e) -> Registry.register(BuiltInRegistries.SOUND_EVENT, id, e)); PatchouliItems.submitItemRegistrations((id, e) -> Registry.register(BuiltInRegistries.ITEM, id, e)); PatchouliItems.submitRecipeSerializerRegistrations((id, e) -> Registry.register(BuiltInRegistries.RECIPE_SERIALIZER, id, e)); + PatchouliDataComponents.submitDataComponentRegistrations((id, e) -> Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, id, e)); FiberPatchouliConfig.setup(); CommandRegistrationCallback.EVENT.register((disp, buildCtx, selection) -> OpenBookCommand.register(disp)); UseBlockCallback.EVENT.register(LecternEventHandler::rightClick); + PayloadTypeRegistry.playS2C().register(MessageOpenBookGui.TYPE, MessageOpenBookGui.CODEC); + PayloadTypeRegistry.playS2C().register(MessageReloadBookContents.TYPE, MessageReloadBookContents.CODEC); + BookRegistry.INSTANCE.init(); ServerLifecycleEvents.END_DATA_PACK_RELOAD.register((server, _r, success) -> { diff --git a/Fabric/src/main/java/vazkii/patchouli/fabric/network/FabricMessageOpenBookGui.java b/Fabric/src/main/java/vazkii/patchouli/fabric/network/FabricMessageOpenBookGui.java index 808fcdde8..8506c2ac9 100644 --- a/Fabric/src/main/java/vazkii/patchouli/fabric/network/FabricMessageOpenBookGui.java +++ b/Fabric/src/main/java/vazkii/patchouli/fabric/network/FabricMessageOpenBookGui.java @@ -1,44 +1,25 @@ package vazkii.patchouli.fabric.network; -import net.fabricmc.fabric.api.networking.v1.PacketSender; +import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; import net.minecraft.client.Minecraft; -import net.minecraft.client.multiplayer.ClientPacketListener; -import net.minecraft.network.FriendlyByteBuf; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerPlayer; -import vazkii.patchouli.api.PatchouliAPI; import vazkii.patchouli.client.book.ClientBookRegistry; +import vazkii.patchouli.network.MessageOpenBookGui; import org.jetbrains.annotations.Nullable; - -import io.netty.buffer.Unpooled; - public class FabricMessageOpenBookGui { - public static final ResourceLocation ID = new ResourceLocation(PatchouliAPI.MOD_ID, "open_book"); public static void send(ServerPlayer player, ResourceLocation book, @Nullable ResourceLocation entry, int page) { - FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer()); - buf.writeResourceLocation(book); - buf.writeUtf(entry == null ? "" : entry.toString()); - buf.writeVarInt(page); - ServerPlayNetworking.send(player, ID, buf); + ServerPlayNetworking.send(player, new MessageOpenBookGui(book, entry, page)); } - public static void handle(Minecraft client, ClientPacketListener handler, FriendlyByteBuf buf, PacketSender responseSender) { - ResourceLocation book = buf.readResourceLocation(); - ResourceLocation entry; - String tmp = buf.readUtf(); - if (tmp.isEmpty()) { - entry = null; - } else { - entry = ResourceLocation.tryParse(tmp); - } - - int page = buf.readVarInt(); - client.submit(() -> ClientBookRegistry.INSTANCE.displayBookGui(book, entry, page)); + public static void handle(MessageOpenBookGui message, ClientPlayNetworking.Context handler) { + Minecraft client = handler.client(); + client.submit(() -> ClientBookRegistry.INSTANCE.displayBookGui(message.book(), message.entry(), message.page())); } } diff --git a/Fabric/src/main/java/vazkii/patchouli/fabric/network/FabricMessageReloadBookContents.java b/Fabric/src/main/java/vazkii/patchouli/fabric/network/FabricMessageReloadBookContents.java index 16b8d63eb..c810c4796 100644 --- a/Fabric/src/main/java/vazkii/patchouli/fabric/network/FabricMessageReloadBookContents.java +++ b/Fabric/src/main/java/vazkii/patchouli/fabric/network/FabricMessageReloadBookContents.java @@ -1,34 +1,27 @@ package vazkii.patchouli.fabric.network; -import net.fabricmc.fabric.api.networking.v1.PacketSender; +import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; import net.fabricmc.fabric.api.networking.v1.PlayerLookup; import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; import net.minecraft.client.Minecraft; -import net.minecraft.client.multiplayer.ClientPacketListener; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerPlayer; -import vazkii.patchouli.api.PatchouliAPI; import vazkii.patchouli.client.book.ClientBookRegistry; - - -import io.netty.buffer.Unpooled; +import vazkii.patchouli.network.MessageReloadBookContents; public class FabricMessageReloadBookContents { - public static final ResourceLocation ID = new ResourceLocation(PatchouliAPI.MOD_ID, "reload_books"); public static void sendToAll(MinecraftServer server) { PlayerLookup.all(server).forEach(FabricMessageReloadBookContents::send); } public static void send(ServerPlayer player) { - FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.EMPTY_BUFFER); - ServerPlayNetworking.send(player, ID, buf); + ServerPlayNetworking.send(player, new MessageReloadBookContents()); } - public static void handle(Minecraft client, ClientPacketListener handler, FriendlyByteBuf buf, PacketSender responseSender) { + public static void handle(MessageReloadBookContents message, ClientPlayNetworking.Context handler) { + Minecraft client = handler.client(); client.submit(() -> ClientBookRegistry.INSTANCE.reload()); } } diff --git a/Fabric/src/main/resources/fabric.mod.json b/Fabric/src/main/resources/fabric.mod.json index 5bb6b8b83..218e2f618 100644 --- a/Fabric/src/main/resources/fabric.mod.json +++ b/Fabric/src/main/resources/fabric.mod.json @@ -35,8 +35,8 @@ ], "depends": { - "fabricloader": ">=0.14.21", - "fabric": ">=0.87.0", - "minecraft": ">=1.20.1 <1.21" + "fabricloader": ">=0.15.10", + "fabric": ">=0.97.6", + "minecraft": ">=1.20.5 <1.21" } } diff --git a/Fabric/src/main/resources/patchouli_fabric.mixins.json b/Fabric/src/main/resources/patchouli_fabric.mixins.json index 292ac1483..6ade76686 100644 --- a/Fabric/src/main/resources/patchouli_fabric.mixins.json +++ b/Fabric/src/main/resources/patchouli_fabric.mixins.json @@ -2,7 +2,7 @@ "required": true, "minVersion": "0.8", "package": "vazkii.patchouli.mixin", - "compatibilityLevel": "JAVA_17", + "compatibilityLevel": "JAVA_21", "mixins": [ ], "client": [ diff --git a/Jenkinsfile b/Jenkinsfile index 098abeceb..a5968e837 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -6,7 +6,7 @@ pipeline { } agent any tools { - jdk "jdk-17.0.1" + jdk "jdk-21.0.2" } stages { stage('Clean') { diff --git a/NeoForge/build.gradle b/NeoForge/build.gradle index a5d8c16cc..588168e7c 100644 --- a/NeoForge/build.gradle +++ b/NeoForge/build.gradle @@ -37,11 +37,11 @@ runs { } dependencies { - implementation "net.neoforged:neoforge:20.4.173" + implementation "net.neoforged:neoforge:20.5.0-beta" implementation project(":Xplat") - compileOnly "mezz.jei:jei-1.20.4-common-api:17.0.0.30" - testCompileOnly "mezz.jei:jei-1.20.4-common-api:17.0.0.30" + compileOnly "mezz.jei:jei-1.20.4-common-api:17.3.0.49" + testCompileOnly "mezz.jei:jei-1.20.4-common-api:17.3.0.49" } TaskCollection.metaClass.excludingNeoTasks = { -> diff --git a/NeoForge/src/main/java/vazkii/patchouli/neoforge/client/NeoForgeClientInitializer.java b/NeoForge/src/main/java/vazkii/patchouli/neoforge/client/NeoForgeClientInitializer.java index e0c0296ed..04f401779 100644 --- a/NeoForge/src/main/java/vazkii/patchouli/neoforge/client/NeoForgeClientInitializer.java +++ b/NeoForge/src/main/java/vazkii/patchouli/neoforge/client/NeoForgeClientInitializer.java @@ -9,10 +9,14 @@ import net.minecraft.world.InteractionResult; import net.neoforged.api.distmarker.Dist; import net.neoforged.bus.api.SubscribeEvent; -import net.neoforged.fml.common.Mod; +import net.neoforged.fml.common.EventBusSubscriber; import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent; -import net.neoforged.neoforge.client.event.*; -import net.neoforged.neoforge.client.gui.overlay.VanillaGuiOverlay; +import net.neoforged.neoforge.client.event.ClientPlayerNetworkEvent; +import net.neoforged.neoforge.client.event.ModelEvent; +import net.neoforged.neoforge.client.event.RegisterClientReloadListenersEvent; +import net.neoforged.neoforge.client.event.RegisterGuiLayersEvent; +import net.neoforged.neoforge.client.event.RenderTooltipEvent; +import net.neoforged.neoforge.client.gui.VanillaGuiLayers; import net.neoforged.neoforge.common.NeoForge; import net.neoforged.neoforge.event.TickEvent; import net.neoforged.neoforge.event.entity.player.PlayerInteractEvent; @@ -36,7 +40,7 @@ import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; -@Mod.EventBusSubscriber(modid = PatchouliAPI.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) +@EventBusSubscriber(modid = PatchouliAPI.MOD_ID, bus = EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) public class NeoForgeClientInitializer { /** * Why are these necessary? @@ -99,12 +103,12 @@ public static void registerReloadListeners(RegisterClientReloadListenersEvent e) } @SubscribeEvent - public static void registerOverlays(RegisterGuiOverlaysEvent evt) { - evt.registerAbove(VanillaGuiOverlay.CROSSHAIR.id(), new ResourceLocation(PatchouliAPI.MOD_ID, "book_overlay"), - (gui, poseStack, partialTick, width, height) -> BookRightClickHandler.onRenderHUD(poseStack, partialTick) + public static void registerOverlays(RegisterGuiLayersEvent evt) { + evt.registerAbove(VanillaGuiLayers.CROSSHAIR, new ResourceLocation(PatchouliAPI.MOD_ID, "book_overlay"), + BookRightClickHandler::onRenderHUD ); - evt.registerBelow(VanillaGuiOverlay.BOSS_EVENT_PROGRESS.id(), new ResourceLocation(PatchouliAPI.MOD_ID, "multiblock_progress"), - (gui, poseStack, partialTick, width, height) -> MultiblockVisualizationHandler.onRenderHUD(poseStack, partialTick) + evt.registerBelow(VanillaGuiLayers.BOSS_OVERLAY, new ResourceLocation(PatchouliAPI.MOD_ID, "multiblock_progress"), + MultiblockVisualizationHandler::onRenderHUD ); } diff --git a/NeoForge/src/main/java/vazkii/patchouli/neoforge/common/NeoForgeModInitializer.java b/NeoForge/src/main/java/vazkii/patchouli/neoforge/common/NeoForgeModInitializer.java index 0379e48e1..719939e5c 100644 --- a/NeoForge/src/main/java/vazkii/patchouli/neoforge/common/NeoForgeModInitializer.java +++ b/NeoForge/src/main/java/vazkii/patchouli/neoforge/common/NeoForgeModInitializer.java @@ -3,8 +3,11 @@ import net.minecraft.core.registries.Registries; import net.minecraft.world.item.CreativeModeTabs; import net.minecraft.world.item.ItemStack; +import net.neoforged.api.distmarker.Dist; import net.neoforged.bus.api.IEventBus; import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.ModContainer; +import net.neoforged.fml.common.EventBusSubscriber; import net.neoforged.fml.common.Mod; import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent; import net.neoforged.neoforge.common.CreativeModeTabRegistry; @@ -22,14 +25,15 @@ import vazkii.patchouli.common.handler.LecternEventHandler; import vazkii.patchouli.common.handler.ReloadContentsHandler; import vazkii.patchouli.common.item.ItemModBook; +import vazkii.patchouli.common.item.PatchouliDataComponents; import vazkii.patchouli.common.item.PatchouliItems; import vazkii.patchouli.neoforge.network.NeoForgeNetworkHandler; -@Mod.EventBusSubscriber(modid = PatchouliAPI.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD) +@EventBusSubscriber(modid = PatchouliAPI.MOD_ID, bus = EventBusSubscriber.Bus.MOD) @Mod(PatchouliAPI.MOD_ID) public class NeoForgeModInitializer { - public NeoForgeModInitializer(IEventBus eventBus) { - NeoForgePatchouliConfig.setup(); + public NeoForgeModInitializer(IEventBus eventBus, Dist dist, ModContainer container) { + NeoForgePatchouliConfig.setup(container); eventBus.addListener(NeoForgeNetworkHandler::setupPackets); } @@ -45,6 +49,9 @@ public static void register(RegisterEvent evt) { evt.register(Registries.RECIPE_SERIALIZER, rh -> { PatchouliItems.submitRecipeSerializerRegistrations(rh::register); }); + evt.register(Registries.DATA_COMPONENT_TYPE, rh -> { + PatchouliDataComponents.submitDataComponentRegistrations(rh::register); + }); } @SubscribeEvent diff --git a/NeoForge/src/main/java/vazkii/patchouli/neoforge/common/NeoForgePatchouliConfig.java b/NeoForge/src/main/java/vazkii/patchouli/neoforge/common/NeoForgePatchouliConfig.java index 66b1f1cff..21be1ca6d 100644 --- a/NeoForge/src/main/java/vazkii/patchouli/neoforge/common/NeoForgePatchouliConfig.java +++ b/NeoForge/src/main/java/vazkii/patchouli/neoforge/common/NeoForgePatchouliConfig.java @@ -1,7 +1,7 @@ package vazkii.patchouli.neoforge.common; import net.minecraft.resources.ResourceLocation; -import net.neoforged.fml.ModLoadingContext; +import net.neoforged.fml.ModContainer; import net.neoforged.fml.config.ModConfig; import net.neoforged.neoforge.common.ModConfigSpec; @@ -55,8 +55,8 @@ public class NeoForgePatchouliConfig { SPEC = builder.build(); } - public static void setup() { - ModLoadingContext.get().registerConfig(ModConfig.Type.CLIENT, SPEC); + public static void setup(ModContainer container) { + container.registerConfig(ModConfig.Type.CLIENT, SPEC); PatchouliConfig.set(new PatchouliConfigAccess() { @Override public boolean disableAdvancementLocking() { diff --git a/NeoForge/src/main/java/vazkii/patchouli/neoforge/network/NeoForgeMessageReloadBookContents.java b/NeoForge/src/main/java/vazkii/patchouli/neoforge/network/NeoForgeMessageReloadBookContents.java deleted file mode 100644 index a9d84a080..000000000 --- a/NeoForge/src/main/java/vazkii/patchouli/neoforge/network/NeoForgeMessageReloadBookContents.java +++ /dev/null @@ -1,28 +0,0 @@ -package vazkii.patchouli.neoforge.network; - -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.network.protocol.common.custom.CustomPacketPayload; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.MinecraftServer; -import net.neoforged.neoforge.network.PacketDistributor; - -import vazkii.patchouli.api.PatchouliAPI; - -public record NeoForgeMessageReloadBookContents() implements CustomPacketPayload { - public static final ResourceLocation ID = new ResourceLocation(PatchouliAPI.MOD_ID, "reload_books"); - - public NeoForgeMessageReloadBookContents(final FriendlyByteBuf packetBuffer) { - this(); - } - - public static void sendToAll(MinecraftServer server) { - PacketDistributor.ALL.noArg().send(new NeoForgeMessageReloadBookContents()); - } - - public void write(FriendlyByteBuf buf) {} - - @Override - public ResourceLocation id() { - return ID; - } -} diff --git a/NeoForge/src/main/java/vazkii/patchouli/neoforge/network/NeoForgeNetworkHandler.java b/NeoForge/src/main/java/vazkii/patchouli/neoforge/network/NeoForgeNetworkHandler.java index d8d2d5b15..55da7bb10 100644 --- a/NeoForge/src/main/java/vazkii/patchouli/neoforge/network/NeoForgeNetworkHandler.java +++ b/NeoForge/src/main/java/vazkii/patchouli/neoforge/network/NeoForgeNetworkHandler.java @@ -1,18 +1,32 @@ package vazkii.patchouli.neoforge.network; -import net.neoforged.neoforge.network.event.RegisterPayloadHandlerEvent; -import net.neoforged.neoforge.network.registration.IPayloadRegistrar; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerPlayer; +import net.neoforged.neoforge.network.PacketDistributor; +import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent; +import net.neoforged.neoforge.network.registration.PayloadRegistrar; import vazkii.patchouli.api.PatchouliAPI; import vazkii.patchouli.neoforge.network.handler.NeoForgeClientPayloadHandler; +import vazkii.patchouli.network.MessageOpenBookGui; +import vazkii.patchouli.network.MessageReloadBookContents; + +import org.jetbrains.annotations.Nullable; public class NeoForgeNetworkHandler { - public static void setupPackets(final RegisterPayloadHandlerEvent event) { - final IPayloadRegistrar registrar = event.registrar(PatchouliAPI.MOD_ID); - registrar.play(NeoForgeMessageOpenBookGui.ID, NeoForgeMessageOpenBookGui::new, handler -> handler - .client(NeoForgeClientPayloadHandler.getInstance()::handleData)); - registrar.play(NeoForgeMessageReloadBookContents.ID, NeoForgeMessageReloadBookContents::new, handler -> handler - .client(NeoForgeClientPayloadHandler.getInstance()::handleData)); + public static void setupPackets(final RegisterPayloadHandlersEvent event) { + final PayloadRegistrar registrar = event.registrar(PatchouliAPI.MOD_ID); + registrar.playToClient(MessageOpenBookGui.TYPE, MessageOpenBookGui.CODEC, NeoForgeClientPayloadHandler.getInstance()::handleData); + registrar.playToClient(MessageReloadBookContents.TYPE, MessageReloadBookContents.CODEC, NeoForgeClientPayloadHandler.getInstance()::handleData); + } + + public static void sendOpenBook(ServerPlayer player, ResourceLocation book, @Nullable ResourceLocation entry, int page) { + player.connection.send(new MessageOpenBookGui(book, entry, page)); + } + + public static void sendReloadBookContents(MinecraftServer server) { + PacketDistributor.sendToAllPlayers(new MessageReloadBookContents()); } } diff --git a/NeoForge/src/main/java/vazkii/patchouli/neoforge/network/handler/NeoForgeClientPayloadHandler.java b/NeoForge/src/main/java/vazkii/patchouli/neoforge/network/handler/NeoForgeClientPayloadHandler.java index e754d2581..e6b572807 100644 --- a/NeoForge/src/main/java/vazkii/patchouli/neoforge/network/handler/NeoForgeClientPayloadHandler.java +++ b/NeoForge/src/main/java/vazkii/patchouli/neoforge/network/handler/NeoForgeClientPayloadHandler.java @@ -1,11 +1,11 @@ package vazkii.patchouli.neoforge.network.handler; import net.minecraft.network.chat.Component; -import net.neoforged.neoforge.network.handling.PlayPayloadContext; +import net.neoforged.neoforge.network.handling.IPayloadContext; import vazkii.patchouli.client.book.ClientBookRegistry; -import vazkii.patchouli.neoforge.network.NeoForgeMessageOpenBookGui; -import vazkii.patchouli.neoforge.network.NeoForgeMessageReloadBookContents; +import vazkii.patchouli.network.MessageOpenBookGui; +import vazkii.patchouli.network.MessageReloadBookContents; public class NeoForgeClientPayloadHandler { private static final NeoForgeClientPayloadHandler INSTANCE = new NeoForgeClientPayloadHandler(); @@ -14,24 +14,24 @@ public static NeoForgeClientPayloadHandler getInstance() { return INSTANCE; } - public void handleData(final NeoForgeMessageOpenBookGui data, final PlayPayloadContext context) { - context.workHandler().submitAsync(() -> { + public void handleData(final MessageOpenBookGui data, final IPayloadContext context) { + context.enqueueWork(() -> { ClientBookRegistry.INSTANCE.displayBookGui(data.book(), data.entry(), data.page()); }) .exceptionally(e -> { // Handle exception - context.packetHandler().disconnect(Component.translatable("patchouli.networking.open_book.failed", e.getMessage())); + context.disconnect(Component.translatable("patchouli.networking.open_book.failed", e.getMessage())); return null; }); } - public void handleData(final NeoForgeMessageReloadBookContents data, final PlayPayloadContext context) { - context.workHandler().submitAsync(() -> { + public void handleData(final MessageReloadBookContents data, final IPayloadContext context) { + context.enqueueWork(() -> { ClientBookRegistry.INSTANCE.reload(); }) .exceptionally(e -> { // Handle exception - context.packetHandler().disconnect(Component.translatable("patchouli.networking.reload_contents.failed", e.getMessage())); + context.disconnect(Component.translatable("patchouli.networking.reload_contents.failed", e.getMessage())); return null; }); } diff --git a/NeoForge/src/main/java/vazkii/patchouli/neoforge/xplat/NeoForgeXplatImpl.java b/NeoForge/src/main/java/vazkii/patchouli/neoforge/xplat/NeoForgeXplatImpl.java index 51e66696b..98a132e0f 100644 --- a/NeoForge/src/main/java/vazkii/patchouli/neoforge/xplat/NeoForgeXplatImpl.java +++ b/NeoForge/src/main/java/vazkii/patchouli/neoforge/xplat/NeoForgeXplatImpl.java @@ -14,8 +14,7 @@ import vazkii.patchouli.api.BookContentsReloadEvent; import vazkii.patchouli.api.BookDrawScreenEvent; import vazkii.patchouli.neoforge.client.NeoForgeClientInitializer; -import vazkii.patchouli.neoforge.network.NeoForgeMessageOpenBookGui; -import vazkii.patchouli.neoforge.network.NeoForgeMessageReloadBookContents; +import vazkii.patchouli.neoforge.network.NeoForgeNetworkHandler; import vazkii.patchouli.xplat.IXplatAbstractions; import vazkii.patchouli.xplat.XplatModContainer; @@ -38,12 +37,12 @@ public void fireBookReload(ResourceLocation book) { @Override public void sendReloadContentsMessage(MinecraftServer server) { - NeoForgeMessageReloadBookContents.sendToAll(server); + NeoForgeNetworkHandler.sendReloadBookContents(server); } @Override public void sendOpenBookGui(ServerPlayer player, ResourceLocation book, @Nullable ResourceLocation entry, int page) { - NeoForgeMessageOpenBookGui.send(player, book, entry, page); + NeoForgeNetworkHandler.sendOpenBook(player, book, entry, page); } @Override diff --git a/NeoForge/src/main/resources/META-INF/mods.toml b/NeoForge/src/main/resources/META-INF/neoforge.mods.toml similarity index 89% rename from NeoForge/src/main/resources/META-INF/mods.toml rename to NeoForge/src/main/resources/META-INF/neoforge.mods.toml index 40f14d437..8494b098e 100644 --- a/NeoForge/src/main/resources/META-INF/mods.toml +++ b/NeoForge/src/main/resources/META-INF/neoforge.mods.toml @@ -16,12 +16,12 @@ Accessible, Data-Driven, Dependency-Free Documentation for Minecraft Modders and [[dependencies.patchouli]] modId="neoforge" type="REQUIRED" -versionRange="[20.4.70-beta,)" +versionRange="[20.5.0-beta,)" [[dependencies.patchouli]] modId="minecraft" type="REQUIRED" -versionRange="[1.20.4,1.21)" +versionRange="[1.20.5,1.21)" [[mixins]] config="patchouli_xplat.mixins.json" \ No newline at end of file diff --git a/Xplat/build.gradle b/Xplat/build.gradle index a2af4b4d1..84db06d51 100644 --- a/Xplat/build.gradle +++ b/Xplat/build.gradle @@ -25,7 +25,7 @@ repositories { dependencies { compileOnly group: 'org.spongepowered', name: 'mixin', version: '0.8.5' - compileOnly "mezz.jei:jei-1.20.4-common-api:17.0.0.30" + compileOnly "mezz.jei:jei-1.20.4-common-api:17.3.0.49" testImplementation 'org.junit.jupiter:junit-jupiter-api:5.6.1' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.6.1' } diff --git a/Xplat/src/main/java/vazkii/patchouli/client/book/BookIcon.java b/Xplat/src/main/java/vazkii/patchouli/client/book/BookIcon.java index f1fd759d9..f9fd73cb9 100644 --- a/Xplat/src/main/java/vazkii/patchouli/client/book/BookIcon.java +++ b/Xplat/src/main/java/vazkii/patchouli/client/book/BookIcon.java @@ -8,7 +8,7 @@ import vazkii.patchouli.api.PatchouliAPI; import vazkii.patchouli.common.util.ItemStackUtil; -public sealed interface BookIcon permits BookIcon.StackIcon,BookIcon.TextureIcon { +public sealed interface BookIcon permits BookIcon.StackIcon, BookIcon.TextureIcon { void render(GuiGraphics graphics, int x, int y); record StackIcon(ItemStack stack) implements BookIcon { diff --git a/Xplat/src/main/java/vazkii/patchouli/client/book/LiquidBlockVertexConsumer.java b/Xplat/src/main/java/vazkii/patchouli/client/book/LiquidBlockVertexConsumer.java index 2e258479d..8b255dbba 100644 --- a/Xplat/src/main/java/vazkii/patchouli/client/book/LiquidBlockVertexConsumer.java +++ b/Xplat/src/main/java/vazkii/patchouli/client/book/LiquidBlockVertexConsumer.java @@ -41,7 +41,7 @@ public VertexConsumer uv2(int u, int v) { @Override public VertexConsumer normal(float x, float y, float z) { - return prior.normal(pose.last().normal(), x, y, z); + return prior.normal(pose.last(), x, y, z); } @Override diff --git a/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/IngredientVariableSerializer.java b/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/IngredientVariableSerializer.java index 75aeb4071..3fc4be9eb 100644 --- a/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/IngredientVariableSerializer.java +++ b/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/IngredientVariableSerializer.java @@ -6,17 +6,16 @@ import net.minecraft.world.item.crafting.Ingredient; import vazkii.patchouli.api.IVariableSerializer; -import vazkii.patchouli.api.PatchouliAPI; import vazkii.patchouli.common.util.ItemStackUtil; public class IngredientVariableSerializer implements IVariableSerializer { @Override public Ingredient fromJson(JsonElement json) { - return (json.isJsonPrimitive()) ? ItemStackUtil.loadIngredientFromString(json.getAsString()) : Ingredient.CODEC.parse(JsonOps.INSTANCE, json).getOrThrow(false, PatchouliAPI.LOGGER::error); + return (json.isJsonPrimitive()) ? ItemStackUtil.loadIngredientFromString(json.getAsString()) : Ingredient.CODEC.parse(JsonOps.INSTANCE, json).result().orElseThrow(); } @Override public JsonElement toJson(Ingredient stack) { - return Ingredient.CODEC.encodeStart(JsonOps.INSTANCE, stack).getOrThrow(false, PatchouliAPI.LOGGER::error); + return Ingredient.CODEC.encodeStart(JsonOps.INSTANCE, stack).result().orElseThrow(); } } diff --git a/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/ItemStackVariableSerializer.java b/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/ItemStackVariableSerializer.java index 31420ce2b..1321ec55a 100644 --- a/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/ItemStackVariableSerializer.java +++ b/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/ItemStackVariableSerializer.java @@ -2,7 +2,9 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import com.mojang.serialization.JsonOps; +import net.minecraft.core.component.DataComponentMap; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.world.item.ItemStack; @@ -32,8 +34,9 @@ public JsonElement toJson(ItemStack stack) { if (stack.getCount() != 1) { ret.addProperty("count", stack.getCount()); } - if (stack.getTag() != null) { - ret.addProperty("nbt", stack.getTag().toString()); + if (!stack.getComponents().isEmpty()) { + DataComponentMap data = stack.getComponents(); + DataComponentMap.CODEC.encodeStart(JsonOps.INSTANCE, data).result().ifPresent(e -> ret.add("nbt", e)); //TODO: Do we want to change the "nbt" key to "components"? } return ret; } diff --git a/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/TextComponentVariableSerializer.java b/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/TextComponentVariableSerializer.java index e55552a0e..ea27908bf 100644 --- a/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/TextComponentVariableSerializer.java +++ b/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/TextComponentVariableSerializer.java @@ -2,10 +2,12 @@ import com.google.gson.JsonElement; +import net.minecraft.core.RegistryAccess; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component.Serializer; import vazkii.patchouli.api.IVariableSerializer; +import vazkii.patchouli.mixin.AccessorComponentSerializer; public class TextComponentVariableSerializer implements IVariableSerializer { @Override @@ -16,11 +18,11 @@ public Component fromJson(JsonElement json) { if (json.isJsonPrimitive() && json.getAsJsonPrimitive().isString()) { return Component.literal(json.getAsString()); } - return Serializer.fromJson(json); + return Serializer.fromJson(json, RegistryAccess.EMPTY); } @Override public JsonElement toJson(Component stack) { - return Serializer.toJsonTree(stack); + return AccessorComponentSerializer.invokeSerialize(stack, RegistryAccess.EMPTY); } } diff --git a/Xplat/src/main/java/vazkii/patchouli/client/handler/MultiblockVisualizationHandler.java b/Xplat/src/main/java/vazkii/patchouli/client/handler/MultiblockVisualizationHandler.java index 5df401fff..30bb8de7f 100644 --- a/Xplat/src/main/java/vazkii/patchouli/client/handler/MultiblockVisualizationHandler.java +++ b/Xplat/src/main/java/vazkii/patchouli/client/handler/MultiblockVisualizationHandler.java @@ -165,9 +165,9 @@ public static void onRenderHUD(GuiGraphics graphics, float partialTicks) { } } - public static void onWorldRenderLast(PoseStack ms) { + public static void onWorldRenderLast(PoseStack ms, Matrix4f pose) { if (hasMultiblock && multiblock != null) { - renderMultiblock(Minecraft.getInstance().level, ms); + renderMultiblock(Minecraft.getInstance().level, ms, pose); } } @@ -198,7 +198,8 @@ public static void onClientTick(Minecraft mc) { } } - public static void renderMultiblock(Level world, PoseStack ms) { + public static void renderMultiblock(Level world, PoseStack ms, Matrix4f pose) { + ms.mulPose(pose); Minecraft mc = Minecraft.getInstance(); if (!isAnchored) { facingRotation = getRotation(mc.player); diff --git a/Xplat/src/main/java/vazkii/patchouli/client/jei/PatchouliJeiPlugin.java b/Xplat/src/main/java/vazkii/patchouli/client/jei/PatchouliJeiPlugin.java index f170e700a..38c7aa921 100644 --- a/Xplat/src/main/java/vazkii/patchouli/client/jei/PatchouliJeiPlugin.java +++ b/Xplat/src/main/java/vazkii/patchouli/client/jei/PatchouliJeiPlugin.java @@ -12,7 +12,7 @@ import net.minecraft.world.item.ItemStack; import vazkii.patchouli.api.PatchouliAPI; -import vazkii.patchouli.common.item.ItemModBook; +import vazkii.patchouli.common.item.PatchouliDataComponents; import vazkii.patchouli.common.item.PatchouliItems; import vazkii.patchouli.mixin.client.AccessorKeyMapping; @@ -46,10 +46,10 @@ public ResourceLocation getPluginUid() { @Override public void registerItemSubtypes(@NotNull ISubtypeRegistration registration) { registration.registerSubtypeInterpreter(VanillaTypes.ITEM_STACK, PatchouliItems.BOOK, (stack, context) -> { - if (!stack.hasTag() || !stack.getTag().contains(ItemModBook.TAG_BOOK)) { + if (!stack.has(PatchouliDataComponents.BOOK)) { return ""; } - return stack.getTag().getString(ItemModBook.TAG_BOOK); + return stack.get(PatchouliDataComponents.BOOK).toString(); }); } diff --git a/Xplat/src/main/java/vazkii/patchouli/common/item/ItemModBook.java b/Xplat/src/main/java/vazkii/patchouli/common/item/ItemModBook.java index f8c9b9741..a5425165d 100644 --- a/Xplat/src/main/java/vazkii/patchouli/common/item/ItemModBook.java +++ b/Xplat/src/main/java/vazkii/patchouli/common/item/ItemModBook.java @@ -2,7 +2,6 @@ import net.minecraft.ChatFormatting; import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerPlayer; @@ -26,8 +25,6 @@ public class ItemModBook extends Item { - public static final String TAG_BOOK = "patchouli:book"; - public ItemModBook() { super(new Item.Properties().stacksTo(1)); } @@ -62,9 +59,7 @@ public static ItemStack forBook(Book book) { public static ItemStack forBook(ResourceLocation book) { ItemStack stack = new ItemStack(PatchouliItems.BOOK); - CompoundTag cmp = new CompoundTag(); - cmp.putString(TAG_BOOK, book.toString()); - stack.setTag(cmp); + stack.set(PatchouliDataComponents.BOOK, book); return stack; } @@ -87,12 +82,11 @@ public static Book getBook(ItemStack stack) { } private static ResourceLocation getBookId(ItemStack stack) { - if (!stack.hasTag() || !stack.getTag().contains(TAG_BOOK)) { + if (!stack.has(PatchouliDataComponents.BOOK)) { return null; } - String bookStr = stack.getTag().getString(TAG_BOOK); - return ResourceLocation.tryParse(bookStr); + return stack.get(PatchouliDataComponents.BOOK); } @Override @@ -106,8 +100,8 @@ public Component getName(ItemStack stack) { } @Override - public void appendHoverText(ItemStack stack, Level worldIn, List tooltip, TooltipFlag flagIn) { - super.appendHoverText(stack, worldIn, tooltip, flagIn); + public void appendHoverText(ItemStack stack, TooltipContext context, List tooltip, TooltipFlag flagIn) { + super.appendHoverText(stack, context, tooltip, flagIn); ResourceLocation rl = getBookId(stack); if (flagIn.isAdvanced()) { diff --git a/Xplat/src/main/java/vazkii/patchouli/common/item/PatchouliDataComponents.java b/Xplat/src/main/java/vazkii/patchouli/common/item/PatchouliDataComponents.java new file mode 100644 index 000000000..9236eff7e --- /dev/null +++ b/Xplat/src/main/java/vazkii/patchouli/common/item/PatchouliDataComponents.java @@ -0,0 +1,21 @@ +package vazkii.patchouli.common.item; + +import net.minecraft.core.component.DataComponentType; +import net.minecraft.resources.ResourceLocation; + +import vazkii.patchouli.api.PatchouliAPI; + +import java.util.function.BiConsumer; + +public class PatchouliDataComponents { + + public static final ResourceLocation COMPONENT_ID = new ResourceLocation(PatchouliAPI.MOD_ID, "book"); + public static final DataComponentType BOOK = DataComponentType.builder() + .persistent(ResourceLocation.CODEC) + .networkSynchronized(ResourceLocation.STREAM_CODEC) + .build(); + + public static void submitDataComponentRegistrations(BiConsumer> consumer) { + consumer.accept(COMPONENT_ID, BOOK); + } +} diff --git a/Xplat/src/main/java/vazkii/patchouli/common/recipe/ShapedBookRecipe.java b/Xplat/src/main/java/vazkii/patchouli/common/recipe/ShapedBookRecipe.java index 36968501b..55b92fbb6 100644 --- a/Xplat/src/main/java/vazkii/patchouli/common/recipe/ShapedBookRecipe.java +++ b/Xplat/src/main/java/vazkii/patchouli/common/recipe/ShapedBookRecipe.java @@ -1,11 +1,12 @@ package vazkii.patchouli.common.recipe; import com.mojang.serialization.Codec; +import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; -import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; import net.minecraft.resources.ResourceLocation; -import net.minecraft.util.ExtraCodecs; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.CraftingBookCategory; import net.minecraft.world.item.crafting.RecipeSerializer; @@ -50,35 +51,41 @@ public RecipeSerializer getSerializer() { } public static class Serializer implements RecipeSerializer { - public static final Codec CODEC = RecordCodecBuilder.create( + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec( instance -> instance.group( - ExtraCodecs.strictOptionalField(Codec.STRING, "group", "").forGetter(bookRecipe -> bookRecipe.group), + Codec.STRING.optionalFieldOf("group", "").forGetter(bookRecipe -> bookRecipe.group), ShapedRecipePattern.MAP_CODEC.forGetter(bookRecipe -> bookRecipe.pattern), - ExtraCodecs.strictOptionalField(ItemStack.ITEM_WITH_COUNT_CODEC, "result", ItemStack.EMPTY).forGetter(bookRecipe -> bookRecipe.result), - ExtraCodecs.strictOptionalField(ResourceLocation.CODEC, "book", null).forGetter(bookRecipe -> bookRecipe.outputBook) + ItemStack.STRICT_CODEC.optionalFieldOf("result", ItemStack.EMPTY).forGetter(bookRecipe -> bookRecipe.result), + ResourceLocation.CODEC.optionalFieldOf("book", null).forGetter(bookRecipe -> bookRecipe.outputBook) ) .apply(instance, ShapedBookRecipe::new) ); + public static final StreamCodec STREAM_CODEC = StreamCodec.of( + ShapedBookRecipe.Serializer::toNetwork, ShapedBookRecipe.Serializer::fromNetwork + ); @Override - public Codec codec() { + public MapCodec codec() { return CODEC; } @Override - public ShapedBookRecipe fromNetwork(FriendlyByteBuf buf) { + public StreamCodec streamCodec() { + return STREAM_CODEC; + } + + private static ShapedBookRecipe fromNetwork(RegistryFriendlyByteBuf buf) { String group = buf.readUtf(); - ShapedRecipePattern recipePattern = ShapedRecipePattern.fromNetwork(buf); - ItemStack result = buf.readItem(); + ShapedRecipePattern recipePattern = ShapedRecipePattern.STREAM_CODEC.decode(buf); + ItemStack result = ItemStack.OPTIONAL_STREAM_CODEC.decode(buf); ResourceLocation outputBook = buf.readBoolean() ? buf.readResourceLocation() : null; return new ShapedBookRecipe(group, recipePattern, result, outputBook); } - @Override - public void toNetwork(FriendlyByteBuf buf, ShapedBookRecipe bookRecipe) { + private static void toNetwork(RegistryFriendlyByteBuf buf, ShapedBookRecipe bookRecipe) { buf.writeUtf(bookRecipe.group); - bookRecipe.pattern.toNetwork(buf); - buf.writeItem(bookRecipe.result); + ShapedRecipePattern.STREAM_CODEC.encode(buf, bookRecipe.pattern); + ItemStack.OPTIONAL_STREAM_CODEC.encode(buf, bookRecipe.result); buf.writeBoolean(bookRecipe.outputBook != null); if (bookRecipe.outputBook != null) { buf.writeResourceLocation(bookRecipe.outputBook); diff --git a/Xplat/src/main/java/vazkii/patchouli/common/recipe/ShapelessBookRecipe.java b/Xplat/src/main/java/vazkii/patchouli/common/recipe/ShapelessBookRecipe.java index 8a3d74340..d7611d53d 100644 --- a/Xplat/src/main/java/vazkii/patchouli/common/recipe/ShapelessBookRecipe.java +++ b/Xplat/src/main/java/vazkii/patchouli/common/recipe/ShapelessBookRecipe.java @@ -2,12 +2,13 @@ import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; +import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; import net.minecraft.core.NonNullList; -import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; import net.minecraft.resources.ResourceLocation; -import net.minecraft.util.ExtraCodecs; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.CraftingBookCategory; import net.minecraft.world.item.crafting.Ingredient; @@ -54,10 +55,10 @@ public RecipeSerializer getSerializer() { public static class Serializer implements RecipeSerializer { static int maxWidth = 3; static int maxHeight = 3; - private static final Codec CODEC = RecordCodecBuilder.create( + private static final MapCodec CODEC = RecordCodecBuilder.mapCodec( instance -> instance.group( - ExtraCodecs.strictOptionalField(Codec.STRING, "group", "").forGetter(bookRecipe -> bookRecipe.group), - ExtraCodecs.strictOptionalField(ItemStack.ITEM_WITH_COUNT_CODEC, "result", ItemStack.EMPTY).forGetter(bookRecipe -> bookRecipe.result), + Codec.STRING.optionalFieldOf("group", "").forGetter(bookRecipe -> bookRecipe.group), + ItemStack.STRICT_CODEC.optionalFieldOf("result", ItemStack.EMPTY).forGetter(bookRecipe -> bookRecipe.result), Ingredient.CODEC_NONEMPTY .listOf() .fieldOf("ingredients") @@ -76,41 +77,43 @@ public static class Serializer implements RecipeSerializer DataResult::success ) .forGetter(bookRecipe -> bookRecipe.ingredients), - ExtraCodecs.strictOptionalField(ResourceLocation.CODEC, "book", null).forGetter(bookRecipe -> bookRecipe.outputBook) + ResourceLocation.CODEC.optionalFieldOf("book", null).forGetter(bookRecipe -> bookRecipe.outputBook) ) .apply(instance, ShapelessBookRecipe::new) ); + public static final StreamCodec STREAM_CODEC = StreamCodec.of( + ShapelessBookRecipe.Serializer::toNetwork, ShapelessBookRecipe.Serializer::fromNetwork + ); @Override - public Codec codec() { + public MapCodec codec() { return CODEC; } @Override - public ShapelessBookRecipe fromNetwork(FriendlyByteBuf buf) { + public StreamCodec streamCodec() { + return STREAM_CODEC; + } + + private static ShapelessBookRecipe fromNetwork(RegistryFriendlyByteBuf buf) { String group = buf.readUtf(); int i = buf.readVarInt(); NonNullList ingredients = NonNullList.withSize(i, Ingredient.EMPTY); - - for (int j = 0; j < ingredients.size(); ++j) { - ingredients.set(j, Ingredient.fromNetwork(buf)); - } - - ItemStack result = buf.readItem(); + ingredients.replaceAll(p_319735_ -> Ingredient.CONTENTS_STREAM_CODEC.decode(buf)); + ItemStack result = ItemStack.OPTIONAL_STREAM_CODEC.decode(buf); ResourceLocation outputBook = buf.readBoolean() ? buf.readResourceLocation() : null; return new ShapelessBookRecipe(group, result, ingredients, outputBook); } - @Override - public void toNetwork(FriendlyByteBuf buf, ShapelessBookRecipe bookRecipe) { + private static void toNetwork(RegistryFriendlyByteBuf buf, ShapelessBookRecipe bookRecipe) { buf.writeUtf(bookRecipe.group); buf.writeVarInt(bookRecipe.ingredients.size()); for (Ingredient ingredient : bookRecipe.ingredients) { - ingredient.toNetwork(buf); + Ingredient.CONTENTS_STREAM_CODEC.encode(buf, ingredient); } - buf.writeItem(bookRecipe.result); + ItemStack.OPTIONAL_STREAM_CODEC.encode(buf, bookRecipe.result); buf.writeBoolean(bookRecipe.outputBook != null); if (bookRecipe.outputBook != null) { buf.writeResourceLocation(bookRecipe.outputBook); diff --git a/Xplat/src/main/java/vazkii/patchouli/common/util/ItemStackUtil.java b/Xplat/src/main/java/vazkii/patchouli/common/util/ItemStackUtil.java index 0233d9acb..8f672b34b 100644 --- a/Xplat/src/main/java/vazkii/patchouli/common/util/ItemStackUtil.java +++ b/Xplat/src/main/java/vazkii/patchouli/common/util/ItemStackUtil.java @@ -4,12 +4,16 @@ import com.google.gson.GsonBuilder; import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import com.mojang.brigadier.StringReader; import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.serialization.JsonOps; +import net.minecraft.commands.arguments.item.ItemParser; +import net.minecraft.core.component.DataComponentMap; +import net.minecraft.core.component.DataComponentPatch; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.Registries; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.TagParser; +import net.minecraft.data.registries.VanillaRegistries; import net.minecraft.resources.ResourceLocation; import net.minecraft.tags.TagKey; import net.minecraft.util.GsonHelper; @@ -26,19 +30,22 @@ import org.jetbrains.annotations.Nullable; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Optional; public final class ItemStackUtil { private static final Gson GSON = new GsonBuilder().create(); private ItemStackUtil() {} - public static Triple parseItemStackString(String res) { - String nbt = ""; - int nbtStart = res.indexOf("{"); - if (nbtStart > 0) { - nbt = res.substring(nbtStart).replaceAll("([^\\\\])'", "$1\"").replaceAll("\\\\'", "'"); - res = res.substring(0, nbtStart); + public static Triple parseItemStackString(String res) { + String components = ""; + int componentsStart = res.indexOf("{"); + if (componentsStart > 0) { + components = res.substring(componentsStart).replaceAll("([^\\\\])'", "$1\"").replaceAll("\\\\'", "'"); + res = res.substring(0, componentsStart); } String[] upper = res.split("#"); @@ -55,23 +62,25 @@ public static Triple parseItemStackStrin ResourceLocation key = new ResourceLocation(tokens[0], tokens[1]); int countn = Integer.parseInt(count); - CompoundTag tag = null; + DataComponentMap.Builder componentMap = DataComponentMap.builder(); - if (!nbt.isEmpty()) { + if (!components.isEmpty()) { + ItemParser parser = new ItemParser(VanillaRegistries.createLookup()); try { - tag = TagParser.parseTag(nbt); + ItemParser.ItemResult result = parser.parse(new StringReader(res.toString() + components)); //TODO: Check if the parsed result is correct + componentMap.addAll(result.components()); } catch (CommandSyntaxException e) { throw new RuntimeException("Failed to parse ItemStack JSON", e); } } - return ImmutableTriple.of(key, countn, tag); + return ImmutableTriple.of(key, countn, componentMap.build()); } - public static ItemStack loadFromParsed(Triple parsed) { + public static ItemStack loadFromParsed(Triple parsed) { var key = parsed.getLeft(); var count = parsed.getMiddle(); - var nbt = parsed.getRight(); + var components = parsed.getRight(); Optional maybeItem = BuiltInRegistries.ITEM.getOptional(key); if (maybeItem.isEmpty()) { throw new RuntimeException("Unknown item ID: " + key); @@ -79,8 +88,8 @@ public static ItemStack loadFromParsed(Triple { + stack.applyComponents(stuff.getFirst()); + }); } return stack; diff --git a/Xplat/src/main/java/vazkii/patchouli/common/util/SerializationUtil.java b/Xplat/src/main/java/vazkii/patchouli/common/util/SerializationUtil.java index 943d2d8fa..fbb7cd5e3 100644 --- a/Xplat/src/main/java/vazkii/patchouli/common/util/SerializationUtil.java +++ b/Xplat/src/main/java/vazkii/patchouli/common/util/SerializationUtil.java @@ -11,7 +11,6 @@ import org.jetbrains.annotations.Nullable; -import java.io.*; import java.util.Locale; public final class SerializationUtil { diff --git a/Xplat/src/main/java/vazkii/patchouli/mixin/AccessorComponentSerializer.java b/Xplat/src/main/java/vazkii/patchouli/mixin/AccessorComponentSerializer.java new file mode 100644 index 000000000..f416e5c7e --- /dev/null +++ b/Xplat/src/main/java/vazkii/patchouli/mixin/AccessorComponentSerializer.java @@ -0,0 +1,17 @@ +package vazkii.patchouli.mixin; + +import com.google.gson.JsonElement; + +import net.minecraft.core.HolderLookup; +import net.minecraft.network.chat.Component; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(Component.Serializer.class) +public interface AccessorComponentSerializer { + @Invoker("serialize") + public static JsonElement invokeSerialize(Component component, HolderLookup.Provider provider) { + throw new AssertionError(); + } +} diff --git a/Xplat/src/main/java/vazkii/patchouli/mixin/client/MixinLevelRenderer.java b/Xplat/src/main/java/vazkii/patchouli/mixin/client/MixinLevelRenderer.java index bc4117992..ec968162b 100644 --- a/Xplat/src/main/java/vazkii/patchouli/mixin/client/MixinLevelRenderer.java +++ b/Xplat/src/main/java/vazkii/patchouli/mixin/client/MixinLevelRenderer.java @@ -18,7 +18,7 @@ @Mixin(LevelRenderer.class) public class MixinLevelRenderer { @Inject(at = @At("RETURN"), method = "renderLevel") - public void onRender(PoseStack matrices, float tickDelta, long limitTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightTexture lightmapTextureManager, Matrix4f matrix4f, CallbackInfo info) { - MultiblockVisualizationHandler.onWorldRenderLast(matrices); + public void onRender(/*PoseStack matrices, */float tickDelta, long limitTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightTexture lightmapTextureManager, Matrix4f pose, Matrix4f matrix4f, CallbackInfo info) { + MultiblockVisualizationHandler.onWorldRenderLast(new PoseStack(), pose); } } diff --git a/NeoForge/src/main/java/vazkii/patchouli/neoforge/network/NeoForgeMessageOpenBookGui.java b/Xplat/src/main/java/vazkii/patchouli/network/MessageOpenBookGui.java similarity index 56% rename from NeoForge/src/main/java/vazkii/patchouli/neoforge/network/NeoForgeMessageOpenBookGui.java rename to Xplat/src/main/java/vazkii/patchouli/network/MessageOpenBookGui.java index 805b06dc6..6a98edb66 100644 --- a/NeoForge/src/main/java/vazkii/patchouli/neoforge/network/NeoForgeMessageOpenBookGui.java +++ b/Xplat/src/main/java/vazkii/patchouli/network/MessageOpenBookGui.java @@ -1,19 +1,23 @@ -package vazkii.patchouli.neoforge.network; +package vazkii.patchouli.network; import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.level.ServerPlayer; import vazkii.patchouli.api.PatchouliAPI; import org.jetbrains.annotations.Nullable; -public record NeoForgeMessageOpenBookGui(ResourceLocation book, @Nullable ResourceLocation entry, int page) implements CustomPacketPayload { +public record MessageOpenBookGui(ResourceLocation book, @Nullable ResourceLocation entry, int page) implements CustomPacketPayload { public static final ResourceLocation ID = new ResourceLocation(PatchouliAPI.MOD_ID, "open_book"); + public static final StreamCodec CODEC = CustomPacketPayload.codec( + MessageOpenBookGui::write, + MessageOpenBookGui::new); + public static final Type TYPE = CustomPacketPayload.createType(ID.toString()); - public NeoForgeMessageOpenBookGui(FriendlyByteBuf buf) { + public MessageOpenBookGui(FriendlyByteBuf buf) { this(buf.readResourceLocation(), getEntry(buf), buf.readVarInt()); } @@ -28,12 +32,8 @@ public void write(FriendlyByteBuf buf) { buf.writeVarInt(page); } - public static void send(ServerPlayer player, ResourceLocation book, @Nullable ResourceLocation entry, int page) { - player.connection.send(new NeoForgeMessageOpenBookGui(book, entry, page)); - } - @Override - public ResourceLocation id() { - return ID; + public Type type() { + return TYPE; } } diff --git a/Xplat/src/main/java/vazkii/patchouli/network/MessageReloadBookContents.java b/Xplat/src/main/java/vazkii/patchouli/network/MessageReloadBookContents.java new file mode 100644 index 000000000..582d3202c --- /dev/null +++ b/Xplat/src/main/java/vazkii/patchouli/network/MessageReloadBookContents.java @@ -0,0 +1,27 @@ +package vazkii.patchouli.network; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.resources.ResourceLocation; + +import vazkii.patchouli.api.PatchouliAPI; + +public record MessageReloadBookContents() implements CustomPacketPayload { + public static final ResourceLocation ID = new ResourceLocation(PatchouliAPI.MOD_ID, "reload_books"); + public static final StreamCodec CODEC = CustomPacketPayload.codec( + MessageReloadBookContents::write, + MessageReloadBookContents::new); + public static final Type TYPE = CustomPacketPayload.createType(ID.toString()); + + public MessageReloadBookContents(final FriendlyByteBuf packetBuffer) { + this(); + } + + public void write(FriendlyByteBuf buf) {} + + @Override + public Type type() { + return TYPE; + } +} diff --git a/Xplat/src/main/resources/assets/patchouli/patchouli_books/comprehensive_test_book/en_us/entries/recipe_mapping/recipe.json b/Xplat/src/main/resources/assets/patchouli/patchouli_books/comprehensive_test_book/en_us/entries/recipe_mapping/recipe.json index c0e844324..8d66b58b2 100644 --- a/Xplat/src/main/resources/assets/patchouli/patchouli_books/comprehensive_test_book/en_us/entries/recipe_mapping/recipe.json +++ b/Xplat/src/main/resources/assets/patchouli/patchouli_books/comprehensive_test_book/en_us/entries/recipe_mapping/recipe.json @@ -14,7 +14,7 @@ }, { "type": "patchouli:blasting", - "recipe": "minecraft:iron_ingot_from_blasting" + "recipe": "minecraft:iron_ingot_from_blasting_iron_ore" }, { "type": "patchouli:smoking", diff --git a/Xplat/src/main/resources/assets/patchouli/patchouli_books/intro/en_us/categories/one.json b/Xplat/src/main/resources/assets/patchouli/patchouli_books/intro/en_us/categories/one.json index 9f9054e42..8ffffed3f 100644 --- a/Xplat/src/main/resources/assets/patchouli/patchouli_books/intro/en_us/categories/one.json +++ b/Xplat/src/main/resources/assets/patchouli/patchouli_books/intro/en_us/categories/one.json @@ -1,6 +1,6 @@ { "name": "Haha yes", "description": "Haha yes", - "icon": "minecraft:grass", + "icon": "minecraft:short_grass", "sortnum": 0 } \ No newline at end of file diff --git a/Xplat/src/main/resources/assets/patchouli/patchouli_books/test_completion/en_us/entries/not_a_pig.json b/Xplat/src/main/resources/assets/patchouli/patchouli_books/test_completion/en_us/entries/not_a_pig.json index e4efaf21d..328a57392 100644 --- a/Xplat/src/main/resources/assets/patchouli/patchouli_books/test_completion/en_us/entries/not_a_pig.json +++ b/Xplat/src/main/resources/assets/patchouli/patchouli_books/test_completion/en_us/entries/not_a_pig.json @@ -1,6 +1,6 @@ { "name": "1 - Pigman?", - "icon": "minecraft:zombie_pigman_spawn_egg", + "icon": "minecraft:zombified_piglin_spawn_egg", "category": "patchouli:regret", "advancement": "patchouli:not_a_pig", "pages": [ diff --git a/Xplat/src/main/resources/assets/patchouli/patchouli_books/testbook1/en_us/entries/intro/smelttest.json b/Xplat/src/main/resources/assets/patchouli/patchouli_books/testbook1/en_us/entries/intro/smelttest.json index 1a4e945ca..7efaa0d26 100644 --- a/Xplat/src/main/resources/assets/patchouli/patchouli_books/testbook1/en_us/entries/intro/smelttest.json +++ b/Xplat/src/main/resources/assets/patchouli/patchouli_books/testbook1/en_us/entries/intro/smelttest.json @@ -9,7 +9,7 @@ "type": "patchouli:smelting", "text": "Haha yes", "recipe": "minecraft:stone", - "recipe2": "minecraft:iron_ingot" + "recipe2": "minecraft:iron_ingot_from_smelting_iron_ore" }, { "type": "patchouli:spotlight", diff --git a/Xplat/src/main/resources/pack.mcmeta b/Xplat/src/main/resources/pack.mcmeta index 4858697ff..ad1f4b3a1 100644 --- a/Xplat/src/main/resources/pack.mcmeta +++ b/Xplat/src/main/resources/pack.mcmeta @@ -1,6 +1,6 @@ { "pack": { "description": "Patchouli Resources", - "pack_format": 8 + "pack_format": 32 } } diff --git a/Xplat/src/main/resources/patchouli_xplat.mixins.json b/Xplat/src/main/resources/patchouli_xplat.mixins.json index 4c8b55445..8e5ce92b9 100644 --- a/Xplat/src/main/resources/patchouli_xplat.mixins.json +++ b/Xplat/src/main/resources/patchouli_xplat.mixins.json @@ -1,11 +1,12 @@ { "required": true, - "minVersion": "0.8", + "minVersion": "0.8.4", "package": "vazkii.patchouli.mixin", - "compatibilityLevel": "JAVA_17", + "compatibilityLevel": "JAVA_21", "mixins": [ "AccessorSmithingTransformRecipe", - "AccessorSmithingTrimRecipe" + "AccessorSmithingTrimRecipe", + "AccessorComponentSerializer" ], "client": [ "client.AccessorClientAdvancements", diff --git a/build.gradle b/build.gradle index 0b2fb63bb..3c8e4b878 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ buildscript { } } dependencies { - classpath "com.diffplug.spotless:spotless-plugin-gradle:5.12.5" + classpath "com.diffplug.spotless:spotless-plugin-gradle:6.23.3" } } @@ -19,7 +19,7 @@ subprojects { apply plugin: 'pmd' apply plugin: "com.diffplug.spotless" apply plugin: 'maven-publish' - java.toolchain.languageVersion = JavaLanguageVersion.of(17) + java.toolchain.languageVersion = JavaLanguageVersion.of(21) java.withSourcesJar() archivesBaseName = "${mod_name}" @@ -34,7 +34,7 @@ subprojects { tasks.withType(JavaCompile).configureEach { it.options.encoding = 'UTF-8' - it.options.release = 17 + it.options.release = 21 } tasks.withType(GenerateModuleMetadata).configureEach { diff --git a/gradle.properties b/gradle.properties index 1688703e1..598b6d189 100644 --- a/gradle.properties +++ b/gradle.properties @@ -7,7 +7,7 @@ org.gradle.jvmargs=-Xmx1G \ --add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED \ --add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED -mc_version=1.20.4 +mc_version=1.20.5 build_number=85 group=vazkii.patchouli mod_name=Patchouli diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 7454180f2ae8848c63b8b4dea2cb829da983f2fa..c1962a79e29d3e0ab67b14947c167a862655af9b 100644 GIT binary patch delta 40133 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/dev/null 2>&1 +then + die "xargs is not available" +fi + # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. diff --git a/gradlew.bat b/gradlew.bat index ac1b06f93..6689b85be 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -14,7 +14,7 @@ @rem limitations under the License. @rem -@if "%DEBUG%" == "" @echo off +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,7 +25,8 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @@ -40,7 +41,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute +if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -75,13 +76,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/settings.gradle b/settings.gradle index 87e94df30..1efa2a5ba 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,9 +1,9 @@ pluginManagement { plugins { - id 'net.neoforged.gradle.userdev' version '7.0.84' apply false + id 'net.neoforged.gradle.userdev' version '7.0.107' apply false id 'org.spongepowered.mixin' version '0.7-SNAPSHOT' apply false id 'org.spongepowered.gradle.vanilla' version '0.2.1-SNAPSHOT' apply false - id 'fabric-loom' version '1.2.7' apply false + id 'fabric-loom' version '1.6-SNAPSHOT' apply false } repositories { maven { @@ -24,7 +24,7 @@ pluginManagement { plugins { // Required for NeoGradle - id 'org.gradle.toolchains.foojay-resolver-convention' version '0.5.0' + id 'org.gradle.toolchains.foojay-resolver-convention' version '0.8.0' } rootProject.name = 'Patchouli' From 7ab23b5ba3117df4b57fdfb30b83a40b3146e5cf Mon Sep 17 00:00:00 2001 From: Mrbysco Date: Wed, 24 Apr 2024 19:48:57 +0200 Subject: [PATCH 02/25] Remove leftover commented out code from the port --- .../java/vazkii/patchouli/mixin/client/MixinLevelRenderer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Xplat/src/main/java/vazkii/patchouli/mixin/client/MixinLevelRenderer.java b/Xplat/src/main/java/vazkii/patchouli/mixin/client/MixinLevelRenderer.java index ec968162b..cad79f02b 100644 --- a/Xplat/src/main/java/vazkii/patchouli/mixin/client/MixinLevelRenderer.java +++ b/Xplat/src/main/java/vazkii/patchouli/mixin/client/MixinLevelRenderer.java @@ -18,7 +18,7 @@ @Mixin(LevelRenderer.class) public class MixinLevelRenderer { @Inject(at = @At("RETURN"), method = "renderLevel") - public void onRender(/*PoseStack matrices, */float tickDelta, long limitTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightTexture lightmapTextureManager, Matrix4f pose, Matrix4f matrix4f, CallbackInfo info) { + public void onRender(float tickDelta, long limitTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightTexture lightmapTextureManager, Matrix4f pose, Matrix4f matrix4f, CallbackInfo info) { MultiblockVisualizationHandler.onWorldRenderLast(new PoseStack(), pose); } } From d8097ec12ddd8c1aba515f11b7ea9a12890a4d88 Mon Sep 17 00:00:00 2001 From: Mrbysco Date: Mon, 29 Apr 2024 21:21:48 +0200 Subject: [PATCH 03/25] Port to 1.20.6 --- Fabric/build.gradle | 6 +++--- Fabric/src/main/resources/fabric.mod.json | 2 +- NeoForge/build.gradle | 2 +- NeoForge/src/main/resources/META-INF/neoforge.mods.toml | 6 +++--- .../main/resources/data/patchouli/advancements/bacon.json | 2 +- .../resources/data/patchouli/advancements/discover_pig.json | 2 +- .../resources/data/patchouli/advancements/kill_chicken.json | 2 +- .../resources/data/patchouli/advancements/mcp_035_0.json | 2 +- .../resources/data/patchouli/advancements/mcp_035_1.json | 2 +- .../resources/data/patchouli/advancements/mcp_035_10.json | 2 +- .../resources/data/patchouli/advancements/mcp_035_11.json | 2 +- .../resources/data/patchouli/advancements/mcp_035_12.json | 2 +- .../resources/data/patchouli/advancements/mcp_035_13.json | 2 +- .../resources/data/patchouli/advancements/mcp_035_14.json | 2 +- .../resources/data/patchouli/advancements/mcp_035_15.json | 2 +- .../resources/data/patchouli/advancements/mcp_035_2.json | 2 +- .../resources/data/patchouli/advancements/mcp_035_3.json | 2 +- .../resources/data/patchouli/advancements/mcp_035_4.json | 2 +- .../resources/data/patchouli/advancements/mcp_035_5.json | 2 +- .../resources/data/patchouli/advancements/mcp_035_6.json | 2 +- .../resources/data/patchouli/advancements/mcp_035_7.json | 2 +- .../resources/data/patchouli/advancements/mcp_035_8.json | 2 +- .../resources/data/patchouli/advancements/mcp_035_9.json | 2 +- .../resources/data/patchouli/advancements/mcp_035_a.json | 2 +- .../resources/data/patchouli/advancements/not_a_pig.json | 2 +- .../main/resources/data/patchouli/advancements/root.json | 2 +- .../resources/data/patchouli/advancements/test_book.json | 2 +- .../main/resources/data/patchouli/advancements/yummy.json | 2 +- .../resources/data/patchouli/advancements/yummy_anyway.json | 2 +- gradle.properties | 2 +- 30 files changed, 34 insertions(+), 34 deletions(-) diff --git a/Fabric/build.gradle b/Fabric/build.gradle index 0e8c02dd4..3315491af 100644 --- a/Fabric/build.gradle +++ b/Fabric/build.gradle @@ -63,13 +63,13 @@ dependencies { mappings loom.officialMojangMappings() modImplementation "net.fabricmc:fabric-loader:0.15.10" - modImplementation "net.fabricmc.fabric-api:fabric-api:0.97.6+1.20.5" + modImplementation "net.fabricmc.fabric-api:fabric-api:0.97.8+1.20.6" compileOnly project(":Xplat") modCompileOnly "mezz.jei:jei-1.20.4-common-api:17.3.0.49" - modCompileOnly("me.shedaniel:RoughlyEnoughItems-api-fabric:13.1.713") { transitive = false } - modCompileOnly("me.shedaniel.cloth:cloth-config-fabric:14.0.125") { transitive = false } + modCompileOnly("me.shedaniel:RoughlyEnoughItems-api-fabric:15.0.728") { transitive = false } + modCompileOnly("me.shedaniel.cloth:cloth-config-fabric:14.0.126") { transitive = false } } compileJava { diff --git a/Fabric/src/main/resources/fabric.mod.json b/Fabric/src/main/resources/fabric.mod.json index 218e2f618..d19ee8dea 100644 --- a/Fabric/src/main/resources/fabric.mod.json +++ b/Fabric/src/main/resources/fabric.mod.json @@ -37,6 +37,6 @@ "depends": { "fabricloader": ">=0.15.10", "fabric": ">=0.97.6", - "minecraft": ">=1.20.5 <1.21" + "minecraft": ">=1.20.6 <1.21" } } diff --git a/NeoForge/build.gradle b/NeoForge/build.gradle index 588168e7c..65623508d 100644 --- a/NeoForge/build.gradle +++ b/NeoForge/build.gradle @@ -37,7 +37,7 @@ runs { } dependencies { - implementation "net.neoforged:neoforge:20.5.0-beta" + implementation "net.neoforged:neoforge:20.6.1-beta" implementation project(":Xplat") compileOnly "mezz.jei:jei-1.20.4-common-api:17.3.0.49" diff --git a/NeoForge/src/main/resources/META-INF/neoforge.mods.toml b/NeoForge/src/main/resources/META-INF/neoforge.mods.toml index 8494b098e..1fc449503 100644 --- a/NeoForge/src/main/resources/META-INF/neoforge.mods.toml +++ b/NeoForge/src/main/resources/META-INF/neoforge.mods.toml @@ -1,6 +1,6 @@ modLoader="javafml" license="CC BY-NC-SA 3.0" -loaderVersion="[2,)" +loaderVersion="[3,)" issueTrackerURL="https://github.com/VazkiiMods/Patchouli" logoFile="logo.png" @@ -16,12 +16,12 @@ Accessible, Data-Driven, Dependency-Free Documentation for Minecraft Modders and [[dependencies.patchouli]] modId="neoforge" type="REQUIRED" -versionRange="[20.5.0-beta,)" +versionRange="[20.6.1-beta,)" [[dependencies.patchouli]] modId="minecraft" type="REQUIRED" -versionRange="[1.20.5,1.21)" +versionRange="[1.20.6,1.21)" [[mixins]] config="patchouli_xplat.mixins.json" \ No newline at end of file diff --git a/Xplat/src/main/resources/data/patchouli/advancements/bacon.json b/Xplat/src/main/resources/data/patchouli/advancements/bacon.json index 3012dbb76..52a9e5987 100644 --- a/Xplat/src/main/resources/data/patchouli/advancements/bacon.json +++ b/Xplat/src/main/resources/data/patchouli/advancements/bacon.json @@ -1,7 +1,7 @@ { "display": { "icon": { - "item": "minecraft:book" + "id": "minecraft:book" }, "title": { "translate": "Bacon time!" diff --git a/Xplat/src/main/resources/data/patchouli/advancements/discover_pig.json b/Xplat/src/main/resources/data/patchouli/advancements/discover_pig.json index f74cb80fc..95bed909f 100644 --- a/Xplat/src/main/resources/data/patchouli/advancements/discover_pig.json +++ b/Xplat/src/main/resources/data/patchouli/advancements/discover_pig.json @@ -1,7 +1,7 @@ { "display": { "icon": { - "item": "minecraft:porkchop" + "id": "minecraft:porkchop" }, "title": { "translate": "Find a Pig" diff --git a/Xplat/src/main/resources/data/patchouli/advancements/kill_chicken.json b/Xplat/src/main/resources/data/patchouli/advancements/kill_chicken.json index c7ed45e7d..da8a247fd 100644 --- a/Xplat/src/main/resources/data/patchouli/advancements/kill_chicken.json +++ b/Xplat/src/main/resources/data/patchouli/advancements/kill_chicken.json @@ -1,7 +1,7 @@ { "display": { "icon": { - "item": "minecraft:feather" + "id": "minecraft:feather" }, "title": { "translate": "Kill Chicken" diff --git a/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_0.json b/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_0.json index 5f3546cb1..2c56b3461 100644 --- a/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_0.json +++ b/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_0.json @@ -1,6 +1,6 @@ { "display": { - "icon": { "item": "minecraft:white_wool" }, + "icon": { "id": "minecraft:white_wool" }, "title": { "translate": "White Wool" }, "description": { "translate": "The MCP Foundation requires you to obtain this." } }, diff --git a/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_1.json b/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_1.json index 0550fbba6..ce775688c 100644 --- a/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_1.json +++ b/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_1.json @@ -1,6 +1,6 @@ { "display": { - "icon": { "item": "minecraft:orange_wool" }, + "icon": { "id": "minecraft:orange_wool" }, "title": { "translate": "Orange Wool" }, "description": { "translate": "The MCP Foundation requires you to obtain this." } }, diff --git a/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_10.json b/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_10.json index d9a97b21a..1d9ae898c 100644 --- a/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_10.json +++ b/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_10.json @@ -1,6 +1,6 @@ { "display": { - "icon": { "item": "minecraft:purple_wool" }, + "icon": { "id": "minecraft:purple_wool" }, "title": { "translate": "Purple Wool" }, "description": { "translate": "The MCP Foundation requires you to obtain this." } }, diff --git a/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_11.json b/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_11.json index e4cd15acf..f72b2b053 100644 --- a/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_11.json +++ b/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_11.json @@ -1,6 +1,6 @@ { "display": { - "icon": { "item": "minecraft:blue_wool" }, + "icon": { "id": "minecraft:blue_wool" }, "title": { "translate": "Blue Wool" }, "description": { "translate": "The MCP Foundation requires you to obtain this." } }, diff --git a/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_12.json b/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_12.json index c8170d7e5..3ba40744d 100644 --- a/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_12.json +++ b/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_12.json @@ -1,6 +1,6 @@ { "display": { - "icon": { "item": "minecraft:brown_wool" }, + "icon": { "id": "minecraft:brown_wool" }, "title": { "translate": "Brown Wool" }, "description": { "translate": "The MCP Foundation requires you to obtain this." } }, diff --git a/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_13.json b/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_13.json index 8cc6572cc..9283af094 100644 --- a/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_13.json +++ b/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_13.json @@ -1,6 +1,6 @@ { "display": { - "icon": { "item": "minecraft:green_wool" }, + "icon": { "id": "minecraft:green_wool" }, "title": { "translate": "Green Wool" }, "description": { "translate": "The MCP Foundation requires you to obtain this." } }, diff --git a/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_14.json b/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_14.json index 85999dc79..8d7b642c8 100644 --- a/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_14.json +++ b/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_14.json @@ -1,6 +1,6 @@ { "display": { - "icon": { "item": "minecraft:red_wool" }, + "icon": { "id": "minecraft:red_wool" }, "title": { "translate": "Red Wool" }, "description": { "translate": "The MCP Foundation requires you to obtain this." } }, diff --git a/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_15.json b/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_15.json index a89e4242c..c570eec93 100644 --- a/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_15.json +++ b/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_15.json @@ -1,6 +1,6 @@ { "display": { - "icon": { "item": "minecraft:black_wool" }, + "icon": { "id": "minecraft:black_wool" }, "title": { "translate": "Black Wool" }, "description": { "translate": "The MCP Foundation requires you to obtain this." } }, diff --git a/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_2.json b/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_2.json index d0658f6a7..ff8c50efd 100644 --- a/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_2.json +++ b/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_2.json @@ -1,6 +1,6 @@ { "display": { - "icon": { "item": "minecraft:magenta_wool" }, + "icon": { "id": "minecraft:magenta_wool" }, "title": { "translate": "Magenta Wool" }, "description": { "translate": "The MCP Foundation requires you to obtain this." } }, diff --git a/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_3.json b/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_3.json index 783ce2ebd..9f0a55cef 100644 --- a/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_3.json +++ b/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_3.json @@ -1,6 +1,6 @@ { "display": { - "icon": { "item": "minecraft:light_blue_wool" }, + "icon": { "id": "minecraft:light_blue_wool" }, "title": { "translate": "Light Blue Wool" }, "description": { "translate": "The MCP Foundation requires you to obtain this." } }, diff --git a/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_4.json b/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_4.json index cf6c2bd75..8ac249f65 100644 --- a/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_4.json +++ b/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_4.json @@ -1,6 +1,6 @@ { "display": { - "icon": { "item": "minecraft:yellow_wool" }, + "icon": { "id": "minecraft:yellow_wool" }, "title": { "translate": "Yellow Wool" }, "description": { "translate": "The MCP Foundation requires you to obtain this." } }, diff --git a/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_5.json b/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_5.json index 49ef13f4a..dfe071a83 100644 --- a/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_5.json +++ b/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_5.json @@ -1,6 +1,6 @@ { "display": { - "icon": { "item": "minecraft:lime_wool" }, + "icon": { "id": "minecraft:lime_wool" }, "title": { "translate": "Lime Wool" }, "description": { "translate": "The MCP Foundation requires you to obtain this." } }, diff --git a/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_6.json b/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_6.json index 1543d77d4..702f59102 100644 --- a/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_6.json +++ b/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_6.json @@ -1,6 +1,6 @@ { "display": { - "icon": { "item": "minecraft:pink_wool" }, + "icon": { "id": "minecraft:pink_wool" }, "title": { "translate": "Pink Wool" }, "description": { "translate": "The MCP Foundation requires you to obtain this." } }, diff --git a/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_7.json b/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_7.json index c04e2a5a7..517d9bf01 100644 --- a/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_7.json +++ b/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_7.json @@ -1,6 +1,6 @@ { "display": { - "icon": { "item": "minecraft:gray_wool" }, + "icon": { "id": "minecraft:gray_wool" }, "title": { "translate": "Gray Wool" }, "description": { "translate": "The MCP Foundation requires you to obtain this." } }, diff --git a/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_8.json b/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_8.json index 96b557753..58f021981 100644 --- a/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_8.json +++ b/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_8.json @@ -1,6 +1,6 @@ { "display": { - "icon": { "item": "minecraft:light_gray_wool" }, + "icon": { "id": "minecraft:light_gray_wool" }, "title": { "translate": "Light Gray Wool" }, "description": { "translate": "The MCP Foundation requires you to obtain this." } }, diff --git a/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_9.json b/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_9.json index 02ec95826..6af521952 100644 --- a/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_9.json +++ b/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_9.json @@ -1,6 +1,6 @@ { "display": { - "icon": { "item": "minecraft:cyan_wool" }, + "icon": { "id": "minecraft:cyan_wool" }, "title": { "translate": "Cyan Wool" }, "description": { "translate": "The MCP Foundation requires you to obtain this." } }, diff --git a/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_a.json b/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_a.json index 0b90e46d6..29030d165 100644 --- a/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_a.json +++ b/Xplat/src/main/resources/data/patchouli/advancements/mcp_035_a.json @@ -1,7 +1,7 @@ { "display": { "icon": { - "item": "minecraft:mutton" + "id": "minecraft:mutton" }, "title": { "translate": "Find a Sheep" diff --git a/Xplat/src/main/resources/data/patchouli/advancements/not_a_pig.json b/Xplat/src/main/resources/data/patchouli/advancements/not_a_pig.json index 57f22a234..6afc21308 100644 --- a/Xplat/src/main/resources/data/patchouli/advancements/not_a_pig.json +++ b/Xplat/src/main/resources/data/patchouli/advancements/not_a_pig.json @@ -1,7 +1,7 @@ { "display": { "icon": { - "item": "minecraft:rotten_flesh" + "id": "minecraft:rotten_flesh" }, "title": { "translate": "That's no pig..." diff --git a/Xplat/src/main/resources/data/patchouli/advancements/root.json b/Xplat/src/main/resources/data/patchouli/advancements/root.json index 6794bbcd6..a77539619 100644 --- a/Xplat/src/main/resources/data/patchouli/advancements/root.json +++ b/Xplat/src/main/resources/data/patchouli/advancements/root.json @@ -1,7 +1,7 @@ { "display": { "icon": { - "item": "minecraft:book" + "id": "minecraft:book" }, "title": { "translate": "Patchouli" diff --git a/Xplat/src/main/resources/data/patchouli/advancements/test_book.json b/Xplat/src/main/resources/data/patchouli/advancements/test_book.json index 3f8d8e191..0f8dbc7be 100644 --- a/Xplat/src/main/resources/data/patchouli/advancements/test_book.json +++ b/Xplat/src/main/resources/data/patchouli/advancements/test_book.json @@ -1,7 +1,7 @@ { "display": { "icon": { - "item": "minecraft:book" + "id": "minecraft:book" }, "title": { "translate": "Test" diff --git a/Xplat/src/main/resources/data/patchouli/advancements/yummy.json b/Xplat/src/main/resources/data/patchouli/advancements/yummy.json index 952628cd5..ef793b164 100644 --- a/Xplat/src/main/resources/data/patchouli/advancements/yummy.json +++ b/Xplat/src/main/resources/data/patchouli/advancements/yummy.json @@ -1,7 +1,7 @@ { "display": { "icon": { - "item": "minecraft:book" + "id": "minecraft:book" }, "title": { "translate": "Yummy!" diff --git a/Xplat/src/main/resources/data/patchouli/advancements/yummy_anyway.json b/Xplat/src/main/resources/data/patchouli/advancements/yummy_anyway.json index d47310e46..5deda5f92 100644 --- a/Xplat/src/main/resources/data/patchouli/advancements/yummy_anyway.json +++ b/Xplat/src/main/resources/data/patchouli/advancements/yummy_anyway.json @@ -1,7 +1,7 @@ { "display": { "icon": { - "item": "minecraft:rotten_flesh" + "id": "minecraft:rotten_flesh" }, "title": { "translate": "Yummy...?" diff --git a/gradle.properties b/gradle.properties index 598b6d189..06288534b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -7,7 +7,7 @@ org.gradle.jvmargs=-Xmx1G \ --add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED \ --add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED -mc_version=1.20.5 +mc_version=1.20.6 build_number=85 group=vazkii.patchouli mod_name=Patchouli From 8228d3cba9b90e7f8cadb8ad8fbdc89b02393359 Mon Sep 17 00:00:00 2001 From: Mrbysco Date: Mon, 29 Apr 2024 21:34:59 +0200 Subject: [PATCH 04/25] Update tick events --- .../client/NeoForgeClientInitializer.java | 26 ++++++++----------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/NeoForge/src/main/java/vazkii/patchouli/neoforge/client/NeoForgeClientInitializer.java b/NeoForge/src/main/java/vazkii/patchouli/neoforge/client/NeoForgeClientInitializer.java index 04f401779..c715e3af7 100644 --- a/NeoForge/src/main/java/vazkii/patchouli/neoforge/client/NeoForgeClientInitializer.java +++ b/NeoForge/src/main/java/vazkii/patchouli/neoforge/client/NeoForgeClientInitializer.java @@ -12,13 +12,14 @@ import net.neoforged.fml.common.EventBusSubscriber; import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent; import net.neoforged.neoforge.client.event.ClientPlayerNetworkEvent; +import net.neoforged.neoforge.client.event.ClientTickEvent; import net.neoforged.neoforge.client.event.ModelEvent; import net.neoforged.neoforge.client.event.RegisterClientReloadListenersEvent; import net.neoforged.neoforge.client.event.RegisterGuiLayersEvent; +import net.neoforged.neoforge.client.event.RenderFrameEvent; import net.neoforged.neoforge.client.event.RenderTooltipEvent; import net.neoforged.neoforge.client.gui.VanillaGuiLayers; import net.neoforged.neoforge.common.NeoForge; -import net.neoforged.neoforge.event.TickEvent; import net.neoforged.neoforge.event.entity.player.PlayerInteractEvent; import vazkii.patchouli.api.PatchouliAPI; @@ -116,10 +117,8 @@ public static void registerOverlays(RegisterGuiLayersEvent evt) { public static void onInitializeClient(FMLClientSetupEvent evt) { ClientBookRegistry.INSTANCE.init(); PersistentData.setup(); - NeoForge.EVENT_BUS.addListener((TickEvent.ClientTickEvent e) -> { - if (e.phase == TickEvent.Phase.END) { - ClientTicker.endClientTick(Minecraft.getInstance()); - } + NeoForge.EVENT_BUS.addListener((ClientTickEvent.Post e) -> { + ClientTicker.endClientTick(Minecraft.getInstance()); }); NeoForge.EVENT_BUS.addListener((PlayerInteractEvent.RightClickBlock e) -> BookRightClickHandler.onRightClick(e.getEntity(), e.getLevel(), e.getHand(), e.getHitVec())); NeoForge.EVENT_BUS.addListener((PlayerInteractEvent.RightClickBlock e) -> { @@ -129,18 +128,15 @@ public static void onInitializeClient(FMLClientSetupEvent evt) { e.setCancellationResult(result); } }); - NeoForge.EVENT_BUS.addListener((TickEvent.ClientTickEvent e) -> { - if (e.phase == TickEvent.Phase.END) { - MultiblockVisualizationHandler.onClientTick(Minecraft.getInstance()); - } + NeoForge.EVENT_BUS.addListener((ClientTickEvent.Post e) -> { + MultiblockVisualizationHandler.onClientTick(Minecraft.getInstance()); }); - NeoForge.EVENT_BUS.addListener((TickEvent.RenderTickEvent e) -> { - if (e.phase == TickEvent.Phase.START) { - ClientTicker.renderTickStart(e.renderTickTime); - } else { - ClientTicker.renderTickEnd(); - } + NeoForge.EVENT_BUS.addListener((RenderFrameEvent.Pre e) -> { + ClientTicker.renderTickStart(e.getPartialTick()); + }); + NeoForge.EVENT_BUS.addListener((RenderFrameEvent.Post e) -> { + ClientTicker.renderTickEnd(); }); NeoForge.EVENT_BUS.addListener((ClientPlayerNetworkEvent.LoggingOut e) -> { From 51df1a36061dbe73c15aab976873c00306af272e Mon Sep 17 00:00:00 2001 From: Mrbysco Date: Thu, 2 May 2024 19:10:26 +0200 Subject: [PATCH 05/25] Update NeoForge --- NeoForge/build.gradle | 2 +- gradle/wrapper/gradle-wrapper.jar | Bin 62076 -> 43462 bytes gradle/wrapper/gradle-wrapper.properties | 3 ++- gradlew | 22 +++++++++++++--------- gradlew.bat | 20 ++++++++++---------- settings.gradle | 2 +- 6 files changed, 27 insertions(+), 22 deletions(-) diff --git a/NeoForge/build.gradle b/NeoForge/build.gradle index 65623508d..6b63a63b9 100644 --- a/NeoForge/build.gradle +++ b/NeoForge/build.gradle @@ -37,7 +37,7 @@ runs { } dependencies { - implementation "net.neoforged:neoforge:20.6.1-beta" + implementation "net.neoforged:neoforge:20.6.18-beta" implementation project(":Xplat") compileOnly "mezz.jei:jei-1.20.4-common-api:17.3.0.49" diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index c1962a79e29d3e0ab67b14947c167a862655af9b..d64cd4917707c1f8861d8cb53dd15194d4248596 100644 GIT binary patch literal 43462 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 literal 62076 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 509c4a29b..b82aa23a4 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index aeb74cbb4..1aa94a426 100755 --- a/gradlew +++ b/gradlew @@ -83,7 +83,8 @@ done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -130,10 +131,13 @@ location of your Java installation." fi else JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. @@ -141,7 +145,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac @@ -149,7 +153,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -198,11 +202,11 @@ fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ diff --git a/gradlew.bat b/gradlew.bat index 6689b85be..7101f8e46 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -43,11 +43,11 @@ set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -57,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail diff --git a/settings.gradle b/settings.gradle index 1efa2a5ba..51a54230a 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,6 +1,6 @@ pluginManagement { plugins { - id 'net.neoforged.gradle.userdev' version '7.0.107' apply false + id 'net.neoforged.gradle.userdev' version '7.0.119' apply false id 'org.spongepowered.mixin' version '0.7-SNAPSHOT' apply false id 'org.spongepowered.gradle.vanilla' version '0.2.1-SNAPSHOT' apply false id 'fabric-loom' version '1.6-SNAPSHOT' apply false From e7af05688d92c6065caebeff17cb794eadc498a4 Mon Sep 17 00:00:00 2001 From: Mrbysco Date: Sat, 4 May 2024 00:07:58 +0200 Subject: [PATCH 06/25] Remove custom book recipe You can specify components in vanilla results now --- .../fabric/common/FabricModInitializer.java | 1 - .../common/NeoForgeModInitializer.java | 3 - .../TextComponentVariableSerializer.java | 6 +- .../patchouli/common/item/PatchouliItems.java | 8 -- .../common/recipe/ShapedBookRecipe.java | 95 -------------- .../common/recipe/ShapelessBookRecipe.java | 123 ------------------ 6 files changed, 4 insertions(+), 232 deletions(-) delete mode 100644 Xplat/src/main/java/vazkii/patchouli/common/recipe/ShapedBookRecipe.java delete mode 100644 Xplat/src/main/java/vazkii/patchouli/common/recipe/ShapelessBookRecipe.java diff --git a/Fabric/src/main/java/vazkii/patchouli/fabric/common/FabricModInitializer.java b/Fabric/src/main/java/vazkii/patchouli/fabric/common/FabricModInitializer.java index 390dc27a9..27f077b9e 100644 --- a/Fabric/src/main/java/vazkii/patchouli/fabric/common/FabricModInitializer.java +++ b/Fabric/src/main/java/vazkii/patchouli/fabric/common/FabricModInitializer.java @@ -29,7 +29,6 @@ public class FabricModInitializer implements ModInitializer { public void onInitialize() { PatchouliSounds.submitRegistrations((id, e) -> Registry.register(BuiltInRegistries.SOUND_EVENT, id, e)); PatchouliItems.submitItemRegistrations((id, e) -> Registry.register(BuiltInRegistries.ITEM, id, e)); - PatchouliItems.submitRecipeSerializerRegistrations((id, e) -> Registry.register(BuiltInRegistries.RECIPE_SERIALIZER, id, e)); PatchouliDataComponents.submitDataComponentRegistrations((id, e) -> Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, id, e)); FiberPatchouliConfig.setup(); CommandRegistrationCallback.EVENT.register((disp, buildCtx, selection) -> OpenBookCommand.register(disp)); diff --git a/NeoForge/src/main/java/vazkii/patchouli/neoforge/common/NeoForgeModInitializer.java b/NeoForge/src/main/java/vazkii/patchouli/neoforge/common/NeoForgeModInitializer.java index 719939e5c..3b060ca47 100644 --- a/NeoForge/src/main/java/vazkii/patchouli/neoforge/common/NeoForgeModInitializer.java +++ b/NeoForge/src/main/java/vazkii/patchouli/neoforge/common/NeoForgeModInitializer.java @@ -46,9 +46,6 @@ public static void register(RegisterEvent evt) { evt.register(Registries.ITEM, rh -> { PatchouliItems.submitItemRegistrations(rh::register); }); - evt.register(Registries.RECIPE_SERIALIZER, rh -> { - PatchouliItems.submitRecipeSerializerRegistrations(rh::register); - }); evt.register(Registries.DATA_COMPONENT_TYPE, rh -> { PatchouliDataComponents.submitDataComponentRegistrations(rh::register); }); diff --git a/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/TextComponentVariableSerializer.java b/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/TextComponentVariableSerializer.java index ea27908bf..fa2ab383e 100644 --- a/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/TextComponentVariableSerializer.java +++ b/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/TextComponentVariableSerializer.java @@ -1,13 +1,15 @@ package vazkii.patchouli.client.book.template.variable; import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; +import com.mojang.serialization.JsonOps; import net.minecraft.core.RegistryAccess; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component.Serializer; +import net.minecraft.network.chat.ComponentSerialization; import vazkii.patchouli.api.IVariableSerializer; -import vazkii.patchouli.mixin.AccessorComponentSerializer; public class TextComponentVariableSerializer implements IVariableSerializer { @Override @@ -23,6 +25,6 @@ public Component fromJson(JsonElement json) { @Override public JsonElement toJson(Component stack) { - return AccessorComponentSerializer.invokeSerialize(stack, RegistryAccess.EMPTY); + return ComponentSerialization.CODEC.encodeStart(RegistryAccess.EMPTY.createSerializationContext(JsonOps.INSTANCE), stack).getOrThrow(JsonParseException::new); } } diff --git a/Xplat/src/main/java/vazkii/patchouli/common/item/PatchouliItems.java b/Xplat/src/main/java/vazkii/patchouli/common/item/PatchouliItems.java index 0eb57e670..a469d6a58 100644 --- a/Xplat/src/main/java/vazkii/patchouli/common/item/PatchouliItems.java +++ b/Xplat/src/main/java/vazkii/patchouli/common/item/PatchouliItems.java @@ -2,11 +2,8 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.Item; -import net.minecraft.world.item.crafting.RecipeSerializer; import vazkii.patchouli.api.PatchouliAPI; -import vazkii.patchouli.common.recipe.ShapedBookRecipe; -import vazkii.patchouli.common.recipe.ShapelessBookRecipe; import java.util.function.BiConsumer; @@ -18,9 +15,4 @@ public class PatchouliItems { public static void submitItemRegistrations(BiConsumer consumer) { consumer.accept(BOOK_ID, BOOK); } - - public static void submitRecipeSerializerRegistrations(BiConsumer> consumer) { - consumer.accept(new ResourceLocation(PatchouliAPI.MOD_ID, "shaped_book_recipe"), ShapedBookRecipe.SERIALIZER); - consumer.accept(new ResourceLocation(PatchouliAPI.MOD_ID, "shapeless_book_recipe"), ShapelessBookRecipe.SERIALIZER); - } } diff --git a/Xplat/src/main/java/vazkii/patchouli/common/recipe/ShapedBookRecipe.java b/Xplat/src/main/java/vazkii/patchouli/common/recipe/ShapedBookRecipe.java deleted file mode 100644 index 55b92fbb6..000000000 --- a/Xplat/src/main/java/vazkii/patchouli/common/recipe/ShapedBookRecipe.java +++ /dev/null @@ -1,95 +0,0 @@ -package vazkii.patchouli.common.recipe; - -import com.mojang.serialization.Codec; -import com.mojang.serialization.MapCodec; -import com.mojang.serialization.codecs.RecordCodecBuilder; - -import net.minecraft.network.RegistryFriendlyByteBuf; -import net.minecraft.network.codec.StreamCodec; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.crafting.CraftingBookCategory; -import net.minecraft.world.item.crafting.RecipeSerializer; -import net.minecraft.world.item.crafting.ShapedRecipe; -import net.minecraft.world.item.crafting.ShapedRecipePattern; - -import vazkii.patchouli.api.PatchouliAPI; - -import org.jetbrains.annotations.Nullable; - -/** - * Recipe type for shaped book recipes. - * The format is the same as vanilla shaped recipes, but the - * "result" object is replaced by a "book" string for the book ID. - */ -public class ShapedBookRecipe extends ShapedRecipe { - public static final RecipeSerializer SERIALIZER = new Serializer(); - - final ShapedRecipePattern pattern; - final ItemStack result; - final String group; - final @Nullable ResourceLocation outputBook; - - public ShapedBookRecipe(String group, ShapedRecipePattern recipePattern, ItemStack result, @Nullable ResourceLocation outputBook) { - super(group, CraftingBookCategory.MISC, recipePattern, getOutputBook(result, outputBook)); - this.pattern = recipePattern; - this.result = result; - this.group = group; - this.outputBook = outputBook; - } - - private static ItemStack getOutputBook(ItemStack result, @Nullable ResourceLocation outputBook) { - if (outputBook != null) { - return PatchouliAPI.get().getBookStack(outputBook); - } - return result; - } - - @Override - public RecipeSerializer getSerializer() { - return SERIALIZER; - } - - public static class Serializer implements RecipeSerializer { - public static final MapCodec CODEC = RecordCodecBuilder.mapCodec( - instance -> instance.group( - Codec.STRING.optionalFieldOf("group", "").forGetter(bookRecipe -> bookRecipe.group), - ShapedRecipePattern.MAP_CODEC.forGetter(bookRecipe -> bookRecipe.pattern), - ItemStack.STRICT_CODEC.optionalFieldOf("result", ItemStack.EMPTY).forGetter(bookRecipe -> bookRecipe.result), - ResourceLocation.CODEC.optionalFieldOf("book", null).forGetter(bookRecipe -> bookRecipe.outputBook) - ) - .apply(instance, ShapedBookRecipe::new) - ); - public static final StreamCodec STREAM_CODEC = StreamCodec.of( - ShapedBookRecipe.Serializer::toNetwork, ShapedBookRecipe.Serializer::fromNetwork - ); - - @Override - public MapCodec codec() { - return CODEC; - } - - @Override - public StreamCodec streamCodec() { - return STREAM_CODEC; - } - - private static ShapedBookRecipe fromNetwork(RegistryFriendlyByteBuf buf) { - String group = buf.readUtf(); - ShapedRecipePattern recipePattern = ShapedRecipePattern.STREAM_CODEC.decode(buf); - ItemStack result = ItemStack.OPTIONAL_STREAM_CODEC.decode(buf); - ResourceLocation outputBook = buf.readBoolean() ? buf.readResourceLocation() : null; - return new ShapedBookRecipe(group, recipePattern, result, outputBook); - } - - private static void toNetwork(RegistryFriendlyByteBuf buf, ShapedBookRecipe bookRecipe) { - buf.writeUtf(bookRecipe.group); - ShapedRecipePattern.STREAM_CODEC.encode(buf, bookRecipe.pattern); - ItemStack.OPTIONAL_STREAM_CODEC.encode(buf, bookRecipe.result); - buf.writeBoolean(bookRecipe.outputBook != null); - if (bookRecipe.outputBook != null) { - buf.writeResourceLocation(bookRecipe.outputBook); - } - } - } -} diff --git a/Xplat/src/main/java/vazkii/patchouli/common/recipe/ShapelessBookRecipe.java b/Xplat/src/main/java/vazkii/patchouli/common/recipe/ShapelessBookRecipe.java deleted file mode 100644 index d7611d53d..000000000 --- a/Xplat/src/main/java/vazkii/patchouli/common/recipe/ShapelessBookRecipe.java +++ /dev/null @@ -1,123 +0,0 @@ -package vazkii.patchouli.common.recipe; - -import com.mojang.serialization.Codec; -import com.mojang.serialization.DataResult; -import com.mojang.serialization.MapCodec; -import com.mojang.serialization.codecs.RecordCodecBuilder; - -import net.minecraft.core.NonNullList; -import net.minecraft.network.RegistryFriendlyByteBuf; -import net.minecraft.network.codec.StreamCodec; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.crafting.CraftingBookCategory; -import net.minecraft.world.item.crafting.Ingredient; -import net.minecraft.world.item.crafting.RecipeSerializer; -import net.minecraft.world.item.crafting.ShapelessRecipe; - -import vazkii.patchouli.api.PatchouliAPI; - -import org.jetbrains.annotations.Nullable; - -/** - * Recipe type for shapeless book recipes. - * The format is the same as vanilla shapeless recipes, but the - * "result" object is replaced by a "book" string for the book ID. - */ -public class ShapelessBookRecipe extends ShapelessRecipe { - public static final RecipeSerializer SERIALIZER = new Serializer(); - - final String group; - final ItemStack result; - final NonNullList ingredients; - final @Nullable ResourceLocation outputBook; - - public ShapelessBookRecipe(String group, ItemStack result, NonNullList ingredients, @Nullable ResourceLocation outputBook) { - super(group, CraftingBookCategory.MISC, getOutputBook(result, outputBook), ingredients); - this.group = group; - this.result = result; - this.ingredients = ingredients; - this.outputBook = outputBook; - } - - private static ItemStack getOutputBook(ItemStack result, @Nullable ResourceLocation outputBook) { - if (outputBook != null) { - return PatchouliAPI.get().getBookStack(outputBook); - } - return result; - } - - @Override - public RecipeSerializer getSerializer() { - return SERIALIZER; - } - - public static class Serializer implements RecipeSerializer { - static int maxWidth = 3; - static int maxHeight = 3; - private static final MapCodec CODEC = RecordCodecBuilder.mapCodec( - instance -> instance.group( - Codec.STRING.optionalFieldOf("group", "").forGetter(bookRecipe -> bookRecipe.group), - ItemStack.STRICT_CODEC.optionalFieldOf("result", ItemStack.EMPTY).forGetter(bookRecipe -> bookRecipe.result), - Ingredient.CODEC_NONEMPTY - .listOf() - .fieldOf("ingredients") - .flatXmap( - ingredientList -> { - Ingredient[] aingredient = ingredientList - .toArray(Ingredient[]::new); - if (aingredient.length == 0) { - return DataResult.error(() -> "No ingredients for shapeless book recipe"); - } else { - return aingredient.length > maxHeight * maxWidth - ? DataResult.error(() -> "Too many ingredients for shapeless book recipe. The maximum is: %s".formatted(maxHeight * maxWidth)) - : DataResult.success(NonNullList.of(Ingredient.EMPTY, aingredient)); - } - }, - DataResult::success - ) - .forGetter(bookRecipe -> bookRecipe.ingredients), - ResourceLocation.CODEC.optionalFieldOf("book", null).forGetter(bookRecipe -> bookRecipe.outputBook) - ) - .apply(instance, ShapelessBookRecipe::new) - ); - public static final StreamCodec STREAM_CODEC = StreamCodec.of( - ShapelessBookRecipe.Serializer::toNetwork, ShapelessBookRecipe.Serializer::fromNetwork - ); - - @Override - public MapCodec codec() { - return CODEC; - } - - @Override - public StreamCodec streamCodec() { - return STREAM_CODEC; - } - - private static ShapelessBookRecipe fromNetwork(RegistryFriendlyByteBuf buf) { - String group = buf.readUtf(); - int i = buf.readVarInt(); - NonNullList ingredients = NonNullList.withSize(i, Ingredient.EMPTY); - ingredients.replaceAll(p_319735_ -> Ingredient.CONTENTS_STREAM_CODEC.decode(buf)); - ItemStack result = ItemStack.OPTIONAL_STREAM_CODEC.decode(buf); - ResourceLocation outputBook = buf.readBoolean() ? buf.readResourceLocation() : null; - return new ShapelessBookRecipe(group, result, ingredients, outputBook); - } - - private static void toNetwork(RegistryFriendlyByteBuf buf, ShapelessBookRecipe bookRecipe) { - buf.writeUtf(bookRecipe.group); - buf.writeVarInt(bookRecipe.ingredients.size()); - - for (Ingredient ingredient : bookRecipe.ingredients) { - Ingredient.CONTENTS_STREAM_CODEC.encode(buf, ingredient); - } - - ItemStack.OPTIONAL_STREAM_CODEC.encode(buf, bookRecipe.result); - buf.writeBoolean(bookRecipe.outputBook != null); - if (bookRecipe.outputBook != null) { - buf.writeResourceLocation(bookRecipe.outputBook); - } - } - } -} From 5094036b913f996a7d0366d88551e93045a1e7da Mon Sep 17 00:00:00 2001 From: Mrbysco Date: Sat, 4 May 2024 14:25:28 +0200 Subject: [PATCH 07/25] Remove Accessor --- .../mixin/AccessorComponentSerializer.java | 17 ----------------- .../main/resources/patchouli_xplat.mixins.json | 3 +-- 2 files changed, 1 insertion(+), 19 deletions(-) delete mode 100644 Xplat/src/main/java/vazkii/patchouli/mixin/AccessorComponentSerializer.java diff --git a/Xplat/src/main/java/vazkii/patchouli/mixin/AccessorComponentSerializer.java b/Xplat/src/main/java/vazkii/patchouli/mixin/AccessorComponentSerializer.java deleted file mode 100644 index f416e5c7e..000000000 --- a/Xplat/src/main/java/vazkii/patchouli/mixin/AccessorComponentSerializer.java +++ /dev/null @@ -1,17 +0,0 @@ -package vazkii.patchouli.mixin; - -import com.google.gson.JsonElement; - -import net.minecraft.core.HolderLookup; -import net.minecraft.network.chat.Component; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Invoker; - -@Mixin(Component.Serializer.class) -public interface AccessorComponentSerializer { - @Invoker("serialize") - public static JsonElement invokeSerialize(Component component, HolderLookup.Provider provider) { - throw new AssertionError(); - } -} diff --git a/Xplat/src/main/resources/patchouli_xplat.mixins.json b/Xplat/src/main/resources/patchouli_xplat.mixins.json index 8e5ce92b9..869b44658 100644 --- a/Xplat/src/main/resources/patchouli_xplat.mixins.json +++ b/Xplat/src/main/resources/patchouli_xplat.mixins.json @@ -5,8 +5,7 @@ "compatibilityLevel": "JAVA_21", "mixins": [ "AccessorSmithingTransformRecipe", - "AccessorSmithingTrimRecipe", - "AccessorComponentSerializer" + "AccessorSmithingTrimRecipe" ], "client": [ "client.AccessorClientAdvancements", From 3748c191b1239dfeda4576e287d7afbf34cd3432 Mon Sep 17 00:00:00 2001 From: Mrbysco Date: Mon, 6 May 2024 20:15:37 +0200 Subject: [PATCH 08/25] Register DataComponent before items --- .../patchouli/fabric/common/FabricModInitializer.java | 2 +- .../patchouli/neoforge/common/NeoForgeModInitializer.java | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Fabric/src/main/java/vazkii/patchouli/fabric/common/FabricModInitializer.java b/Fabric/src/main/java/vazkii/patchouli/fabric/common/FabricModInitializer.java index 27f077b9e..8b8194133 100644 --- a/Fabric/src/main/java/vazkii/patchouli/fabric/common/FabricModInitializer.java +++ b/Fabric/src/main/java/vazkii/patchouli/fabric/common/FabricModInitializer.java @@ -28,8 +28,8 @@ public class FabricModInitializer implements ModInitializer { @Override public void onInitialize() { PatchouliSounds.submitRegistrations((id, e) -> Registry.register(BuiltInRegistries.SOUND_EVENT, id, e)); - PatchouliItems.submitItemRegistrations((id, e) -> Registry.register(BuiltInRegistries.ITEM, id, e)); PatchouliDataComponents.submitDataComponentRegistrations((id, e) -> Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, id, e)); + PatchouliItems.submitItemRegistrations((id, e) -> Registry.register(BuiltInRegistries.ITEM, id, e)); FiberPatchouliConfig.setup(); CommandRegistrationCallback.EVENT.register((disp, buildCtx, selection) -> OpenBookCommand.register(disp)); UseBlockCallback.EVENT.register(LecternEventHandler::rightClick); diff --git a/NeoForge/src/main/java/vazkii/patchouli/neoforge/common/NeoForgeModInitializer.java b/NeoForge/src/main/java/vazkii/patchouli/neoforge/common/NeoForgeModInitializer.java index 3b060ca47..70a4967b9 100644 --- a/NeoForge/src/main/java/vazkii/patchouli/neoforge/common/NeoForgeModInitializer.java +++ b/NeoForge/src/main/java/vazkii/patchouli/neoforge/common/NeoForgeModInitializer.java @@ -43,12 +43,12 @@ public static void register(RegisterEvent evt) { evt.register(Registries.SOUND_EVENT, rh -> { PatchouliSounds.submitRegistrations(rh::register); }); - evt.register(Registries.ITEM, rh -> { - PatchouliItems.submitItemRegistrations(rh::register); - }); evt.register(Registries.DATA_COMPONENT_TYPE, rh -> { PatchouliDataComponents.submitDataComponentRegistrations(rh::register); }); + evt.register(Registries.ITEM, rh -> { + PatchouliItems.submitItemRegistrations(rh::register); + }); } @SubscribeEvent From 0b43ba4482240bfcaf2e351c6078c3a030a8c10d Mon Sep 17 00:00:00 2001 From: Mrbysco Date: Mon, 6 May 2024 20:15:53 +0200 Subject: [PATCH 09/25] Fix test recipes --- .../resources/data/patchouli/recipes/test_recipe.json | 10 ++++++++-- .../data/patchouli/recipes/test_recipe_shapeless.json | 10 ++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/Xplat/src/main/resources/data/patchouli/recipes/test_recipe.json b/Xplat/src/main/resources/data/patchouli/recipes/test_recipe.json index de920251a..e30abab17 100644 --- a/Xplat/src/main/resources/data/patchouli/recipes/test_recipe.json +++ b/Xplat/src/main/resources/data/patchouli/recipes/test_recipe.json @@ -1,5 +1,5 @@ { - "type": "patchouli:shaped_book_recipe", + "type": "minecraft:crafting_shaped", "pattern": [ "##" ], @@ -8,5 +8,11 @@ "item": "minecraft:dirt" } }, - "book": "patchouli:comprehensive_test_book" + "result": { + "components": { + "patchouli:book": "patchouli:comprehensive_test_book" + }, + "count": 1, + "id": "patchouli:guide_book" + } } \ No newline at end of file diff --git a/Xplat/src/main/resources/data/patchouli/recipes/test_recipe_shapeless.json b/Xplat/src/main/resources/data/patchouli/recipes/test_recipe_shapeless.json index 7128a1ef5..57e1793d8 100644 --- a/Xplat/src/main/resources/data/patchouli/recipes/test_recipe_shapeless.json +++ b/Xplat/src/main/resources/data/patchouli/recipes/test_recipe_shapeless.json @@ -1,5 +1,5 @@ { - "type": "patchouli:shapeless_book_recipe", + "type": "minecraft:crafting_shapeless", "ingredients": [ { "item": "minecraft:gold_ingot" @@ -8,5 +8,11 @@ "item": "minecraft:dirt" } ], - "book": "patchouli:testbook1" + "result": { + "components": { + "patchouli:book": "patchouli:testbook1" + }, + "count": 1, + "id": "patchouli:guide_book" + } } \ No newline at end of file From 7c99926be9781d7ce07597cecb97430163cfedbe Mon Sep 17 00:00:00 2001 From: Mrbysco Date: Wed, 22 May 2024 16:20:27 +0200 Subject: [PATCH 10/25] Update neoforge --- NeoForge/build.gradle | 2 +- settings.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/NeoForge/build.gradle b/NeoForge/build.gradle index 6b63a63b9..9f79daf9e 100644 --- a/NeoForge/build.gradle +++ b/NeoForge/build.gradle @@ -37,7 +37,7 @@ runs { } dependencies { - implementation "net.neoforged:neoforge:20.6.18-beta" + implementation "net.neoforged:neoforge:20.6.74-beta" implementation project(":Xplat") compileOnly "mezz.jei:jei-1.20.4-common-api:17.3.0.49" diff --git a/settings.gradle b/settings.gradle index 51a54230a..4692c24e1 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,6 +1,6 @@ pluginManagement { plugins { - id 'net.neoforged.gradle.userdev' version '7.0.119' apply false + id 'net.neoforged.gradle.userdev' version '7.0.134' apply false id 'org.spongepowered.mixin' version '0.7-SNAPSHOT' apply false id 'org.spongepowered.gradle.vanilla' version '0.2.1-SNAPSHOT' apply false id 'fabric-loom' version '1.6-SNAPSHOT' apply false From e458ff34833aec4001d9861789f3ffa3a66031f5 Mon Sep 17 00:00:00 2001 From: Mrbysco Date: Thu, 23 May 2024 21:06:35 +0200 Subject: [PATCH 11/25] Change the stack serialization method (WIP) --- .../patchouli/client/book/BookEntry.java | 4 +- .../patchouli/client/book/BookIcon.java | 4 +- .../IngredientVariableSerializer.java | 4 +- .../ItemStackArrayVariableSerializer.java | 4 +- .../variable/ItemStackVariableSerializer.java | 3 +- .../vazkii/patchouli/common/book/Book.java | 3 +- .../patchouli/common/util/ItemStackUtil.java | 101 +++++------------- 7 files changed, 44 insertions(+), 79 deletions(-) diff --git a/Xplat/src/main/java/vazkii/patchouli/client/book/BookEntry.java b/Xplat/src/main/java/vazkii/patchouli/client/book/BookEntry.java index 1fbe26fd9..09a2eda85 100644 --- a/Xplat/src/main/java/vazkii/patchouli/client/book/BookEntry.java +++ b/Xplat/src/main/java/vazkii/patchouli/client/book/BookEntry.java @@ -4,6 +4,8 @@ import com.google.common.reflect.TypeToken; import com.google.gson.JsonObject; +import net.minecraft.core.RegistryAccess; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.MutableComponent; import net.minecraft.resources.ResourceLocation; @@ -250,7 +252,7 @@ public void build(Level level, BookContentsBuilder builder) { List stacks; int pageNumber = entry.getValue(); try { - stacks = ItemStackUtil.loadStackListFromString(key); + stacks = ItemStackUtil.loadStackListFromString(key, RegistryAccess.fromRegistryOfRegistries(BuiltInRegistries.REGISTRY)); } catch (Exception e) { PatchouliAPI.LOGGER.warn("Invalid extra recipe mapping: {} to page {} in entry {}: {}", key, pageNumber, id, e.getMessage()); continue; diff --git a/Xplat/src/main/java/vazkii/patchouli/client/book/BookIcon.java b/Xplat/src/main/java/vazkii/patchouli/client/book/BookIcon.java index f9fd73cb9..1501bc542 100644 --- a/Xplat/src/main/java/vazkii/patchouli/client/book/BookIcon.java +++ b/Xplat/src/main/java/vazkii/patchouli/client/book/BookIcon.java @@ -2,6 +2,8 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.core.RegistryAccess; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; @@ -32,7 +34,7 @@ static BookIcon from(String str) { return new TextureIcon(new ResourceLocation(str)); } else { try { - ItemStack stack = ItemStackUtil.loadStackFromString(str); + ItemStack stack = ItemStackUtil.loadStackFromString(str, RegistryAccess.fromRegistryOfRegistries(BuiltInRegistries.REGISTRY)); return new StackIcon(stack); } catch (Exception e) { PatchouliAPI.LOGGER.warn("Invalid icon item stack: {}", e.getMessage()); diff --git a/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/IngredientVariableSerializer.java b/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/IngredientVariableSerializer.java index 3fc4be9eb..ce4218f12 100644 --- a/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/IngredientVariableSerializer.java +++ b/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/IngredientVariableSerializer.java @@ -3,6 +3,8 @@ import com.google.gson.JsonElement; import com.mojang.serialization.JsonOps; +import net.minecraft.core.RegistryAccess; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.world.item.crafting.Ingredient; import vazkii.patchouli.api.IVariableSerializer; @@ -11,7 +13,7 @@ public class IngredientVariableSerializer implements IVariableSerializer { @Override public Ingredient fromJson(JsonElement json) { - return (json.isJsonPrimitive()) ? ItemStackUtil.loadIngredientFromString(json.getAsString()) : Ingredient.CODEC.parse(JsonOps.INSTANCE, json).result().orElseThrow(); + return (json.isJsonPrimitive()) ? ItemStackUtil.loadIngredientFromString(json.getAsString(), RegistryAccess.fromRegistryOfRegistries(BuiltInRegistries.REGISTRY)) : Ingredient.CODEC.parse(RegistryAccess.fromRegistryOfRegistries(BuiltInRegistries.REGISTRY).createSerializationContext(JsonOps.INSTANCE), json).result().orElseThrow(); } @Override diff --git a/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/ItemStackArrayVariableSerializer.java b/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/ItemStackArrayVariableSerializer.java index 232975be7..9994f12c8 100644 --- a/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/ItemStackArrayVariableSerializer.java +++ b/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/ItemStackArrayVariableSerializer.java @@ -3,6 +3,8 @@ import com.google.gson.JsonArray; import com.google.gson.JsonElement; +import net.minecraft.core.RegistryAccess; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.world.item.ItemStack; import vazkii.patchouli.common.util.ItemStackUtil; @@ -34,7 +36,7 @@ public ItemStack[] fromNonArray(JsonElement json) { return empty; } if (json.isJsonPrimitive()) { - return ItemStackUtil.loadStackListFromString(json.getAsString()).toArray(empty); + return ItemStackUtil.loadStackListFromString(json.getAsString(), RegistryAccess.fromRegistryOfRegistries(BuiltInRegistries.REGISTRY)).toArray(empty); } if (json.isJsonObject()) { return new ItemStack[] { ItemStackUtil.loadStackFromJson(json.getAsJsonObject()) }; diff --git a/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/ItemStackVariableSerializer.java b/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/ItemStackVariableSerializer.java index 1321ec55a..4c183f8ca 100644 --- a/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/ItemStackVariableSerializer.java +++ b/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/ItemStackVariableSerializer.java @@ -4,6 +4,7 @@ import com.google.gson.JsonObject; import com.mojang.serialization.JsonOps; +import net.minecraft.core.RegistryAccess; import net.minecraft.core.component.DataComponentMap; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.world.item.ItemStack; @@ -18,7 +19,7 @@ public ItemStack fromJson(JsonElement json) { return ItemStack.EMPTY; } if (json.isJsonPrimitive()) { - return ItemStackUtil.loadStackFromString(json.getAsString()); + return ItemStackUtil.loadStackFromString(json.getAsString(), RegistryAccess.fromRegistryOfRegistries(BuiltInRegistries.REGISTRY)); } if (json.isJsonObject()) { return ItemStackUtil.loadStackFromJson(json.getAsJsonObject()); diff --git a/Xplat/src/main/java/vazkii/patchouli/common/book/Book.java b/Xplat/src/main/java/vazkii/patchouli/common/book/Book.java index 416fcad8d..b37ee6ca6 100644 --- a/Xplat/src/main/java/vazkii/patchouli/common/book/Book.java +++ b/Xplat/src/main/java/vazkii/patchouli/common/book/Book.java @@ -5,6 +5,7 @@ import net.minecraft.Util; import net.minecraft.client.Minecraft; +import net.minecraft.data.registries.VanillaRegistries; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.MutableComponent; import net.minecraft.network.chat.Style; @@ -158,7 +159,7 @@ public Book(JsonObject root, XplatModContainer owner, ResourceLocation id, boole if (noBook) { // Parse on load to catch errors, but need lazy loading for mods // that load after Patchouli - var parsed = ItemStackUtil.parseItemStackString(customBookItem); + var parsed = ItemStackUtil.deserializeStack(customBookItem, VanillaRegistries.createLookup()); bookItem = Suppliers.memoize(() -> ItemStackUtil.loadFromParsed(parsed)); } else { bookItem = Suppliers.memoize(() -> ItemModBook.forBook(id)); diff --git a/Xplat/src/main/java/vazkii/patchouli/common/util/ItemStackUtil.java b/Xplat/src/main/java/vazkii/patchouli/common/util/ItemStackUtil.java index 8f672b34b..6ba38c585 100644 --- a/Xplat/src/main/java/vazkii/patchouli/common/util/ItemStackUtil.java +++ b/Xplat/src/main/java/vazkii/patchouli/common/util/ItemStackUtil.java @@ -1,27 +1,22 @@ package vazkii.patchouli.common.util; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.mojang.brigadier.StringReader; import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.serialization.JsonOps; import net.minecraft.commands.arguments.item.ItemParser; +import net.minecraft.core.Holder; +import net.minecraft.core.HolderLookup; import net.minecraft.core.component.DataComponentMap; -import net.minecraft.core.component.DataComponentPatch; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.Registries; -import net.minecraft.data.registries.VanillaRegistries; import net.minecraft.resources.ResourceLocation; import net.minecraft.tags.TagKey; -import net.minecraft.util.GsonHelper; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.Ingredient; -import org.apache.commons.lang3.tuple.ImmutableTriple; import org.apache.commons.lang3.tuple.Triple; import vazkii.patchouli.common.book.Book; @@ -33,59 +28,34 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; -import java.util.Optional; public final class ItemStackUtil { - private static final Gson GSON = new GsonBuilder().create(); - private ItemStackUtil() {} - public static Triple parseItemStackString(String res) { - String components = ""; - int componentsStart = res.indexOf("{"); - if (componentsStart > 0) { - components = res.substring(componentsStart).replaceAll("([^\\\\])'", "$1\"").replaceAll("\\\\'", "'"); - res = res.substring(0, componentsStart); - } - - String[] upper = res.split("#"); - String count = "1"; - if (upper.length > 1) { - res = upper[0]; - count = upper[1]; - } - - String[] tokens = res.split(":"); - if (tokens.length < 2) { - throw new RuntimeException("Malformed item ID " + res); - } - - ResourceLocation key = new ResourceLocation(tokens[0], tokens[1]); - int countn = Integer.parseInt(count); - DataComponentMap.Builder componentMap = DataComponentMap.builder(); - - if (!components.isEmpty()) { - ItemParser parser = new ItemParser(VanillaRegistries.createLookup()); - try { - ItemParser.ItemResult result = parser.parse(new StringReader(res.toString() + components)); //TODO: Check if the parsed result is correct - componentMap.addAll(result.components()); - } catch (CommandSyntaxException e) { - throw new RuntimeException("Failed to parse ItemStack JSON", e); + public static Triple, DataComponentMap, Integer> deserializeStack(String string, HolderLookup.Provider registries) { + StringReader reader = new StringReader(string.trim()); + ItemParser itemParser = new ItemParser(registries); + try { + ItemParser.ItemResult result = itemParser.parse(reader); + int count = 1; + if (reader.canRead()) { + reader.expect('#'); + count = reader.readInt(); } + return Triple.of(result.item(), result.components(), count); + } catch (CommandSyntaxException e) { + throw new RuntimeException(e); } - - return ImmutableTriple.of(key, countn, componentMap.build()); } - public static ItemStack loadFromParsed(Triple parsed) { - var key = parsed.getLeft(); - var count = parsed.getMiddle(); - var components = parsed.getRight(); - Optional maybeItem = BuiltInRegistries.ITEM.getOptional(key); - if (maybeItem.isEmpty()) { - throw new RuntimeException("Unknown item ID: " + key); + public static ItemStack loadFromParsed(Triple, DataComponentMap, Integer> parsed) { + var holder = parsed.getLeft(); + var components = parsed.getMiddle(); + var count = parsed.getRight(); + if (!holder.isBound() && holder.unwrapKey().isPresent()) { + throw new RuntimeException("Unknown item ID: " + holder.unwrapKey().get().location()); } - Item item = maybeItem.get(); + Item item = holder.value(); ItemStack stack = new ItemStack(item, count); if (!components.isEmpty()) { @@ -94,15 +64,15 @@ public static ItemStack loadFromParsed(Triple loadStackListFromString(String ingredientString) { + public static List loadStackListFromString(String ingredientString, HolderLookup.Provider registries) { String[] stacksSerialized = splitStacksFromSerializedIngredient(ingredientString); List stacks = new ArrayList<>(); for (String s : stacksSerialized) { @@ -110,7 +80,7 @@ public static List loadStackListFromString(String ingredientString) { var key = TagKey.create(Registries.ITEM, new ResourceLocation(s.substring(4))); BuiltInRegistries.ITEM.getTag(key).ifPresent(tag -> tag.stream().forEach(item -> stacks.add(new ItemStack(item)))); } else { - stacks.add(loadStackFromString(s)); + stacks.add(loadStackFromString(s, registries)); } } return stacks; @@ -202,21 +172,6 @@ private static String[] splitStacksFromSerializedIngredient(String ingredientSer } public static ItemStack loadStackFromJson(JsonObject json) { - // Adapted from net.minecraftforge.common.crafting.CraftingHelper::getItemStack - String itemName = json.get("item").getAsString(); - - Item item = BuiltInRegistries.ITEM.getOptional(new ResourceLocation(itemName)).orElseThrow(() -> new IllegalArgumentException("Unknown item '" + itemName + "'") - ); - - ItemStack stack = new ItemStack(item, GsonHelper.getAsInt(json, "count", 1)); - - if (json.has("nbt")) { - JsonElement element = json.get("nbt"); //TODO: Do we want to change the "nbt" key to "components"? - DataComponentPatch.CODEC.decode(JsonOps.INSTANCE, element).result().ifPresent(stuff -> { - stack.applyComponents(stuff.getFirst()); - }); - } - - return stack; + return ItemStack.CODEC.parse(JsonOps.INSTANCE, json).getOrThrow(); } } From 52439fc922bba0832e05a3faaa7fc4762808a0ff Mon Sep 17 00:00:00 2001 From: Mrbysco Date: Sun, 9 Jun 2024 14:10:04 +0200 Subject: [PATCH 12/25] Feed registry access where possible --- .../java/vazkii/patchouli/api/IVariable.java | 42 ++++++++++--------- .../patchouli/api/IVariableProvider.java | 4 +- .../patchouli/api/IVariableSerializer.java | 6 ++- .../vazkii/patchouli/api/VariableHelper.java | 6 ++- .../book/template/JsonVariableWrapper.java | 6 ++- .../book/template/TemplateInclusion.java | 11 +++-- .../book/template/VariableAssigner.java | 6 ++- .../template/test/EntityTestProcessor.java | 2 +- .../template/test/RecipeTestProcessor.java | 4 +- .../GenericArrayVariableSerializer.java | 10 +++-- .../IngredientVariableSerializer.java | 7 ++-- .../ItemStackArrayVariableSerializer.java | 15 ++++--- .../variable/ItemStackVariableSerializer.java | 12 +++--- .../TextComponentVariableSerializer.java | 10 ++--- .../book/template/variable/Variable.java | 8 +++- .../template/variable/VariableHelperImpl.java | 13 +++--- .../patchouli/common/util/ItemStackUtil.java | 4 +- 17 files changed, 95 insertions(+), 71 deletions(-) diff --git a/Xplat/src/main/java/vazkii/patchouli/api/IVariable.java b/Xplat/src/main/java/vazkii/patchouli/api/IVariable.java index ebf61a0c3..b8f4f9de9 100644 --- a/Xplat/src/main/java/vazkii/patchouli/api/IVariable.java +++ b/Xplat/src/main/java/vazkii/patchouli/api/IVariable.java @@ -7,6 +7,10 @@ import com.google.gson.JsonNull; import com.google.gson.JsonPrimitive; +import net.minecraft.core.HolderLookup; +import net.minecraft.core.RegistryAccess; +import net.minecraft.core.registries.BuiltInRegistries; + import org.jetbrains.annotations.Nullable; import java.lang.reflect.Type; @@ -87,77 +91,77 @@ default boolean asBoolean(boolean def) { /** * Get this IVariable as a {@code Stream}, assuming it's backed by a JsonArray. */ - default Stream asStream() { + default Stream asStream(HolderLookup.Provider registries) { return StreamSupport.stream(unwrap().getAsJsonArray().spliterator(), false) - .map(IVariable::wrap); + .map((json) -> IVariable.wrap(json, registries)); } /** * Get this IVariable as a {@code List}, returning as singleton if it's not a JsonArray. */ - default Stream asStreamOrSingleton() { - return unwrap().isJsonArray() ? asStream() : Stream.of(this); + default Stream asStreamOrSingleton(HolderLookup.Provider registries) { + return unwrap().isJsonArray() ? asStream(registries) : Stream.of(this); } /** * Get this IVariable as a {@code List}, assuming it's backed by a JsonArray. */ - default List asList() { - return asStream().collect(Collectors.toList()); + default List asList(HolderLookup.Provider registries) { + return asStream(registries).collect(Collectors.toList()); } /** * Get this IVariable as a {@code List}, returning as singleton if it's not a JsonArray. */ - default List asListOrSingleton() { - return asStreamOrSingleton().collect(Collectors.toList()); + default List asListOrSingleton(HolderLookup.Provider registries) { + return asStreamOrSingleton(registries).collect(Collectors.toList()); } /** * Convenience method to create an IVariable from {@link VariableHelper#createFromObject}. */ - static IVariable from(@Nullable T object) { - return object != null ? VariableHelper.instance().createFromObject(object) : empty(); + static IVariable from(@Nullable T object, HolderLookup.Provider registries) { + return object != null ? VariableHelper.instance().createFromObject(object, registries) : empty(); } /** * Convenience method to create an IVariable from a JsonElement with {@link VariableHelper#createFromJson}. */ - static IVariable wrap(@Nullable JsonElement elem) { - return elem != null ? VariableHelper.instance().createFromJson(elem) : empty(); + static IVariable wrap(@Nullable JsonElement elem, HolderLookup.Provider registries) { + return elem != null ? VariableHelper.instance().createFromJson(elem, registries) : empty(); } /** * Convenience method to create an IVariable from a list of IVariables. */ - static IVariable wrapList(Iterable elems) { + static IVariable wrapList(Iterable elems, HolderLookup.Provider registries) { JsonArray arr = new JsonArray(); for (IVariable v : elems) { arr.add(v.unwrap()); } - return wrap(arr); + return wrap(arr, registries); } static IVariable wrap(@Nullable Number n) { - return n != null ? wrap(new JsonPrimitive(n)) : empty(); + return n != null ? wrap(new JsonPrimitive(n), RegistryAccess.EMPTY) : empty(); } static IVariable wrap(@Nullable Boolean b) { - return b != null ? wrap(new JsonPrimitive(b)) : empty(); + return b != null ? wrap(new JsonPrimitive(b), RegistryAccess.EMPTY) : empty(); } static IVariable wrap(@Nullable String s) { - return s != null ? wrap(new JsonPrimitive(s)) : empty(); + return s != null ? wrap(new JsonPrimitive(s), RegistryAccess.EMPTY) : empty(); } static IVariable empty() { - return wrap(JsonNull.INSTANCE); + return wrap(JsonNull.INSTANCE, RegistryAccess.EMPTY); } class Serializer implements JsonDeserializer { @Override public IVariable deserialize(JsonElement elem, Type t, JsonDeserializationContext c) { - return IVariable.wrap(elem); + return IVariable.wrap(elem, RegistryAccess.fromRegistryOfRegistries(BuiltInRegistries.REGISTRY)); } } } diff --git a/Xplat/src/main/java/vazkii/patchouli/api/IVariableProvider.java b/Xplat/src/main/java/vazkii/patchouli/api/IVariableProvider.java index 932a41e87..af23dd2c4 100644 --- a/Xplat/src/main/java/vazkii/patchouli/api/IVariableProvider.java +++ b/Xplat/src/main/java/vazkii/patchouli/api/IVariableProvider.java @@ -1,5 +1,7 @@ package vazkii.patchouli.api; +import net.minecraft.core.HolderLookup; + /** * A provider of variables to a template. Probably a JSON. */ @@ -9,7 +11,7 @@ public interface IVariableProvider { * Gets the value assigned to the variable passed in. * May throw an exception if it doesn't exist. */ - IVariable get(String key); + IVariable get(String key, HolderLookup.Provider registries); /** * Returns if a variable exists or not. diff --git a/Xplat/src/main/java/vazkii/patchouli/api/IVariableSerializer.java b/Xplat/src/main/java/vazkii/patchouli/api/IVariableSerializer.java index cbfe3b2e7..cbb9ffcf2 100644 --- a/Xplat/src/main/java/vazkii/patchouli/api/IVariableSerializer.java +++ b/Xplat/src/main/java/vazkii/patchouli/api/IVariableSerializer.java @@ -2,6 +2,8 @@ import com.google.gson.JsonElement; +import net.minecraft.core.HolderLookup; + /** * An instance of a class implementing this interface * provides conversions for the given type to/from {@link JsonElement}. @@ -12,10 +14,10 @@ public interface IVariableSerializer { /** * Deserialize an object of type T from JSON. */ - T fromJson(JsonElement json); + T fromJson(JsonElement json, HolderLookup.Provider registries); /** * Serialize an object of type T to JSON. */ - JsonElement toJson(T object); + JsonElement toJson(T object, HolderLookup.Provider registries); } diff --git a/Xplat/src/main/java/vazkii/patchouli/api/VariableHelper.java b/Xplat/src/main/java/vazkii/patchouli/api/VariableHelper.java index 0320aa2e5..7798036b9 100644 --- a/Xplat/src/main/java/vazkii/patchouli/api/VariableHelper.java +++ b/Xplat/src/main/java/vazkii/patchouli/api/VariableHelper.java @@ -3,6 +3,8 @@ import com.google.common.base.Suppliers; import com.google.gson.JsonElement; +import net.minecraft.core.HolderLookup; + import org.jetbrains.annotations.Nullable; import java.util.function.Supplier; @@ -30,14 +32,14 @@ static VariableHelper instance() { /** * Create an {@link IVariable} from a given object. */ - default IVariable createFromObject(T object) { + default IVariable createFromObject(T object, HolderLookup.Provider registries) { return null; } /** * Create an {@link IVariable} backed by the given {@link JsonElement}. */ - default IVariable createFromJson(JsonElement elem) { + default IVariable createFromJson(JsonElement elem, HolderLookup.Provider registries) { return null; } diff --git a/Xplat/src/main/java/vazkii/patchouli/client/book/template/JsonVariableWrapper.java b/Xplat/src/main/java/vazkii/patchouli/client/book/template/JsonVariableWrapper.java index 6201aee08..fb1422dc6 100644 --- a/Xplat/src/main/java/vazkii/patchouli/client/book/template/JsonVariableWrapper.java +++ b/Xplat/src/main/java/vazkii/patchouli/client/book/template/JsonVariableWrapper.java @@ -3,6 +3,8 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import net.minecraft.core.HolderLookup; + import vazkii.patchouli.api.IVariable; import vazkii.patchouli.api.IVariableProvider; @@ -15,13 +17,13 @@ public JsonVariableWrapper(JsonObject source) { } @Override - public IVariable get(String key) { + public IVariable get(String key, HolderLookup.Provider registries) { JsonElement prim = source.get(key); if (prim == null) { throw new IllegalArgumentException("Attempted to get variable " + key + " when it's not present"); } - return IVariable.wrap(prim); + return IVariable.wrap(prim, registries); } @Override diff --git a/Xplat/src/main/java/vazkii/patchouli/client/book/template/TemplateInclusion.java b/Xplat/src/main/java/vazkii/patchouli/client/book/template/TemplateInclusion.java index 15a2b87ca..9939b5248 100644 --- a/Xplat/src/main/java/vazkii/patchouli/client/book/template/TemplateInclusion.java +++ b/Xplat/src/main/java/vazkii/patchouli/client/book/template/TemplateInclusion.java @@ -4,6 +4,9 @@ import com.google.gson.JsonObject; import com.google.gson.annotations.SerializedName; +import net.minecraft.core.HolderLookup; +import net.minecraft.core.RegistryAccess; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.world.level.Level; import vazkii.patchouli.api.IComponentProcessor; @@ -87,7 +90,7 @@ public String qualifyName(String name) { String query = prefixed ? name.substring(1) : name; // if it's an upreference, return the upreference - String result = IVariable.wrap(localBindings.get(query)).asString(); + String result = IVariable.wrap(localBindings.get(query), RegistryAccess.fromRegistryOfRegistries(BuiltInRegistries.REGISTRY)).asString(); if (result.startsWith("#")) { return result.substring(1); } @@ -102,7 +105,7 @@ public IVariable attemptVariableLookup(String key) { if (key.startsWith("#")) { key = key.substring(1); } - IVariable result = IVariable.wrap(localBindings.get(key)); + IVariable result = IVariable.wrap(localBindings.get(key), RegistryAccess.fromRegistryOfRegistries(BuiltInRegistries.REGISTRY)); return result.asString().isEmpty() || isUpreference(result) ? null : result; } @@ -121,9 +124,9 @@ public boolean has(String key) { } @Override - public IVariable get(String key) { + public IVariable get(String key, HolderLookup.Provider registries) { IVariable vari = attemptVariableLookup(key); - return vari == null ? provider.get(qualifyName(key)) : vari; + return vari == null ? provider.get(qualifyName(key), registries) : vari; } }; } diff --git a/Xplat/src/main/java/vazkii/patchouli/client/book/template/VariableAssigner.java b/Xplat/src/main/java/vazkii/patchouli/client/book/template/VariableAssigner.java index 1b98be9fc..cdd61ed82 100644 --- a/Xplat/src/main/java/vazkii/patchouli/client/book/template/VariableAssigner.java +++ b/Xplat/src/main/java/vazkii/patchouli/client/book/template/VariableAssigner.java @@ -1,6 +1,8 @@ package vazkii.patchouli.client.book.template; import net.minecraft.client.resources.language.I18n; +import net.minecraft.core.RegistryAccess; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.level.Level; @@ -133,7 +135,7 @@ private static IVariable resolveStringVar(Level level, String original, Context } if (val == null && c.variables.has(key)) { - val = c.variables.get(key); + val = c.variables.get(key, level.registryAccess()); } return val == null ? IVariable.empty() : val; @@ -169,7 +171,7 @@ private static IVariable inv(IVariable arg) { } private static IVariable stacks(IVariable arg) { - return IVariable.from(arg.as(Ingredient.class).getItems()); + return IVariable.from(arg.as(Ingredient.class).getItems(), RegistryAccess.fromRegistryOfRegistries(BuiltInRegistries.REGISTRY)); } private static String ename(String arg) { diff --git a/Xplat/src/main/java/vazkii/patchouli/client/book/template/test/EntityTestProcessor.java b/Xplat/src/main/java/vazkii/patchouli/client/book/template/test/EntityTestProcessor.java index ecaf75cb7..e8e3c144a 100644 --- a/Xplat/src/main/java/vazkii/patchouli/client/book/template/test/EntityTestProcessor.java +++ b/Xplat/src/main/java/vazkii/patchouli/client/book/template/test/EntityTestProcessor.java @@ -16,7 +16,7 @@ public class EntityTestProcessor implements IComponentProcessor { @Override public void setup(Level level, IVariableProvider variables) { - String entityType = variables.get("entity").unwrap().getAsString(); + String entityType = variables.get("entity", level.registryAccess()).unwrap().getAsString(); if (entityType.contains("{")) { entityType = entityType.substring(0, entityType.indexOf("{")); } diff --git a/Xplat/src/main/java/vazkii/patchouli/client/book/template/test/RecipeTestProcessor.java b/Xplat/src/main/java/vazkii/patchouli/client/book/template/test/RecipeTestProcessor.java index 100c8b792..9da52d1ca 100644 --- a/Xplat/src/main/java/vazkii/patchouli/client/book/template/test/RecipeTestProcessor.java +++ b/Xplat/src/main/java/vazkii/patchouli/client/book/template/test/RecipeTestProcessor.java @@ -18,7 +18,7 @@ public class RecipeTestProcessor implements IComponentProcessor { @Override public void setup(Level level, IVariableProvider variables) { // TODO probably add a recipe serializer? - String recipeId = variables.get("recipe").asString(); + String recipeId = variables.get("recipe", level.registryAccess()).asString(); RecipeManager manager = level.getRecipeManager(); recipe = manager.byKey(new ResourceLocation(recipeId)).orElseThrow(IllegalArgumentException::new).value(); } @@ -31,7 +31,7 @@ public IVariable process(Level level, String key) { ItemStack[] stacks = ingredient.getItems(); ItemStack stack = stacks.length == 0 ? ItemStack.EMPTY : stacks[0]; - return IVariable.from(stack); + return IVariable.from(stack, level.registryAccess()); } else if (key.equals("text")) { ItemStack out = recipe.getResultItem(level.registryAccess()); return IVariable.wrap(out.getCount() + "x$(br)" + out.getHoverName()); diff --git a/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/GenericArrayVariableSerializer.java b/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/GenericArrayVariableSerializer.java index 59d4e122a..217b05b16 100644 --- a/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/GenericArrayVariableSerializer.java +++ b/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/GenericArrayVariableSerializer.java @@ -3,6 +3,8 @@ import com.google.gson.JsonArray; import com.google.gson.JsonElement; +import net.minecraft.core.HolderLookup; + import vazkii.patchouli.api.IVariableSerializer; import java.lang.reflect.Array; @@ -20,12 +22,12 @@ public GenericArrayVariableSerializer(IVariableSerializer inner, Class typ } @Override - public T[] fromJson(JsonElement json) { + public T[] fromJson(JsonElement json, HolderLookup.Provider registries) { if (json.isJsonArray()) { JsonArray array = json.getAsJsonArray(); List stacks = new ArrayList<>(); for (JsonElement e : array) { - stacks.add(inner.fromJson(e)); + stacks.add(inner.fromJson(e, registries)); } return stacks.toArray(empty); } @@ -33,10 +35,10 @@ public T[] fromJson(JsonElement json) { } @Override - public JsonArray toJson(T[] array) { + public JsonArray toJson(T[] array, HolderLookup.Provider registries) { JsonArray result = new JsonArray(); for (T elem : array) { - result.add(inner.toJson(elem)); + result.add(inner.toJson(elem, registries)); } return result; } diff --git a/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/IngredientVariableSerializer.java b/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/IngredientVariableSerializer.java index ce4218f12..38607a7bd 100644 --- a/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/IngredientVariableSerializer.java +++ b/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/IngredientVariableSerializer.java @@ -3,6 +3,7 @@ import com.google.gson.JsonElement; import com.mojang.serialization.JsonOps; +import net.minecraft.core.HolderLookup; import net.minecraft.core.RegistryAccess; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.world.item.crafting.Ingredient; @@ -12,12 +13,12 @@ public class IngredientVariableSerializer implements IVariableSerializer { @Override - public Ingredient fromJson(JsonElement json) { + public Ingredient fromJson(JsonElement json, HolderLookup.Provider registries) { return (json.isJsonPrimitive()) ? ItemStackUtil.loadIngredientFromString(json.getAsString(), RegistryAccess.fromRegistryOfRegistries(BuiltInRegistries.REGISTRY)) : Ingredient.CODEC.parse(RegistryAccess.fromRegistryOfRegistries(BuiltInRegistries.REGISTRY).createSerializationContext(JsonOps.INSTANCE), json).result().orElseThrow(); } @Override - public JsonElement toJson(Ingredient stack) { - return Ingredient.CODEC.encodeStart(JsonOps.INSTANCE, stack).result().orElseThrow(); + public JsonElement toJson(Ingredient stack, HolderLookup.Provider registries) { + return Ingredient.CODEC.encodeStart(registries.createSerializationContext(JsonOps.INSTANCE), stack).result().orElseThrow(); } } diff --git a/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/ItemStackArrayVariableSerializer.java b/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/ItemStackArrayVariableSerializer.java index 9994f12c8..efd1e31bd 100644 --- a/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/ItemStackArrayVariableSerializer.java +++ b/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/ItemStackArrayVariableSerializer.java @@ -3,8 +3,7 @@ import com.google.gson.JsonArray; import com.google.gson.JsonElement; -import net.minecraft.core.RegistryAccess; -import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.core.HolderLookup; import net.minecraft.world.item.ItemStack; import vazkii.patchouli.common.util.ItemStackUtil; @@ -19,27 +18,27 @@ public ItemStackArrayVariableSerializer() { } @Override - public ItemStack[] fromJson(JsonElement json) { + public ItemStack[] fromJson(JsonElement json, HolderLookup.Provider registries) { if (json.isJsonArray()) { JsonArray array = json.getAsJsonArray(); List stacks = new ArrayList<>(); for (JsonElement e : array) { - stacks.addAll(Arrays.asList(fromNonArray(e))); + stacks.addAll(Arrays.asList(fromNonArray(e, registries))); } return stacks.toArray(empty); } - return fromNonArray(json); + return fromNonArray(json, registries); } - public ItemStack[] fromNonArray(JsonElement json) { + public ItemStack[] fromNonArray(JsonElement json, HolderLookup.Provider registries) { if (json.isJsonNull()) { return empty; } if (json.isJsonPrimitive()) { - return ItemStackUtil.loadStackListFromString(json.getAsString(), RegistryAccess.fromRegistryOfRegistries(BuiltInRegistries.REGISTRY)).toArray(empty); + return ItemStackUtil.loadStackListFromString(json.getAsString(), registries).toArray(empty); } if (json.isJsonObject()) { - return new ItemStack[] { ItemStackUtil.loadStackFromJson(json.getAsJsonObject()) }; + return new ItemStack[] { ItemStackUtil.loadStackFromJson(json.getAsJsonObject(), registries) }; } throw new IllegalArgumentException("Can't make an ItemStack from an array!"); } diff --git a/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/ItemStackVariableSerializer.java b/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/ItemStackVariableSerializer.java index 4c183f8ca..f33ebd1ef 100644 --- a/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/ItemStackVariableSerializer.java +++ b/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/ItemStackVariableSerializer.java @@ -4,7 +4,7 @@ import com.google.gson.JsonObject; import com.mojang.serialization.JsonOps; -import net.minecraft.core.RegistryAccess; +import net.minecraft.core.HolderLookup; import net.minecraft.core.component.DataComponentMap; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.world.item.ItemStack; @@ -14,21 +14,21 @@ public class ItemStackVariableSerializer implements IVariableSerializer { @Override - public ItemStack fromJson(JsonElement json) { + public ItemStack fromJson(JsonElement json, HolderLookup.Provider registries) { if (json.isJsonNull()) { return ItemStack.EMPTY; } if (json.isJsonPrimitive()) { - return ItemStackUtil.loadStackFromString(json.getAsString(), RegistryAccess.fromRegistryOfRegistries(BuiltInRegistries.REGISTRY)); + return ItemStackUtil.loadStackFromString(json.getAsString(), registries); } if (json.isJsonObject()) { - return ItemStackUtil.loadStackFromJson(json.getAsJsonObject()); + return ItemStackUtil.loadStackFromJson(json.getAsJsonObject(), registries); } throw new IllegalArgumentException("Can't make an ItemStack from an array!"); } @Override - public JsonElement toJson(ItemStack stack) { + public JsonElement toJson(ItemStack stack, HolderLookup.Provider registries) { // Adapted from net.minecraftforge.common.crafting.StackList::toJson JsonObject ret = new JsonObject(); ret.addProperty("item", BuiltInRegistries.ITEM.getKey(stack.getItem()).toString()); @@ -37,7 +37,7 @@ public JsonElement toJson(ItemStack stack) { } if (!stack.getComponents().isEmpty()) { DataComponentMap data = stack.getComponents(); - DataComponentMap.CODEC.encodeStart(JsonOps.INSTANCE, data).result().ifPresent(e -> ret.add("nbt", e)); //TODO: Do we want to change the "nbt" key to "components"? + DataComponentMap.CODEC.encodeStart(registries.createSerializationContext(JsonOps.INSTANCE), data).result().ifPresent(e -> ret.add("nbt", e)); //TODO: Do we want to change the "nbt" key to "components"? } return ret; } diff --git a/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/TextComponentVariableSerializer.java b/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/TextComponentVariableSerializer.java index fa2ab383e..419b91e6a 100644 --- a/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/TextComponentVariableSerializer.java +++ b/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/TextComponentVariableSerializer.java @@ -4,7 +4,7 @@ import com.google.gson.JsonParseException; import com.mojang.serialization.JsonOps; -import net.minecraft.core.RegistryAccess; +import net.minecraft.core.HolderLookup; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component.Serializer; import net.minecraft.network.chat.ComponentSerialization; @@ -13,18 +13,18 @@ public class TextComponentVariableSerializer implements IVariableSerializer { @Override - public Component fromJson(JsonElement json) { + public Component fromJson(JsonElement json, HolderLookup.Provider registries) { if (json.isJsonNull()) { return Component.literal(""); } if (json.isJsonPrimitive() && json.getAsJsonPrimitive().isString()) { return Component.literal(json.getAsString()); } - return Serializer.fromJson(json, RegistryAccess.EMPTY); + return Serializer.fromJson(json, registries); } @Override - public JsonElement toJson(Component stack) { - return ComponentSerialization.CODEC.encodeStart(RegistryAccess.EMPTY.createSerializationContext(JsonOps.INSTANCE), stack).getOrThrow(JsonParseException::new); + public JsonElement toJson(Component stack, HolderLookup.Provider registries) { + return ComponentSerialization.CODEC.encodeStart(registries.createSerializationContext(JsonOps.INSTANCE), stack).getOrThrow(JsonParseException::new); } } diff --git a/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/Variable.java b/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/Variable.java index a7fdd21b4..ca67b6cf6 100644 --- a/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/Variable.java +++ b/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/Variable.java @@ -2,6 +2,8 @@ import com.google.gson.JsonElement; +import net.minecraft.core.HolderLookup; + import vazkii.patchouli.api.IVariable; import vazkii.patchouli.api.IVariableSerializer; import vazkii.patchouli.api.VariableHelper; @@ -14,10 +16,12 @@ public class Variable implements IVariable { private final JsonElement value; @Nullable private final Class sourceClass; + private final HolderLookup.Provider registries; - public Variable(JsonElement elem, Class c) { + public Variable(JsonElement elem, Class c, HolderLookup.Provider provider) { value = Objects.requireNonNull(elem); sourceClass = c; + registries = provider; } @Override @@ -28,7 +32,7 @@ public T as(Class clazz) { throw new IllegalArgumentException(String.format("Can't deserialize object of class %s from IVariable", clazz)); } - return serializer.fromJson(value); + return serializer.fromJson(value, registries); } @Override diff --git a/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/VariableHelperImpl.java b/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/VariableHelperImpl.java index e125e58cb..19d80e512 100644 --- a/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/VariableHelperImpl.java +++ b/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/VariableHelperImpl.java @@ -2,6 +2,7 @@ import com.google.gson.JsonElement; +import net.minecraft.core.HolderLookup; import net.minecraft.network.chat.Component; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.Ingredient; @@ -44,11 +45,11 @@ public IVariableSerializer serializerForClass(Class clazz) { @Override @SuppressWarnings("unchecked") - public IVariable createFromObject(T object) { + public IVariable createFromObject(T object, HolderLookup.Provider registries) { Class clazz = object.getClass(); for (Entry, IVariableSerializer> e : serializers.entrySet()) { if (e.getKey().isAssignableFrom(clazz)) { - return create(((IVariableSerializer) e.getValue()).toJson(object), clazz); + return create(((IVariableSerializer) e.getValue()).toJson(object, registries), clazz, registries); } } @@ -56,12 +57,12 @@ public IVariable createFromObject(T object) { } @Override - public IVariable createFromJson(JsonElement elem) { - return create(elem, null); + public IVariable createFromJson(JsonElement elem, HolderLookup.Provider registries) { + return create(elem, null, registries); } - private IVariable create(JsonElement elem, Class originator) { - return new Variable(elem, originator); + private IVariable create(JsonElement elem, Class originator, HolderLookup.Provider registries) { + return new Variable(elem, originator, registries); } @Override diff --git a/Xplat/src/main/java/vazkii/patchouli/common/util/ItemStackUtil.java b/Xplat/src/main/java/vazkii/patchouli/common/util/ItemStackUtil.java index 6ba38c585..aa002abc8 100644 --- a/Xplat/src/main/java/vazkii/patchouli/common/util/ItemStackUtil.java +++ b/Xplat/src/main/java/vazkii/patchouli/common/util/ItemStackUtil.java @@ -171,7 +171,7 @@ private static String[] splitStacksFromSerializedIngredient(String ingredientSer return result.toArray(new String[0]); } - public static ItemStack loadStackFromJson(JsonObject json) { - return ItemStack.CODEC.parse(JsonOps.INSTANCE, json).getOrThrow(); + public static ItemStack loadStackFromJson(JsonObject json, HolderLookup.Provider registries) { + return ItemStack.CODEC.parse(registries.createSerializationContext(JsonOps.INSTANCE), json).getOrThrow(); } } From 919ce3e180912d99e92ed0fd631cb569f706b01d Mon Sep 17 00:00:00 2001 From: Mrbysco Date: Sun, 9 Jun 2024 14:11:40 +0200 Subject: [PATCH 13/25] Fix typo in networking translation key --- Xplat/src/main/resources/assets/patchouli/lang/en_us.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Xplat/src/main/resources/assets/patchouli/lang/en_us.json b/Xplat/src/main/resources/assets/patchouli/lang/en_us.json index 77202d41f..b39f7a231 100644 --- a/Xplat/src/main/resources/assets/patchouli/lang/en_us.json +++ b/Xplat/src/main/resources/assets/patchouli/lang/en_us.json @@ -100,5 +100,5 @@ "patchouli.gui.lexicon.button.mark_category_read": "Mark this category as read", "patchouli.networking.open_book.failed": "Failed to open book %s", - "patchouli.networking.reload_contents.invalid": "Failed to reload contents %S" + "patchouli.networking.reload_contents.failed": "Failed to reload contents %S" } From 013d12944fb31d153aa1e7cd02b5e16eeb5cf585 Mon Sep 17 00:00:00 2001 From: Mrbysco Date: Tue, 11 Jun 2024 19:06:43 +0200 Subject: [PATCH 14/25] Update NeoForge and Fabric --- Fabric/build.gradle | 4 ++-- NeoForge/build.gradle | 2 +- settings.gradle | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Fabric/build.gradle b/Fabric/build.gradle index 3315491af..2125e87fe 100644 --- a/Fabric/build.gradle +++ b/Fabric/build.gradle @@ -61,9 +61,9 @@ dependencies { minecraft "com.mojang:minecraft:${mc_version}" mappings loom.officialMojangMappings() - modImplementation "net.fabricmc:fabric-loader:0.15.10" + modImplementation "net.fabricmc:fabric-loader:0.15.11" - modImplementation "net.fabricmc.fabric-api:fabric-api:0.97.8+1.20.6" + modImplementation "net.fabricmc.fabric-api:fabric-api:0.100.0+1.20.6" compileOnly project(":Xplat") modCompileOnly "mezz.jei:jei-1.20.4-common-api:17.3.0.49" diff --git a/NeoForge/build.gradle b/NeoForge/build.gradle index 9f79daf9e..8380a98d4 100644 --- a/NeoForge/build.gradle +++ b/NeoForge/build.gradle @@ -37,7 +37,7 @@ runs { } dependencies { - implementation "net.neoforged:neoforge:20.6.74-beta" + implementation "net.neoforged:neoforge:20.6.115" implementation project(":Xplat") compileOnly "mezz.jei:jei-1.20.4-common-api:17.3.0.49" diff --git a/settings.gradle b/settings.gradle index 4692c24e1..a0a9afaaf 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,6 +1,6 @@ pluginManagement { plugins { - id 'net.neoforged.gradle.userdev' version '7.0.134' apply false + id 'net.neoforged.gradle.userdev' version '7.0.142' apply false id 'org.spongepowered.mixin' version '0.7-SNAPSHOT' apply false id 'org.spongepowered.gradle.vanilla' version '0.2.1-SNAPSHOT' apply false id 'fabric-loom' version '1.6-SNAPSHOT' apply false From 50736e18a0d567fedcc4074374c29f4b3ba39d0b Mon Sep 17 00:00:00 2001 From: Mrbysco Date: Tue, 11 Jun 2024 21:14:53 +0200 Subject: [PATCH 15/25] Fix a creative tab crash --- .../patchouli/neoforge/common/NeoForgeModInitializer.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/NeoForge/src/main/java/vazkii/patchouli/neoforge/common/NeoForgeModInitializer.java b/NeoForge/src/main/java/vazkii/patchouli/neoforge/common/NeoForgeModInitializer.java index 70a4967b9..e2dfc7349 100644 --- a/NeoForge/src/main/java/vazkii/patchouli/neoforge/common/NeoForgeModInitializer.java +++ b/NeoForge/src/main/java/vazkii/patchouli/neoforge/common/NeoForgeModInitializer.java @@ -1,6 +1,7 @@ package vazkii.patchouli.neoforge.common; import net.minecraft.core.registries.Registries; +import net.minecraft.world.item.CreativeModeTab; import net.minecraft.world.item.CreativeModeTabs; import net.minecraft.world.item.ItemStack; import net.neoforged.api.distmarker.Dist; @@ -57,7 +58,7 @@ public static void processCreativeTabs(BuildCreativeModeTabContentsEvent evt) { if (!b.noBook) { ItemStack book = ItemModBook.forBook(b); if (evt.getTab() == CreativeModeTabs.searchTab()) { - evt.accept(book); + evt.accept(book, CreativeModeTab.TabVisibility.SEARCH_TAB_ONLY); } else if (b.creativeTab != null) { if (evt.getTab() == CreativeModeTabRegistry.getTab(b.creativeTab)) { evt.accept(book); From 111b13b3eb4f4b09d97c6b2272d3206ef5f9f2d5 Mon Sep 17 00:00:00 2001 From: Mrbysco Date: Tue, 11 Jun 2024 21:26:44 +0200 Subject: [PATCH 16/25] Disable NeoForge test since it conflicts --- NeoForge/build.gradle | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/NeoForge/build.gradle b/NeoForge/build.gradle index 8380a98d4..757b0b156 100644 --- a/NeoForge/build.gradle +++ b/NeoForge/build.gradle @@ -44,6 +44,11 @@ dependencies { testCompileOnly "mezz.jei:jei-1.20.4-common-api:17.3.0.49" } +tasks.named('test').configure { + //Disable builtin test as we have JUnit enabled in Xplat + enabled(false) +} + TaskCollection.metaClass.excludingNeoTasks = { -> delegate.matching { !it.name.startsWith("neo") } } From 360067c4477d7b424a0da9d747b77de55ac952a4 Mon Sep 17 00:00:00 2001 From: Mrbysco Date: Mon, 17 Jun 2024 21:52:04 +0200 Subject: [PATCH 17/25] Update JEI and REI --- Fabric/build.gradle | 4 ++-- NeoForge/build.gradle | 4 ++-- Xplat/build.gradle | 6 ++++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Fabric/build.gradle b/Fabric/build.gradle index 2125e87fe..66ac61813 100644 --- a/Fabric/build.gradle +++ b/Fabric/build.gradle @@ -66,9 +66,9 @@ dependencies { modImplementation "net.fabricmc.fabric-api:fabric-api:0.100.0+1.20.6" compileOnly project(":Xplat") - modCompileOnly "mezz.jei:jei-1.20.4-common-api:17.3.0.49" + modCompileOnly "mezz.jei:jei-1.20.6-common-api:18.0.0.62" - modCompileOnly("me.shedaniel:RoughlyEnoughItems-api-fabric:15.0.728") { transitive = false } + modCompileOnly("me.shedaniel:RoughlyEnoughItems-api-fabric:16.0.729") { transitive = false } modCompileOnly("me.shedaniel.cloth:cloth-config-fabric:14.0.126") { transitive = false } } diff --git a/NeoForge/build.gradle b/NeoForge/build.gradle index 757b0b156..06002dea0 100644 --- a/NeoForge/build.gradle +++ b/NeoForge/build.gradle @@ -40,8 +40,8 @@ dependencies { implementation "net.neoforged:neoforge:20.6.115" implementation project(":Xplat") - compileOnly "mezz.jei:jei-1.20.4-common-api:17.3.0.49" - testCompileOnly "mezz.jei:jei-1.20.4-common-api:17.3.0.49" + compileOnly "mezz.jei:jei-1.20.6-common-api:18.0.0.62" + testCompileOnly "mezz.jei:jei-1.20.6-common-api:18.0.0.62" } tasks.named('test').configure { diff --git a/Xplat/build.gradle b/Xplat/build.gradle index 84db06d51..b82aac148 100644 --- a/Xplat/build.gradle +++ b/Xplat/build.gradle @@ -3,7 +3,9 @@ plugins { id 'org.spongepowered.gradle.vanilla' } -archivesBaseName = "${mod_name}-xplat" +base { + archivesName = "${mod_name}-xplat" +} version = "${mc_version}-${build_number}" if (System.getenv().RELEASE_MODE == null) { version += '-SNAPSHOT' @@ -25,7 +27,7 @@ repositories { dependencies { compileOnly group: 'org.spongepowered', name: 'mixin', version: '0.8.5' - compileOnly "mezz.jei:jei-1.20.4-common-api:17.3.0.49" + compileOnly "mezz.jei:jei-1.20.6-common-api:18.0.0.62" testImplementation 'org.junit.jupiter:junit-jupiter-api:5.6.1' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.6.1' } From ca081af4a504b3a44eba888e3fe1ed3cc0967449 Mon Sep 17 00:00:00 2001 From: Mrbysco Date: Mon, 17 Jun 2024 22:54:34 +0200 Subject: [PATCH 18/25] Fix Ingredient Variable serializer not using the HolderLookup --- .../book/template/variable/IngredientVariableSerializer.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/IngredientVariableSerializer.java b/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/IngredientVariableSerializer.java index 38607a7bd..ca52c4704 100644 --- a/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/IngredientVariableSerializer.java +++ b/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/IngredientVariableSerializer.java @@ -4,8 +4,6 @@ import com.mojang.serialization.JsonOps; import net.minecraft.core.HolderLookup; -import net.minecraft.core.RegistryAccess; -import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.world.item.crafting.Ingredient; import vazkii.patchouli.api.IVariableSerializer; @@ -14,7 +12,7 @@ public class IngredientVariableSerializer implements IVariableSerializer { @Override public Ingredient fromJson(JsonElement json, HolderLookup.Provider registries) { - return (json.isJsonPrimitive()) ? ItemStackUtil.loadIngredientFromString(json.getAsString(), RegistryAccess.fromRegistryOfRegistries(BuiltInRegistries.REGISTRY)) : Ingredient.CODEC.parse(RegistryAccess.fromRegistryOfRegistries(BuiltInRegistries.REGISTRY).createSerializationContext(JsonOps.INSTANCE), json).result().orElseThrow(); + return (json.isJsonPrimitive()) ? ItemStackUtil.loadIngredientFromString(json.getAsString(), registries) : Ingredient.CODEC.parse(registries.createSerializationContext(JsonOps.INSTANCE), json).result().orElseThrow(); } @Override From 1dbfa89ed6e9e58d6a6022d9be1f447ba3f46dff Mon Sep 17 00:00:00 2001 From: Mrbysco Date: Mon, 17 Jun 2024 22:56:53 +0200 Subject: [PATCH 19/25] Change the ItemStackVariableSerializer toJson to use "components" --- .../variable/ItemStackVariableSerializer.java | 2 +- .../en_us/entries/intro/smelttest.json | 19 ++++++++----------- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/ItemStackVariableSerializer.java b/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/ItemStackVariableSerializer.java index f33ebd1ef..67b827580 100644 --- a/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/ItemStackVariableSerializer.java +++ b/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/ItemStackVariableSerializer.java @@ -37,7 +37,7 @@ public JsonElement toJson(ItemStack stack, HolderLookup.Provider registries) { } if (!stack.getComponents().isEmpty()) { DataComponentMap data = stack.getComponents(); - DataComponentMap.CODEC.encodeStart(registries.createSerializationContext(JsonOps.INSTANCE), data).result().ifPresent(e -> ret.add("nbt", e)); //TODO: Do we want to change the "nbt" key to "components"? + DataComponentMap.CODEC.encodeStart(registries.createSerializationContext(JsonOps.INSTANCE), data).result().ifPresent(e -> ret.add("components", e)); } return ret; } diff --git a/Xplat/src/main/resources/assets/patchouli/patchouli_books/testbook1/en_us/entries/intro/smelttest.json b/Xplat/src/main/resources/assets/patchouli/patchouli_books/testbook1/en_us/entries/intro/smelttest.json index 7efaa0d26..9cb78e126 100644 --- a/Xplat/src/main/resources/assets/patchouli/patchouli_books/testbook1/en_us/entries/intro/smelttest.json +++ b/Xplat/src/main/resources/assets/patchouli/patchouli_books/testbook1/en_us/entries/intro/smelttest.json @@ -18,18 +18,15 @@ "item": { "item": "minecraft:diamond_sword", "count": 293, - "nbt": { - "Enchantments": [ - { - "id": "minecraft:sharpness", - "lvl": 3 - } + "components": { + "minecraft:lore": [ + "\"This has lore!!!\"", + "\"Whoever redesigned this system to take \\\"stringified JSON\\\" should be fed to Ravagers on sight!\"" ], - "display": { - "Lore": [ - "\"This has lore!!!\"", - "\"Whoever redesigned this system to take \\\"stringified JSON\\\" should be fed to Ravagers on sight!\"" - ] + "minecraft:enchantments": { + "levels": { + "minecraft:sharpness": 3 + } } } } From b5af6d0f516bc01b15c9c0b49771e55dcc0edf75 Mon Sep 17 00:00:00 2001 From: Mrbysco Date: Mon, 17 Jun 2024 22:57:49 +0200 Subject: [PATCH 20/25] Revert change to ItemStackUtil#loadStackFromJson --- .../patchouli/common/util/ItemStackUtil.java | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/Xplat/src/main/java/vazkii/patchouli/common/util/ItemStackUtil.java b/Xplat/src/main/java/vazkii/patchouli/common/util/ItemStackUtil.java index aa002abc8..907f4179b 100644 --- a/Xplat/src/main/java/vazkii/patchouli/common/util/ItemStackUtil.java +++ b/Xplat/src/main/java/vazkii/patchouli/common/util/ItemStackUtil.java @@ -13,6 +13,7 @@ import net.minecraft.core.registries.Registries; import net.minecraft.resources.ResourceLocation; import net.minecraft.tags.TagKey; +import net.minecraft.util.GsonHelper; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.Ingredient; @@ -172,6 +173,19 @@ private static String[] splitStacksFromSerializedIngredient(String ingredientSer } public static ItemStack loadStackFromJson(JsonObject json, HolderLookup.Provider registries) { - return ItemStack.CODEC.parse(registries.createSerializationContext(JsonOps.INSTANCE), json).getOrThrow(); + String itemName = json.get("item").getAsString(); + + Item item = BuiltInRegistries.ITEM.getOptional(new ResourceLocation(itemName)).orElseThrow(() -> new IllegalArgumentException("Unknown item '" + itemName + "'") + ); + + ItemStack stack = new ItemStack(item, GsonHelper.getAsInt(json, "count", 1)); + + if (json.has("components")) { + DataComponentMap.CODEC.parse(registries.createSerializationContext(JsonOps.INSTANCE), json.get("components")).resultOrPartial(e -> { + throw new IllegalArgumentException("Failed to parse components: " + e); + }).ifPresent(stack::applyComponents); + } + + return stack; } } From f99ce5955499dca7e85fcdc9f57acf9b24df9b66 Mon Sep 17 00:00:00 2001 From: Mrbysco Date: Sat, 22 Jun 2024 17:59:33 +0200 Subject: [PATCH 21/25] Change the spotlight page to use ItemStack[] instead of Ingredient This prevents Components from being getting removed --- .../patchouli/client/book/page/PageSpotlight.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Xplat/src/main/java/vazkii/patchouli/client/book/page/PageSpotlight.java b/Xplat/src/main/java/vazkii/patchouli/client/book/page/PageSpotlight.java index 8fcd2fa47..97200cf83 100644 --- a/Xplat/src/main/java/vazkii/patchouli/client/book/page/PageSpotlight.java +++ b/Xplat/src/main/java/vazkii/patchouli/client/book/page/PageSpotlight.java @@ -6,7 +6,6 @@ import net.minecraft.client.gui.GuiGraphics; import net.minecraft.network.chat.Component; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.level.Level; import vazkii.patchouli.api.IVariable; @@ -21,15 +20,15 @@ public class PageSpotlight extends PageWithText { String title; @SerializedName("link_recipe") boolean linkRecipe; - transient Ingredient ingredient; + transient ItemStack[] stacks; @Override public void build(Level level, BookEntry entry, BookContentsBuilder builder, int pageNum) { super.build(level, entry, builder, pageNum); - ingredient = item.as(Ingredient.class); + stacks = item.as(ItemStack[].class); if (linkRecipe) { - for (ItemStack stack : ingredient.getItems()) { + for (ItemStack stack : stacks) { entry.addRelevantStack(builder, stack, pageNum); } } @@ -47,11 +46,13 @@ public void render(GuiGraphics graphics, int mouseX, int mouseY, float pticks) { if (title != null && !title.isEmpty()) { toDraw = i18nText(title); } else { - toDraw = ingredient.getItems()[0].getHoverName(); + toDraw = stacks[0].getHoverName(); } parent.drawCenteredStringNoShadow(graphics, toDraw.getVisualOrderText(), GuiBook.PAGE_WIDTH / 2, 0, book.headerColor); - parent.renderIngredient(graphics, GuiBook.PAGE_WIDTH / 2 - 8, 15, mouseX, mouseY, ingredient); + if (stacks.length > 0) { + parent.renderItemStack(graphics, GuiBook.PAGE_WIDTH / 2 - 8, 15, mouseX, mouseY, stacks[(parent.ticksInBook / 20) % stacks.length]); + } super.render(graphics, mouseX, mouseY, pticks); } From ac94dda150dc226faf5439c5adc61d9ed7cc905b Mon Sep 17 00:00:00 2001 From: Mrbysco Date: Sat, 22 Jun 2024 18:05:27 +0200 Subject: [PATCH 22/25] Remove the isString check from TextComponentVariableSerializer --- .../book/template/variable/TextComponentVariableSerializer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/TextComponentVariableSerializer.java b/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/TextComponentVariableSerializer.java index 419b91e6a..9c88babb4 100644 --- a/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/TextComponentVariableSerializer.java +++ b/Xplat/src/main/java/vazkii/patchouli/client/book/template/variable/TextComponentVariableSerializer.java @@ -17,7 +17,7 @@ public Component fromJson(JsonElement json, HolderLookup.Provider registries) { if (json.isJsonNull()) { return Component.literal(""); } - if (json.isJsonPrimitive() && json.getAsJsonPrimitive().isString()) { + if (json.isJsonPrimitive()) { return Component.literal(json.getAsString()); } return Serializer.fromJson(json, registries); From b4a1d8ac3829147dd79005d972646b3be7aa5598 Mon Sep 17 00:00:00 2001 From: Minecraftschurli Date: Mon, 1 Jul 2024 20:58:36 +0200 Subject: [PATCH 23/25] add HolderLookup.Provider context in VariableAssigner --- .../book/template/VariableAssigner.java | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/Xplat/src/main/java/vazkii/patchouli/client/book/template/VariableAssigner.java b/Xplat/src/main/java/vazkii/patchouli/client/book/template/VariableAssigner.java index cdd61ed82..409853d8f 100644 --- a/Xplat/src/main/java/vazkii/patchouli/client/book/template/VariableAssigner.java +++ b/Xplat/src/main/java/vazkii/patchouli/client/book/template/VariableAssigner.java @@ -1,8 +1,7 @@ package vazkii.patchouli.client.book.template; import net.minecraft.client.resources.language.I18n; -import net.minecraft.core.RegistryAccess; -import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.core.HolderLookup; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.level.Level; @@ -19,8 +18,8 @@ import java.util.HashMap; import java.util.Map; +import java.util.function.BiFunction; import java.util.function.Function; -import java.util.function.UnaryOperator; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -29,7 +28,7 @@ public class VariableAssigner { private static final Pattern INLINE_VAR_PATTERN = Pattern.compile("([^#]*)(#[^#]+)#(.*)"); private static final Pattern FUNCTION_PATTERN = Pattern.compile("(.+)->(.+)"); - private static final Map> FUNCTIONS = new HashMap<>(); + private static final Map> FUNCTIONS = new HashMap<>(); static { FUNCTIONS.put("iname", VariableAssigner::iname); FUNCTIONS.put("icount", VariableAssigner::icount); @@ -96,9 +95,9 @@ private static IVariable resolveStringFunctions(Level level, String curr, Contex String arg = m.group(1); if (FUNCTIONS.containsKey(funcStr)) { - UnaryOperator func = FUNCTIONS.get(funcStr); + BiFunction func = FUNCTIONS.get(funcStr); IVariable parsedArg = resolveStringFunctions(level, arg, c); - return c.cache(curr, func.apply(parsedArg)); + return c.cache(curr, func.apply(parsedArg, level.registryAccess())); } else { throw new IllegalArgumentException("Invalid Function " + funcStr); } @@ -143,35 +142,35 @@ private static IVariable resolveStringVar(Level level, String original, Context return IVariable.wrap(curr); } - private static UnaryOperator wrapStringFunc(Function inner) { - return x -> IVariable.wrap(inner.apply(x.asString())); + private static BiFunction wrapStringFunc(Function inner) { + return (x, r) -> IVariable.wrap(inner.apply(x.asString())); } - private static IVariable iname(IVariable arg) { + private static IVariable iname(IVariable arg, HolderLookup.Provider registries) { ItemStack stack = arg.as(ItemStack.class); return IVariable.wrap(stack.getHoverName().getString()); } - private static IVariable icount(IVariable arg) { + private static IVariable icount(IVariable arg, HolderLookup.Provider registries) { ItemStack stack = arg.as(ItemStack.class); return IVariable.wrap(stack.getCount()); } - private static IVariable exists(IVariable arg) { + private static IVariable exists(IVariable arg, HolderLookup.Provider registries) { return IVariable.wrap(!arg.unwrap().isJsonNull()); } - private static IVariable iexists(IVariable arg) { + private static IVariable iexists(IVariable arg, HolderLookup.Provider registries) { ItemStack stack = arg.as(ItemStack.class); return IVariable.wrap(stack != null && !stack.isEmpty()); } - private static IVariable inv(IVariable arg) { + private static IVariable inv(IVariable arg, HolderLookup.Provider registries) { return IVariable.wrap(!arg.unwrap().getAsBoolean()); } - private static IVariable stacks(IVariable arg) { - return IVariable.from(arg.as(Ingredient.class).getItems(), RegistryAccess.fromRegistryOfRegistries(BuiltInRegistries.REGISTRY)); + private static IVariable stacks(IVariable arg, HolderLookup.Provider registries) { + return IVariable.from(arg.as(Ingredient.class).getItems(), registries); } private static String ename(String arg) { From 14fda7fab2bb0fdeb9b20c1e2f1ddb3688e90b82 Mon Sep 17 00:00:00 2001 From: Minecraftschurli Date: Mon, 1 Jul 2024 21:25:34 +0200 Subject: [PATCH 24/25] Update BookOpenTrigger codec --- .../patchouli/common/advancement/BookOpenTrigger.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Xplat/src/main/java/vazkii/patchouli/common/advancement/BookOpenTrigger.java b/Xplat/src/main/java/vazkii/patchouli/common/advancement/BookOpenTrigger.java index 6daac7754..e2fcda377 100644 --- a/Xplat/src/main/java/vazkii/patchouli/common/advancement/BookOpenTrigger.java +++ b/Xplat/src/main/java/vazkii/patchouli/common/advancement/BookOpenTrigger.java @@ -6,7 +6,6 @@ import net.minecraft.advancements.critereon.*; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerPlayer; -import net.minecraft.util.ExtraCodecs; import vazkii.patchouli.api.PatchouliAPI; @@ -39,10 +38,10 @@ public void trigger(@NotNull ServerPlayer player, @NotNull ResourceLocation book public record TriggerInstance(Optional player, ResourceLocation book, Optional entry, MinMaxBounds.Ints page) implements SimpleInstance { public static Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( - ExtraCodecs.strictOptionalField(EntityPredicate.ADVANCEMENT_CODEC, "player").forGetter(TriggerInstance::player), + EntityPredicate.ADVANCEMENT_CODEC.optionalFieldOf("player").forGetter(TriggerInstance::player), ResourceLocation.CODEC.fieldOf("book").forGetter(TriggerInstance::book), - ExtraCodecs.strictOptionalField(ResourceLocation.CODEC, "entry").forGetter(TriggerInstance::entry), - ExtraCodecs.strictOptionalField(MinMaxBounds.Ints.CODEC, "page", MinMaxBounds.Ints.ANY).forGetter(TriggerInstance::page) + ResourceLocation.CODEC.optionalFieldOf("entry").forGetter(TriggerInstance::entry), + MinMaxBounds.Ints.CODEC.optionalFieldOf("page", MinMaxBounds.Ints.ANY).forGetter(TriggerInstance::page) ).apply(instance, TriggerInstance::new)); public boolean matches(@NotNull ResourceLocation book, @Nullable ResourceLocation entry, int page) { From 9071f412f7c8d473d8f1c10945109cc7e973d3f2 Mon Sep 17 00:00:00 2001 From: Minecraftschurli Date: Mon, 1 Jul 2024 21:42:49 +0200 Subject: [PATCH 25/25] Spotless apply --- .../patchouli/neoforge/common/NeoForgeModInitializer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/NeoForge/src/main/java/vazkii/patchouli/neoforge/common/NeoForgeModInitializer.java b/NeoForge/src/main/java/vazkii/patchouli/neoforge/common/NeoForgeModInitializer.java index 363d2137e..4a8b5c458 100644 --- a/NeoForge/src/main/java/vazkii/patchouli/neoforge/common/NeoForgeModInitializer.java +++ b/NeoForge/src/main/java/vazkii/patchouli/neoforge/common/NeoForgeModInitializer.java @@ -51,8 +51,8 @@ public static void register(RegisterEvent evt) { evt.register(Registries.ITEM, rh -> { PatchouliItems.submitItemRegistrations(rh::register); }); - evt.register(Registries.TRIGGER_TYPE, rh -> PatchouliCriteriaTriggers.submitTriggerRegistrations(rh::register)); - } + evt.register(Registries.TRIGGER_TYPE, rh -> PatchouliCriteriaTriggers.submitTriggerRegistrations(rh::register)); + } @SubscribeEvent public static void processCreativeTabs(BuildCreativeModeTabContentsEvent evt) {