From 89b0c0d63f50a89654b626a7996eb2144ae40451 Mon Sep 17 00:00:00 2001 From: thedarkcolour <30441001+thedarkcolour@users.noreply.github.com> Date: Tue, 14 Nov 2023 00:07:01 -0800 Subject: [PATCH] Ex Deorum 1.9 --- build.gradle | 2 +- changelog.md | 6 +++ .../exdeorum/client/ClientHandler.java | 21 ++++++++- .../exdeorum/event/ClientsideCode.java | 30 ++++++++++++ .../exdeorum/event/EventHandler.java | 47 +++++++++++++++++-- .../exdeorum/item/HammerItem.java | 23 ++++++--- .../network/ClientMessageHandler.java | 7 +++ .../exdeorum/network/NetworkHandler.java | 5 ++ .../exdeorum/network/PlayerDataMessage.java | 36 ++++++++++++++ .../exdeorum/recipe/RecipeUtil.java | 14 ++++++ src/main/resources/coremods.js | 2 +- 11 files changed, 180 insertions(+), 13 deletions(-) create mode 100644 src/main/java/thedarkcolour/exdeorum/event/ClientsideCode.java create mode 100644 src/main/java/thedarkcolour/exdeorum/network/PlayerDataMessage.java diff --git a/build.gradle b/build.gradle index 454dbe86..4560ae5f 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ plugins { id 'org.spongepowered.mixin' version '0.7.+' } -version = '1.8' +version = '1.9' group = 'thedarkcolour.exdeorum' base { archivesName = 'exdeorum' diff --git a/changelog.md b/changelog.md index 2dad9595..2cd2f1c7 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,9 @@ +## Ex Deorum 1.9 +- Fixed incompatibility with SkyblockBuilder where player would not receive torch/watering can and Ex Deorum advancements +- Fixed error message printing while patching the End Portal method +- Fixed several issues with hammers in LAN and server worlds +- Fixed hammer recipes with tag ingredients not functioning + ## Ex Deorum 1.8 - Added a config option to limit the number of sieve drops from sieving moss. May be useful when playing with mods that add a lot of different saplings. - Added compatibility with Ars Nouveau's saplings and Sourceberries to the sieve. diff --git a/src/main/java/thedarkcolour/exdeorum/client/ClientHandler.java b/src/main/java/thedarkcolour/exdeorum/client/ClientHandler.java index de0cac89..68bbbafa 100644 --- a/src/main/java/thedarkcolour/exdeorum/client/ClientHandler.java +++ b/src/main/java/thedarkcolour/exdeorum/client/ClientHandler.java @@ -35,6 +35,8 @@ import net.minecraftforge.client.event.RegisterClientReloadListenersEvent; import net.minecraftforge.client.event.RegisterShadersEvent; import net.minecraftforge.client.event.ScreenEvent; import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.TagsUpdatedEvent; +import net.minecraftforge.eventbus.api.Event; import net.minecraftforge.fml.event.config.ModConfigEvent; import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; @@ -45,6 +47,7 @@ import thedarkcolour.exdeorum.client.ter.InfestedLeavesRenderer; import thedarkcolour.exdeorum.client.ter.SieveRenderer; import thedarkcolour.exdeorum.config.EConfig; import thedarkcolour.exdeorum.network.ClientMessageHandler; +import thedarkcolour.exdeorum.recipe.RecipeUtil; import thedarkcolour.exdeorum.registry.EBlockEntities; import thedarkcolour.exdeorum.registry.EFluids; import thedarkcolour.exdeorum.registry.EWorldPresets; @@ -52,6 +55,8 @@ import thedarkcolour.exdeorum.registry.EWorldPresets; import java.io.IOException; public class ClientHandler { + public static boolean needsRecipeCacheRefresh; + public static void register() { var modBus = FMLJavaModLoadingContext.get().getModEventBus(); var fmlBus = MinecraftForge.EVENT_BUS; @@ -60,10 +65,18 @@ public class ClientHandler { modBus.addListener(ClientHandler::registerRenderers); modBus.addListener(ClientHandler::registerShaders); modBus.addListener(ClientHandler::addClientReloadListeners); + modBus.addListener(ClientHandler::onConfigChanged); fmlBus.addListener(ClientHandler::onPlayerRespawn); fmlBus.addListener(ClientHandler::onPlayerLogout); - modBus.addListener(ClientHandler::onConfigChanged); fmlBus.addListener(ClientHandler::onScreenOpen); + fmlBus.addListener(ClientHandler::onTagsUpdated); + } + + private static void onTagsUpdated(TagsUpdatedEvent event) { + if (needsRecipeCacheRefresh && Minecraft.getInstance().getConnection() != null) { + RecipeUtil.reload(Minecraft.getInstance().getConnection().getRecipeManager()); + needsRecipeCacheRefresh = false; + } } private static void addClientReloadListeners(RegisterClientReloadListenersEvent event) { @@ -84,6 +97,12 @@ public class ClientHandler { private static void onPlayerLogout(ClientPlayerNetworkEvent.LoggingOut event) { ClientMessageHandler.isInVoidWorld = false; + needsRecipeCacheRefresh = false; + + // Only null when logging in + if (Minecraft.getInstance().level != null) { + RecipeUtil.unload(); + } } private static void onConfigChanged(ModConfigEvent.Reloading event) { diff --git a/src/main/java/thedarkcolour/exdeorum/event/ClientsideCode.java b/src/main/java/thedarkcolour/exdeorum/event/ClientsideCode.java new file mode 100644 index 00000000..f8f48f2a --- /dev/null +++ b/src/main/java/thedarkcolour/exdeorum/event/ClientsideCode.java @@ -0,0 +1,30 @@ +/* + * Ex Deorum + * Copyright (c) 2023 thedarkcolour + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package thedarkcolour.exdeorum.event; + +import net.minecraft.client.Minecraft; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.Level; + +// necessary to avoid EventBus loading LocalPlayer through its ASM transformations +class ClientsideCode { + static Player getLocalPlayer() { + return Minecraft.getInstance().player; + } +} diff --git a/src/main/java/thedarkcolour/exdeorum/event/EventHandler.java b/src/main/java/thedarkcolour/exdeorum/event/EventHandler.java index 89712b97..16dfa8cd 100644 --- a/src/main/java/thedarkcolour/exdeorum/event/EventHandler.java +++ b/src/main/java/thedarkcolour/exdeorum/event/EventHandler.java @@ -29,6 +29,7 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.util.Unit; +import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.world.level.GameRules; @@ -36,18 +37,23 @@ import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.level.levelgen.XoroshiroRandomSource; import net.minecraft.world.level.levelgen.feature.ConfiguredFeature; +import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.client.event.ClientChatEvent; import net.minecraftforge.common.ForgeMod; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.AddReloadListenerEvent; +import net.minecraftforge.event.OnDatapackSyncEvent; import net.minecraftforge.event.entity.player.PlayerEvent; import net.minecraftforge.event.level.LevelEvent; import net.minecraftforge.fluids.FluidInteractionRegistry; +import net.minecraftforge.fml.DistExecutor; import net.minecraftforge.fml.InterModComms; import net.minecraftforge.fml.ModList; import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; import net.minecraftforge.fml.event.lifecycle.InterModEnqueueEvent; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import net.minecraftforge.fml.loading.FMLEnvironment; +import org.jetbrains.annotations.Nullable; import thedarkcolour.exdeorum.ExDeorum; import thedarkcolour.exdeorum.blockentity.LavaCrucibleBlockEntity; import thedarkcolour.exdeorum.client.CompostColors; @@ -56,6 +62,7 @@ import thedarkcolour.exdeorum.compat.top.ExDeorumTopCompat; import thedarkcolour.exdeorum.config.EConfig; import thedarkcolour.exdeorum.item.HammerItem; import thedarkcolour.exdeorum.item.WateringCanItem; +import thedarkcolour.exdeorum.network.ClientMessageHandler; import thedarkcolour.exdeorum.network.NetworkHandler; import thedarkcolour.exdeorum.recipe.RecipeUtil; import thedarkcolour.exdeorum.registry.EFluids; @@ -63,15 +70,21 @@ import thedarkcolour.exdeorum.registry.EItems; import thedarkcolour.exdeorum.tag.EBiomeTags; import thedarkcolour.exdeorum.voidworld.VoidChunkGenerator; +import java.util.HashSet; +import java.util.Locale; +import java.util.Set; +import java.util.UUID; + public final class EventHandler { public static void register() { var fmlBus = MinecraftForge.EVENT_BUS; var modBus = FMLJavaModLoadingContext.get().getModEventBus(); fmlBus.addListener(EventHandler::onPlayerLogin); + fmlBus.addListener(EventHandler::onDataSynced); fmlBus.addListener(EventHandler::addReloadListeners); - modBus.addListener(EventHandler::interModEnqueue); fmlBus.addListener(EventHandler::createSpawnTree); + modBus.addListener(EventHandler::interModEnqueue); modBus.addListener(EventHandler::onCommonSetup); if (ExDeorum.DEBUG) { @@ -154,9 +167,38 @@ public final class EventHandler { }); } + private static void onDataSynced(OnDatapackSyncEvent event) { + UUID excludedUUID = null; + + if (FMLEnvironment.dist == Dist.CLIENT) { + // since event code is turned into ASM, we need this to prevent ASM trying to load the LocalPlayer class + Player player = DistExecutor.unsafeCallWhenOn(Dist.CLIENT, () -> ClientsideCode::getLocalPlayer);; + if (player == null) { + return; + } else { + excludedUUID = player.getUUID(); + } + } + + // A player who is first connecting isn't yet included in the server's player list, so include them. + Set players = new HashSet<>(event.getPlayerList().getPlayers()); + if (event.getPlayer() != null) { + players.add(event.getPlayer()); + } + + for (var player : players) { + if (!player.getUUID().equals(excludedUUID)) { + NetworkHandler.sendRecipeCacheReset(player); + } + } + } + private static void onPlayerLogin(PlayerEvent.PlayerLoggedInEvent event) { if (event.getEntity() instanceof ServerPlayer player) { - if (player.serverLevel().getChunkSource().getGenerator() instanceof VoidChunkGenerator) { + var generator = player.serverLevel().getChunkSource().getGenerator(); + + // tries to account for other SkyBlock generator mods like SkyBlockBuilder + if (generator instanceof VoidChunkGenerator || generator.getClass().getName().toLowerCase(Locale.ROOT).contains("skyblock")) { NetworkHandler.sendVoidWorld(player); var advancement = player.server.getAdvancements().getAdvancement(new ResourceLocation(ExDeorum.ID, "core/root")); @@ -188,7 +230,6 @@ public final class EventHandler { var recipes = event.getServerResources().getRecipeManager(); event.addListener((prepBarrier, resourceManager, prepProfiler, reloadProfiler, backgroundExecutor, gameExecutor) -> { return prepBarrier.wait(Unit.INSTANCE).thenRunAsync(() -> { - HammerItem.refreshValidBlocks(recipes); RecipeUtil.reload(recipes); LavaCrucibleBlockEntity.putDefaultHeatValues(); }, gameExecutor); diff --git a/src/main/java/thedarkcolour/exdeorum/item/HammerItem.java b/src/main/java/thedarkcolour/exdeorum/item/HammerItem.java index 49a41ff5..21055a26 100644 --- a/src/main/java/thedarkcolour/exdeorum/item/HammerItem.java +++ b/src/main/java/thedarkcolour/exdeorum/item/HammerItem.java @@ -28,32 +28,41 @@ import net.minecraft.world.item.crafting.RecipeManager; import net.minecraft.world.item.crafting.RecipeType; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.common.util.Lazy; import org.jetbrains.annotations.Nullable; +import thedarkcolour.exdeorum.recipe.RecipeUtil; import thedarkcolour.exdeorum.registry.EItems; -import thedarkcolour.exdeorum.registry.ERecipeTypes; import java.util.Set; public class HammerItem extends DiggerItem { - public static final Set VALID_BLOCKS = new ObjectOpenHashSet<>(); + public static Lazy> validBlocks = Lazy.of(HammerItem::computeValidBlocks); public HammerItem(Tier tier, Properties properties) { super(1.0f, -2.8f, tier, null, properties); } - public static void refreshValidBlocks(RecipeManager recipes) { - VALID_BLOCKS.clear(); - for (var recipe : recipes.byType(ERecipeTypes.HAMMER.get()).values()) { + public static Set computeValidBlocks() { + var hammerRecipes = RecipeUtil.getCachedHammerRecipes(); + var validBlocks = new ObjectOpenHashSet(hammerRecipes.size()); + + for (var recipe : hammerRecipes) { for (var item : recipe.getIngredient().getItems()) { if (item.getItem() instanceof BlockItem blockItem) { - VALID_BLOCKS.add(blockItem.getBlock()); + validBlocks.add(blockItem.getBlock()); } } } + + return validBlocks; + } + + public static void refreshValidBlocks(RecipeManager recipes) { + validBlocks = Lazy.of(HammerItem::computeValidBlocks); } protected Set getValidBlocks() { - return VALID_BLOCKS; + return validBlocks.get(); } @Override diff --git a/src/main/java/thedarkcolour/exdeorum/network/ClientMessageHandler.java b/src/main/java/thedarkcolour/exdeorum/network/ClientMessageHandler.java index e0370c60..6fdbffd8 100644 --- a/src/main/java/thedarkcolour/exdeorum/network/ClientMessageHandler.java +++ b/src/main/java/thedarkcolour/exdeorum/network/ClientMessageHandler.java @@ -19,6 +19,8 @@ package thedarkcolour.exdeorum.network; import net.minecraft.client.Minecraft; +import thedarkcolour.exdeorum.client.ClientHandler; +import thedarkcolour.exdeorum.recipe.RecipeUtil; public class ClientMessageHandler { public static boolean isInVoidWorld; @@ -32,4 +34,9 @@ public class ClientMessageHandler { level.clientLevelData.isFlat = true; } } + + public static void reloadClientRecipeCache() { + //RecipeUtil.reload(Minecraft.getInstance().level.getRecipeManager()); + ClientHandler.needsRecipeCacheRefresh = true; + } } diff --git a/src/main/java/thedarkcolour/exdeorum/network/NetworkHandler.java b/src/main/java/thedarkcolour/exdeorum/network/NetworkHandler.java index 5491075d..077d5799 100644 --- a/src/main/java/thedarkcolour/exdeorum/network/NetworkHandler.java +++ b/src/main/java/thedarkcolour/exdeorum/network/NetworkHandler.java @@ -35,12 +35,17 @@ public final class NetworkHandler { public static void register() { CHANNEL.registerMessage(0, VoidWorldMessage.class, VoidWorldMessage::encode, VoidWorldMessage::decode, VoidWorldMessage::handle); + CHANNEL.registerMessage(1, PlayerDataMessage.class, (msg, buffer) -> {}, buffer -> new PlayerDataMessage(), PlayerDataMessage::handle); } public static void sendVoidWorld(ServerPlayer pPlayer) { CHANNEL.sendTo(new VoidWorldMessage(), pPlayer.connection.connection, NetworkDirection.PLAY_TO_CLIENT); } + public static void sendRecipeCacheReset(ServerPlayer player) { + CHANNEL.sendTo(new PlayerDataMessage(), player.connection.connection, NetworkDirection.PLAY_TO_CLIENT); + } + static void handle(Supplier ctxSupplier, Consumer handler) { var ctx = ctxSupplier.get(); ctx.enqueueWork(() -> handler.accept(ctx)); diff --git a/src/main/java/thedarkcolour/exdeorum/network/PlayerDataMessage.java b/src/main/java/thedarkcolour/exdeorum/network/PlayerDataMessage.java new file mode 100644 index 00000000..f9be33c7 --- /dev/null +++ b/src/main/java/thedarkcolour/exdeorum/network/PlayerDataMessage.java @@ -0,0 +1,36 @@ +/* + * Ex Deorum + * Copyright (c) 2023 thedarkcolour + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package thedarkcolour.exdeorum.network; + +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.fml.DistExecutor; +import net.minecraftforge.network.NetworkEvent; + +import java.util.function.Supplier; + +// Server -> Client +// Fired whenever a player joins an LAN world or dedicated server to load the recipe caches +// Also fired whenever those servers reload data +public class PlayerDataMessage { + public void handle(Supplier ctxSupplier) { + NetworkHandler.handle(ctxSupplier, ctx -> { + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> ClientMessageHandler::reloadClientRecipeCache); + }); + } +} diff --git a/src/main/java/thedarkcolour/exdeorum/recipe/RecipeUtil.java b/src/main/java/thedarkcolour/exdeorum/recipe/RecipeUtil.java index 82c2d998..dfa4abfd 100644 --- a/src/main/java/thedarkcolour/exdeorum/recipe/RecipeUtil.java +++ b/src/main/java/thedarkcolour/exdeorum/recipe/RecipeUtil.java @@ -47,6 +47,7 @@ import net.minecraftforge.common.util.Lazy; import net.minecraftforge.fluids.FluidStack; import org.jetbrains.annotations.Nullable; import thedarkcolour.exdeorum.compat.PreferredOres; +import thedarkcolour.exdeorum.item.HammerItem; import thedarkcolour.exdeorum.recipe.barrel.BarrelCompostRecipe; import thedarkcolour.exdeorum.recipe.barrel.BarrelMixingRecipe; import thedarkcolour.exdeorum.recipe.crucible.CrucibleRecipe; @@ -77,6 +78,15 @@ public final class RecipeUtil { lavaCrucibleRecipeCache = loadSimpleRecipeCache(recipes, ERecipeTypes.LAVA_CRUCIBLE); waterCrucibleRecipeCache = loadSimpleRecipeCache(recipes, ERecipeTypes.WATER_CRUCIBLE); hammerRecipeCache = loadSimpleRecipeCache(recipes, ERecipeTypes.HAMMER); + HammerItem.refreshValidBlocks(recipes); + } + + public static void unload() { + SIEVE_RECIPE_CACHE.invalidateAll(); + barrelCompostRecipeCache = null; + lavaCrucibleRecipeCache = null; + waterCrucibleRecipeCache = null; + hammerRecipeCache = null; } private static Lazy> loadSimpleRecipeCache(RecipeManager recipes, Supplier> recipeType) { @@ -138,6 +148,10 @@ public final class RecipeUtil { return hammerRecipeCache.get().get(playerItem); } + public static Collection getCachedHammerRecipes() { + return hammerRecipeCache.get().values(); + } + public static > Collection byType(RecipeManager manager, RecipeType type) { return manager.byType(type).values(); } diff --git a/src/main/resources/coremods.js b/src/main/resources/coremods.js index 2fc897dc..503e3dac 100644 --- a/src/main/resources/coremods.js +++ b/src/main/resources/coremods.js @@ -107,7 +107,7 @@ function initializeCoreMod() { new FieldInsnNode(Opcodes.PUTFIELD, insn.owner, insn.name, insn.desc) )); - ASMAPI.log('INFO', 'The node we are patching at: { opcode: ' + insn.getOpcode() + ', name: ' + insn.getName()); + ASMAPI.log('INFO', 'The node we are patching at: { opcode: ' + insn.getOpcode() + ', name: ' + insn.name); ASMAPI.log('INFO', 'Successfully patched end portal.'); return method;