From 5e81a49dc8d660a347efe148c4aec4c44cdaac98 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Fri, 24 Mar 2023 10:50:47 -0400 Subject: [PATCH 01/25] Don't use cached server resources if they got closed somehow Related: #46 --- .../perf/reuse_datapacks/MinecraftMixin.java | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/reuse_datapacks/MinecraftMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/reuse_datapacks/MinecraftMixin.java index 461633f5..71c0f439 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/reuse_datapacks/MinecraftMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/reuse_datapacks/MinecraftMixin.java @@ -37,16 +37,21 @@ public class MinecraftMixin implements ICachingResourceClient { @Redirect(method = "makeServerStem", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/ServerResources;loadResources(Ljava/util/List;Lnet/minecraft/commands/Commands$CommandSelection;ILjava/util/concurrent/Executor;Ljava/util/concurrent/Executor;)Ljava/util/concurrent/CompletableFuture;")) private CompletableFuture useCachedResources(List list, Commands.CommandSelection arg, int i, Executor executor, Executor executor2) { if(cachedResources != null) { - if(cachedDataPackConfig.equals(loadingDataPackConfig)) { - ModernFix.LOGGER.warn("Reusing loaded server resources from previous world"); - return CompletableFuture.completedFuture(cachedResources); + if(cachedResources.getResourceManager().getNamespaces().size() > 0) { + if (cachedDataPackConfig.equals(loadingDataPackConfig)) { + ModernFix.LOGGER.warn("Reusing loaded server resources from previous world"); + return CompletableFuture.completedFuture(cachedResources); + } else { + ModernFix.LOGGER.warn("Discarding cached server resources, datapack configs have changed"); + ModernFix.LOGGER.warn("Old: {}", "[" + String.join(", ", cachedDataPackConfig) + "]"); + ModernFix.LOGGER.warn("New: {}", "[" + String.join(", ", loadingDataPackConfig) + "]"); + cachedResources.close(); + cachedResources = null; + cachedDataPackConfig = null; + } } else { - ModernFix.LOGGER.warn("Discarding cached server resources, datapack configs have changed"); - ModernFix.LOGGER.warn("Old: {}", "[" + String.join(", ", cachedDataPackConfig) + "]"); - ModernFix.LOGGER.warn("New: {}", "[" + String.join(", ", loadingDataPackConfig) + "]"); - cachedResources.close(); + ModernFix.LOGGER.error("Cached server resources were closed somehow, that shouldn't happen"); cachedResources = null; - cachedDataPackConfig = null; } } return ServerResources.loadResources(list, arg, i, executor, executor2); From c37d91e476be0f39abe3aa4cb7a8abad9a781804 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sun, 26 Mar 2023 09:17:03 -0400 Subject: [PATCH 02/25] Avoid fetching key state on background threads --- .../perf/async_jei/InputConstantsMixin.java | 19 +++++++++++++++++++ src/main/resources/modernfix.mixins.json | 1 + 2 files changed, 20 insertions(+) create mode 100644 src/main/java/org/embeddedt/modernfix/mixin/perf/async_jei/InputConstantsMixin.java diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/async_jei/InputConstantsMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/async_jei/InputConstantsMixin.java new file mode 100644 index 00000000..add53d70 --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/async_jei/InputConstantsMixin.java @@ -0,0 +1,19 @@ +package org.embeddedt.modernfix.mixin.perf.async_jei; + +import com.mojang.blaze3d.platform.InputConstants; +import com.mojang.blaze3d.systems.RenderSystem; +import org.lwjgl.glfw.GLFW; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(InputConstants.class) +public class InputConstantsMixin { + @Redirect(method = "isKeyDown", at = @At(value = "INVOKE", target = "Lorg/lwjgl/glfw/GLFW;glfwGetKey(JI)I")) + private static int offThreadKeyFetch(long win, int k) { + if(RenderSystem.isOnRenderThreadOrInit()) + return GLFW.glfwGetKey(win, k); + else + return 0; + } +} diff --git a/src/main/resources/modernfix.mixins.json b/src/main/resources/modernfix.mixins.json index f90ed5ce..9833178c 100644 --- a/src/main/resources/modernfix.mixins.json +++ b/src/main/resources/modernfix.mixins.json @@ -73,6 +73,7 @@ "perf.parallelize_model_loading.TransformationMatrixMixin", "perf.parallelize_model_loading.BooleanPropertyMixin", "perf.parallelize_model_loading.PropertyMixin", + "perf.async_jei.InputConstantsMixin", "perf.async_jei.IngredientListElementFactoryMixin", "perf.async_jei.ClientLifecycleHandlerMixin", "perf.async_jei.JeiStarterMixin", From f8d17ba3abe6b4216838e99f3488440f16b1353f Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sun, 26 Mar 2023 15:25:17 -0400 Subject: [PATCH 03/25] Disable datapack reload elision if TaC is installed Related: #46 --- .../embeddedt/modernfix/core/config/ModernFixEarlyConfig.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java b/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java index 707ff38f..9511bea7 100644 --- a/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java +++ b/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java @@ -69,6 +69,7 @@ public class ModernFixEarlyConfig { disableIfModPresent("mixin.perf.compress_biome_container", "chocolate", "betterendforge"); disableIfModPresent("mixin.bugfix.mc218112", "performant"); disableIfModPresent("mixin.perf.faster_baking", "touhou_little_maid"); + disableIfModPresent("mixin.perf.reuse_datapacks", "tac"); } private void disableIfModPresent(String configName, String... ids) { From b3449a2d638dc31d45fd64ab54308cebd94d262b Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sun, 26 Mar 2023 18:20:47 -0400 Subject: [PATCH 04/25] Disable resource finder log --- .../modernfix/classloading/ModernFixResourceFinder.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/embeddedt/modernfix/classloading/ModernFixResourceFinder.java b/src/main/java/org/embeddedt/modernfix/classloading/ModernFixResourceFinder.java index 58ddf9d6..432ede05 100644 --- a/src/main/java/org/embeddedt/modernfix/classloading/ModernFixResourceFinder.java +++ b/src/main/java/org/embeddedt/modernfix/classloading/ModernFixResourceFinder.java @@ -37,7 +37,7 @@ public class ModernFixResourceFinder { } public static synchronized void init() throws ReflectiveOperationException { urlsForClass = new HashMap<>(); - LOGGER.info("Start building list of class locations..."); + //LOGGER.info("Start building list of class locations..."); for(ModFileInfo fileInfo : LoadingModList.get().getModFiles()) { ModFile file = fileInfo.getFile(); IModLocator locator = file.getLocator(); @@ -77,7 +77,7 @@ public class ModernFixResourceFinder { if(list instanceof ArrayList) ((ArrayList)list).trimToSize(); } - LOGGER.info("Finish building"); + //LOGGER.info("Finish building"); } private static Iterable getRootPathForLocator(IModLocator locator, ModFile file) throws ReflectiveOperationException { From bb9201c58c00a5296e40f08493916597132a2a06 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sun, 26 Mar 2023 18:20:57 -0400 Subject: [PATCH 05/25] Add some mixins to speed up dev time --- .../core/config/ModernFixEarlyConfig.java | 3 +++ .../mixin/devenv/MinecraftMixin.java | 17 +++++++++++++++ .../mixin/devenv/MinecraftServerMixin.java | 21 +++++++++++++++++++ .../modernfix/mixin/devenv/NarratorMixin.java | 16 ++++++++++++++ src/main/resources/modernfix.mixins.json | 7 +++++-- 5 files changed, 62 insertions(+), 2 deletions(-) create mode 100644 src/main/java/org/embeddedt/modernfix/mixin/devenv/MinecraftMixin.java create mode 100644 src/main/java/org/embeddedt/modernfix/mixin/devenv/MinecraftServerMixin.java create mode 100644 src/main/java/org/embeddedt/modernfix/mixin/devenv/NarratorMixin.java diff --git a/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java b/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java index 9511bea7..e8ece824 100644 --- a/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java +++ b/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java @@ -1,6 +1,7 @@ package org.embeddedt.modernfix.core.config; import net.minecraftforge.fml.loading.FMLLoader; +import net.minecraftforge.fml.loading.moddiscovery.ExplodedDirectoryLocator; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -62,6 +63,8 @@ public class ModernFixEarlyConfig { this.addMixinRule("safety", true); this.addMixinRule("launch.transformer_cache", false); this.addMixinRule("launch.class_search_cache", true); + boolean isDevEnv = !FMLLoader.isProduction() && FMLLoader.getLoadingModList().getModFileById("modernfix").getFile().getLocator() instanceof ExplodedDirectoryLocator; + this.addMixinRule("devenv", isDevEnv); /* Mod compat */ disableIfModPresent("mixin.perf.thread_priorities", "smoothboot"); diff --git a/src/main/java/org/embeddedt/modernfix/mixin/devenv/MinecraftMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/devenv/MinecraftMixin.java new file mode 100644 index 00000000..e4e90f44 --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/devenv/MinecraftMixin.java @@ -0,0 +1,17 @@ +package org.embeddedt.modernfix.mixin.devenv; + +import com.mojang.authlib.minecraft.OfflineSocialInteractions; +import com.mojang.authlib.minecraft.SocialInteractionsService; +import net.minecraft.client.Minecraft; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(Minecraft.class) +public class MinecraftMixin { + @Inject(method = "createSocialInteractions", at = @At("HEAD"), cancellable = true) + private void noSocialInteraction(CallbackInfoReturnable cir) { + cir.setReturnValue(new OfflineSocialInteractions()); + } +} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/devenv/MinecraftServerMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/devenv/MinecraftServerMixin.java new file mode 100644 index 00000000..176ac2c6 --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/devenv/MinecraftServerMixin.java @@ -0,0 +1,21 @@ +package org.embeddedt.modernfix.mixin.devenv; + +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerChunkCache; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +/* Disable waiting for spawn chunk load */ +@Mixin(MinecraftServer.class) +public class MinecraftServerMixin { + @Redirect(method = "prepareLevels", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerChunkCache;getTickingGenerated()I")) + private int noSpawnChunkWait(ServerChunkCache cache) { + return 441; + } + + @Redirect(method = "prepareLevels", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/MinecraftServer;waitUntilNextTick()V")) + private void noWaitTick(MinecraftServer server) { + + } +} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/devenv/NarratorMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/devenv/NarratorMixin.java new file mode 100644 index 00000000..6c0754ae --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/devenv/NarratorMixin.java @@ -0,0 +1,16 @@ +package org.embeddedt.modernfix.mixin.devenv; + +import com.mojang.text2speech.Narrator; +import com.mojang.text2speech.NarratorDummy; +import net.minecraft.client.gui.chat.NarratorChatListener; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(NarratorChatListener.class) +public class NarratorMixin { + @Redirect(method = "", at = @At(value = "INVOKE", target = "Lcom/mojang/text2speech/Narrator;getNarrator()Lcom/mojang/text2speech/Narrator;")) + private Narrator useDummyNarrator() { + return new NarratorDummy(); + } +} diff --git a/src/main/resources/modernfix.mixins.json b/src/main/resources/modernfix.mixins.json index 9833178c..a6f0380a 100644 --- a/src/main/resources/modernfix.mixins.json +++ b/src/main/resources/modernfix.mixins.json @@ -53,7 +53,8 @@ "perf.fast_registry_validation.ForgeRegistryMixin", "perf.cache_strongholds.ChunkGeneratorMixin", "perf.cache_upgraded_structures.StructureManagerMixin", - "perf.cache_strongholds.ServerLevelMixin" + "perf.cache_strongholds.ServerLevelMixin", + "devenv.MinecraftServerMixin", ], "client": [ "core.MinecraftMixin", @@ -100,7 +101,9 @@ "perf.use_integrated_resources.PiglinBarteringRecipeBuilderMixin", "perf.jeresources_startup.VillagerEntryMixin", "bugfix.mc218112.SynchedEntityDataMixin_Client", - "perf.faster_singleplayer_load.MinecraftServerMixin" + "perf.faster_singleplayer_load.MinecraftServerMixin", + "devenv.MinecraftMixin", + "devenv.NarratorMixin" ], "injectors": { "defaultRequire": 1 From 304fd059556bc3596fbf180d3e0b5ea96b9ed061 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sun, 26 Mar 2023 19:30:10 -0400 Subject: [PATCH 06/25] Clean up log messages --- .../core/config/ModernFixEarlyConfig.java | 17 +++++++++++------ .../PiglinBarteringRecipeBuilderMixin.java | 2 +- .../{ => jeresources}/LootTableHelperMixin.java | 2 +- src/main/resources/modernfix.mixins.json | 4 ++-- 4 files changed, 15 insertions(+), 10 deletions(-) rename src/main/java/org/embeddedt/modernfix/mixin/perf/use_integrated_resources/{ => jepb}/PiglinBarteringRecipeBuilderMixin.java (99%) rename src/main/java/org/embeddedt/modernfix/mixin/perf/use_integrated_resources/{ => jeresources}/LootTableHelperMixin.java (98%) diff --git a/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java b/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java index e8ece824..0184c476 100644 --- a/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java +++ b/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java @@ -14,6 +14,10 @@ public class ModernFixEarlyConfig { private final Map options = new HashMap<>(); + private static boolean modPresent(String modId) { + return FMLLoader.getLoadingModList().getModFileById(modId) != null; + } + private ModernFixEarlyConfig() { // Defines the default rules which can be configured by the user or other mods. // You must manually add a rule for any new mixins not covered by an existing package rule. @@ -23,8 +27,9 @@ public class ModernFixEarlyConfig { this.addMixinRule("feature.reduce_loading_screen_freezes", false); this.addMixinRule("feature.direct_stack_trace", false); this.addMixinRule("perf.fast_registry_validation", true); - this.addMixinRule("perf.use_integrated_resources", true); - this.addMixinRule("perf.jeresources_startup", true); + this.addMixinRule("perf.use_integrated_resources.jepb", modPresent("jepb")); + this.addMixinRule("perf.use_integrated_resources.jeresources", modPresent("jeresources")); + this.addMixinRule("perf.jeresources_startup", modPresent("jeresources")); this.addMixinRule("perf.remove_biome_temperature_cache", true); this.addMixinRule("perf.resourcepacks", true); this.addMixinRule("perf.reduce_blockstate_cache_rebuilds", true); @@ -40,8 +45,8 @@ public class ModernFixEarlyConfig { this.addMixinRule("bugfix.packet_leak", false); this.addMixinRule("bugfix.structure_manager_crash", true); this.addMixinRule("bugfix.mc218112", true); - this.addMixinRule("bugfix.tf_cme_on_load", true); - this.addMixinRule("perf.async_jei", true); + this.addMixinRule("bugfix.tf_cme_on_load", modPresent("twilightforest")); + this.addMixinRule("perf.async_jei", modPresent("jei")); this.addMixinRule("perf.thread_priorities", true); this.addMixinRule("perf.preload_block_classes", false); this.addMixinRule("perf.sync_executor_sleep", true); @@ -56,10 +61,10 @@ public class ModernFixEarlyConfig { this.addMixinRule("perf.datapack_reload_exceptions", true); this.addMixinRule("perf.async_locator", true); this.addMixinRule("perf.faster_texture_stitching", true); - this.addMixinRule("perf.kubejs", true); + this.addMixinRule("perf.kubejs", modPresent("kubejs")); this.addMixinRule("perf.faster_singleplayer_load", false); /* Keep this off if JEI isn't installed to prevent breaking vanilla gameplay */ - this.addMixinRule("perf.blast_search_trees", FMLLoader.getLoadingModList().getModFileById("jei") != null); + this.addMixinRule("perf.blast_search_trees", modPresent("jei")); this.addMixinRule("safety", true); this.addMixinRule("launch.transformer_cache", false); this.addMixinRule("launch.class_search_cache", true); diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/use_integrated_resources/PiglinBarteringRecipeBuilderMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/use_integrated_resources/jepb/PiglinBarteringRecipeBuilderMixin.java similarity index 99% rename from src/main/java/org/embeddedt/modernfix/mixin/perf/use_integrated_resources/PiglinBarteringRecipeBuilderMixin.java rename to src/main/java/org/embeddedt/modernfix/mixin/perf/use_integrated_resources/jepb/PiglinBarteringRecipeBuilderMixin.java index a333fa7e..8370282e 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/use_integrated_resources/PiglinBarteringRecipeBuilderMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/use_integrated_resources/jepb/PiglinBarteringRecipeBuilderMixin.java @@ -1,4 +1,4 @@ -package org.embeddedt.modernfix.mixin.perf.use_integrated_resources; +package org.embeddedt.modernfix.mixin.perf.use_integrated_resources.jepb; import com.thenatekirby.jepb.plugin.PiglinBarteringRecipeBuilder; import net.minecraft.server.MinecraftServer; diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/use_integrated_resources/LootTableHelperMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/use_integrated_resources/jeresources/LootTableHelperMixin.java similarity index 98% rename from src/main/java/org/embeddedt/modernfix/mixin/perf/use_integrated_resources/LootTableHelperMixin.java rename to src/main/java/org/embeddedt/modernfix/mixin/perf/use_integrated_resources/jeresources/LootTableHelperMixin.java index ddfaf64b..538426ab 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/use_integrated_resources/LootTableHelperMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/use_integrated_resources/jeresources/LootTableHelperMixin.java @@ -1,4 +1,4 @@ -package org.embeddedt.modernfix.mixin.perf.use_integrated_resources; +package org.embeddedt.modernfix.mixin.perf.use_integrated_resources.jeresources; import jeresources.util.LootTableHelper; import net.minecraft.server.MinecraftServer; diff --git a/src/main/resources/modernfix.mixins.json b/src/main/resources/modernfix.mixins.json index a6f0380a..6c71335f 100644 --- a/src/main/resources/modernfix.mixins.json +++ b/src/main/resources/modernfix.mixins.json @@ -97,8 +97,8 @@ "bugfix.packet_leak.SCustomPayloadPlayPacketMixin", "perf.reuse_datapacks.MinecraftMixin", "perf.reuse_datapacks.MinecraftServerMixin", - "perf.use_integrated_resources.LootTableHelperMixin", - "perf.use_integrated_resources.PiglinBarteringRecipeBuilderMixin", + "perf.use_integrated_resources.jeresources.LootTableHelperMixin", + "perf.use_integrated_resources.jepb.PiglinBarteringRecipeBuilderMixin", "perf.jeresources_startup.VillagerEntryMixin", "bugfix.mc218112.SynchedEntityDataMixin_Client", "perf.faster_singleplayer_load.MinecraftServerMixin", From 4dd6b7641e5ae50dab39c7783c8ade91995f4937 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Fri, 7 Apr 2023 18:54:54 -0400 Subject: [PATCH 07/25] Fix https://github.com/refinedmods/refinedstorage/issues/2636 Mixin version of https://github.com/refinedmods/refinedstorage/pull/3435 --- .../core/config/ModernFixEarlyConfig.java | 1 + .../duck/rs/IFluidExternalStorageCache.java | 7 +++ .../duck/rs/IItemExternalStorageCache.java | 7 +++ .../FluidExternalStorageCacheMixin.java | 50 ++++++++++++++++++ .../te_bug/FluidExternalStorageMixin.java | 31 +++++++++++ .../FluidExternalStorageProviderMixin.java | 43 ++++++++++++++++ .../te_bug/ItemExternalStorageCacheMixin.java | 51 +++++++++++++++++++ .../te_bug/ItemExternalStorageMixin.java | 26 ++++++++++ .../ItemExternalStorageProviderMixin.java | 43 ++++++++++++++++ src/main/resources/modernfix.mixins.json | 6 +++ 10 files changed, 265 insertions(+) create mode 100644 src/main/java/org/embeddedt/modernfix/duck/rs/IFluidExternalStorageCache.java create mode 100644 src/main/java/org/embeddedt/modernfix/duck/rs/IItemExternalStorageCache.java create mode 100644 src/main/java/org/embeddedt/modernfix/mixin/bugfix/refinedstorage/te_bug/FluidExternalStorageCacheMixin.java create mode 100644 src/main/java/org/embeddedt/modernfix/mixin/bugfix/refinedstorage/te_bug/FluidExternalStorageMixin.java create mode 100644 src/main/java/org/embeddedt/modernfix/mixin/bugfix/refinedstorage/te_bug/FluidExternalStorageProviderMixin.java create mode 100644 src/main/java/org/embeddedt/modernfix/mixin/bugfix/refinedstorage/te_bug/ItemExternalStorageCacheMixin.java create mode 100644 src/main/java/org/embeddedt/modernfix/mixin/bugfix/refinedstorage/te_bug/ItemExternalStorageMixin.java create mode 100644 src/main/java/org/embeddedt/modernfix/mixin/bugfix/refinedstorage/te_bug/ItemExternalStorageProviderMixin.java diff --git a/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java b/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java index 0184c476..fc2c23d7 100644 --- a/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java +++ b/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java @@ -46,6 +46,7 @@ public class ModernFixEarlyConfig { this.addMixinRule("bugfix.structure_manager_crash", true); this.addMixinRule("bugfix.mc218112", true); this.addMixinRule("bugfix.tf_cme_on_load", modPresent("twilightforest")); + this.addMixinRule("bugfix.refinedstorage", modPresent("refinedstorage")); this.addMixinRule("perf.async_jei", modPresent("jei")); this.addMixinRule("perf.thread_priorities", true); this.addMixinRule("perf.preload_block_classes", false); diff --git a/src/main/java/org/embeddedt/modernfix/duck/rs/IFluidExternalStorageCache.java b/src/main/java/org/embeddedt/modernfix/duck/rs/IFluidExternalStorageCache.java new file mode 100644 index 00000000..87031bb2 --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/duck/rs/IFluidExternalStorageCache.java @@ -0,0 +1,7 @@ +package org.embeddedt.modernfix.duck.rs; + +import net.minecraftforge.fluids.capability.IFluidHandler; + +public interface IFluidExternalStorageCache { + boolean initCache(IFluidHandler handler); +} diff --git a/src/main/java/org/embeddedt/modernfix/duck/rs/IItemExternalStorageCache.java b/src/main/java/org/embeddedt/modernfix/duck/rs/IItemExternalStorageCache.java new file mode 100644 index 00000000..133646a2 --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/duck/rs/IItemExternalStorageCache.java @@ -0,0 +1,7 @@ +package org.embeddedt.modernfix.duck.rs; + +import net.minecraftforge.items.IItemHandler; + +public interface IItemExternalStorageCache { + boolean initCache(IItemHandler handler); +} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/bugfix/refinedstorage/te_bug/FluidExternalStorageCacheMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/bugfix/refinedstorage/te_bug/FluidExternalStorageCacheMixin.java new file mode 100644 index 00000000..98266338 --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/bugfix/refinedstorage/te_bug/FluidExternalStorageCacheMixin.java @@ -0,0 +1,50 @@ +package org.embeddedt.modernfix.mixin.bugfix.refinedstorage.te_bug; + +import com.refinedmods.refinedstorage.api.network.INetwork; +import com.refinedmods.refinedstorage.apiimpl.storage.externalstorage.FluidExternalStorageCache; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.capability.IFluidHandler; +import org.embeddedt.modernfix.duck.rs.IFluidExternalStorageCache; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.List; + +@Mixin(FluidExternalStorageCache.class) +public class FluidExternalStorageCacheMixin implements IFluidExternalStorageCache { + @Shadow(remap = false) private List cache; + + @Shadow(remap = false) private int stored; + + public boolean initCache(IFluidHandler handler) { + if (cache != null) { + return false; + } + + cache = new ArrayList<>(); + + int stored = 0; + for (int i = 0; i < handler.getTanks(); ++i) { + FluidStack stack = handler.getFluidInTank(i).copy(); + cache.add(stack); + stored += stack.getAmount(); + } + this.stored = stored; + + return true; + } + + /** + * Make sure all cache creation goes through initCache. + */ + @Inject(method = "update", at = @At(value = "FIELD", target = "Lcom/refinedmods/refinedstorage/apiimpl/storage/externalstorage/FluidExternalStorageCache;cache:Ljava/util/List;", ordinal = 0), cancellable = true, remap = false) + private void checkNullCache(INetwork network, @Nullable IFluidHandler handler, CallbackInfo ci) { + if(initCache(handler)) + ci.cancel(); + } +} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/bugfix/refinedstorage/te_bug/FluidExternalStorageMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/bugfix/refinedstorage/te_bug/FluidExternalStorageMixin.java new file mode 100644 index 00000000..3424d38d --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/bugfix/refinedstorage/te_bug/FluidExternalStorageMixin.java @@ -0,0 +1,31 @@ +package org.embeddedt.modernfix.mixin.bugfix.refinedstorage.te_bug; + +import com.refinedmods.refinedstorage.apiimpl.storage.externalstorage.FluidExternalStorage; +import com.refinedmods.refinedstorage.apiimpl.storage.externalstorage.FluidExternalStorageCache; +import com.refinedmods.refinedstorage.apiimpl.storage.externalstorage.ItemExternalStorageCache; +import net.minecraftforge.fluids.capability.IFluidHandler; +import net.minecraftforge.items.IItemHandler; +import org.embeddedt.modernfix.duck.rs.IFluidExternalStorageCache; +import org.embeddedt.modernfix.duck.rs.IItemExternalStorageCache; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import java.util.function.Supplier; + +@Mixin(FluidExternalStorage.class) +public class FluidExternalStorageMixin { + @Shadow(remap = false) + @Final + private FluidExternalStorageCache cache; + + @Redirect(method = "getStacks", at = @At(value = "INVOKE", target = "Ljava/util/function/Supplier;get()Ljava/lang/Object;"), remap = false) + private Object cacheAndGet(Supplier supplier) { + IFluidHandler handler = supplier.get(); + if(handler != null) + ((IFluidExternalStorageCache)cache).initCache(handler); + return handler; + } +} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/bugfix/refinedstorage/te_bug/FluidExternalStorageProviderMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/bugfix/refinedstorage/te_bug/FluidExternalStorageProviderMixin.java new file mode 100644 index 00000000..f89b64b7 --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/bugfix/refinedstorage/te_bug/FluidExternalStorageProviderMixin.java @@ -0,0 +1,43 @@ +package org.embeddedt.modernfix.mixin.bugfix.refinedstorage.te_bug; + +import com.refinedmods.refinedstorage.api.storage.externalstorage.IExternalStorage; +import com.refinedmods.refinedstorage.api.storage.externalstorage.IExternalStorageContext; +import com.refinedmods.refinedstorage.apiimpl.storage.externalstorage.FluidExternalStorage; +import com.refinedmods.refinedstorage.apiimpl.storage.externalstorage.FluidExternalStorageProvider; +import com.refinedmods.refinedstorage.tile.FluidInterfaceTile; +import com.refinedmods.refinedstorage.util.WorldUtils; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraftforge.fluids.FluidStack; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; + +@Mixin(FluidExternalStorageProvider.class) +public class FluidExternalStorageProviderMixin { + /** + * @author embeddedt + * @reason replace supplier in 2nd arg, no easy way of doing so without overwrite + */ + @Overwrite + public IExternalStorage provide(IExternalStorageContext context, BlockEntity blockEntity, Direction direction) { + return new FluidExternalStorage(context, () -> { + Level level = blockEntity.getLevel(); + + if (level == null) { + return null; + } + + BlockPos blockPos = blockEntity.getBlockPos(); + + if (!level.isLoaded(blockPos)) { + return null; + } + + BlockEntity currentBlockEntity = level.getBlockEntity(blockPos); + + return WorldUtils.getFluidHandler(currentBlockEntity, direction.getOpposite()); + }, blockEntity instanceof FluidInterfaceTile); + } +} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/bugfix/refinedstorage/te_bug/ItemExternalStorageCacheMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/bugfix/refinedstorage/te_bug/ItemExternalStorageCacheMixin.java new file mode 100644 index 00000000..86768652 --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/bugfix/refinedstorage/te_bug/ItemExternalStorageCacheMixin.java @@ -0,0 +1,51 @@ +package org.embeddedt.modernfix.mixin.bugfix.refinedstorage.te_bug; + +import com.refinedmods.refinedstorage.api.network.INetwork; +import com.refinedmods.refinedstorage.apiimpl.storage.externalstorage.ItemExternalStorageCache; +import net.minecraft.world.item.ItemStack; +import net.minecraftforge.fluids.capability.IFluidHandler; +import net.minecraftforge.items.IItemHandler; +import org.embeddedt.modernfix.duck.rs.IItemExternalStorageCache; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.List; + +@Mixin(ItemExternalStorageCache.class) +public class ItemExternalStorageCacheMixin implements IItemExternalStorageCache { + @Shadow(remap = false) private List cache; + + @Shadow(remap = false) private int stored; + + public boolean initCache(IItemHandler handler) { + if (cache != null) { + return false; + } + + cache = new ArrayList<>(); + + int stored = 0; + for (int i = 0; i < handler.getSlots(); ++i) { + ItemStack stack = handler.getStackInSlot(i).copy(); + cache.add(stack); + stored += stack.getCount(); + } + this.stored = stored; + + return true; + } + + /** + * Make sure all cache creation goes through initCache. + */ + @Inject(method = "update", at = @At(value = "FIELD", remap = false, target = "Lcom/refinedmods/refinedstorage/apiimpl/storage/externalstorage/ItemExternalStorageCache;cache:Ljava/util/List;", ordinal = 0), cancellable = true, remap = false) + private void checkNullCache(INetwork network, @Nullable IItemHandler handler, CallbackInfo ci) { + if(initCache(handler)) + ci.cancel(); + } +} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/bugfix/refinedstorage/te_bug/ItemExternalStorageMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/bugfix/refinedstorage/te_bug/ItemExternalStorageMixin.java new file mode 100644 index 00000000..31489225 --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/bugfix/refinedstorage/te_bug/ItemExternalStorageMixin.java @@ -0,0 +1,26 @@ +package org.embeddedt.modernfix.mixin.bugfix.refinedstorage.te_bug; + +import com.refinedmods.refinedstorage.apiimpl.storage.externalstorage.ItemExternalStorage; +import com.refinedmods.refinedstorage.apiimpl.storage.externalstorage.ItemExternalStorageCache; +import net.minecraftforge.items.IItemHandler; +import org.embeddedt.modernfix.duck.rs.IItemExternalStorageCache; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import java.util.function.Supplier; + +@Mixin(ItemExternalStorage.class) +public class ItemExternalStorageMixin { + @Shadow(remap = false) @Final private ItemExternalStorageCache cache; + + @Redirect(method = "getStacks", at = @At(value = "INVOKE", target = "Ljava/util/function/Supplier;get()Ljava/lang/Object;"), remap = false) + private Object cacheAndGet(Supplier supplier) { + IItemHandler handler = supplier.get(); + if(handler != null) + ((IItemExternalStorageCache)cache).initCache(handler); + return handler; + } +} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/bugfix/refinedstorage/te_bug/ItemExternalStorageProviderMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/bugfix/refinedstorage/te_bug/ItemExternalStorageProviderMixin.java new file mode 100644 index 00000000..a8664075 --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/bugfix/refinedstorage/te_bug/ItemExternalStorageProviderMixin.java @@ -0,0 +1,43 @@ +package org.embeddedt.modernfix.mixin.bugfix.refinedstorage.te_bug; + +import com.refinedmods.refinedstorage.api.storage.externalstorage.IExternalStorage; +import com.refinedmods.refinedstorage.api.storage.externalstorage.IExternalStorageContext; +import com.refinedmods.refinedstorage.apiimpl.storage.externalstorage.ItemExternalStorage; +import com.refinedmods.refinedstorage.apiimpl.storage.externalstorage.ItemExternalStorageProvider; +import com.refinedmods.refinedstorage.tile.InterfaceTile; +import com.refinedmods.refinedstorage.util.WorldUtils; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; + +@Mixin(ItemExternalStorageProvider.class) +public class ItemExternalStorageProviderMixin { + /** + * @author embeddedt + * @reason replace supplier in 2nd arg, no easy way of doing so without overwrite + */ + @Overwrite + public IExternalStorage provide(IExternalStorageContext context, BlockEntity blockEntity, Direction direction) { + return new ItemExternalStorage(context, () -> { + Level level = blockEntity.getLevel(); + + if (level == null) { + return null; + } + + BlockPos blockPos = blockEntity.getBlockPos(); + + if (!level.isLoaded(blockPos)) { + return null; + } + + BlockEntity currentBlockEntity = level.getBlockEntity(blockPos); + + return WorldUtils.getItemHandler(currentBlockEntity, direction.getOpposite()); + }, blockEntity instanceof InterfaceTile); + } +} diff --git a/src/main/resources/modernfix.mixins.json b/src/main/resources/modernfix.mixins.json index 6c71335f..d156cbc4 100644 --- a/src/main/resources/modernfix.mixins.json +++ b/src/main/resources/modernfix.mixins.json @@ -9,6 +9,12 @@ "bugfix.edge_chunk_not_saved.ChunkManagerMixin", "bugfix.structure_manager_crash.StructureManagerMixin", "bugfix.tf_cme_on_load.TwilightForestModMixin", + "bugfix.refinedstorage.te_bug.ItemExternalStorageProviderMixin", + "bugfix.refinedstorage.te_bug.FluidExternalStorageProviderMixin", + "bugfix.refinedstorage.te_bug.FluidExternalStorageCacheMixin", + "bugfix.refinedstorage.te_bug.FluidExternalStorageMixin", + "bugfix.refinedstorage.te_bug.ItemExternalStorageCacheMixin", + "bugfix.refinedstorage.te_bug.ItemExternalStorageMixin", "perf.remove_biome_temperature_cache.BiomeMixin", "perf.resourcepacks.ModFileResourcePackMixin", "perf.resourcepacks.VanillaPackMixin", From 1814d96d6c21db594476947cc46030460adc0de2 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Fri, 7 Apr 2023 19:00:48 -0400 Subject: [PATCH 08/25] Update Loom --- build.gradle | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/build.gradle b/build.gradle index 079ccc8c..ae85e2ce 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ plugins { - id "dev.architectury.loom" version "1.0.312" + id "dev.architectury.loom" version "1.1-SNAPSHOT" id "maven-publish" id 'com.matthewprenger.cursegradle' version '1.4.0' id 'com.palantir.git-version' version '1.0.0' @@ -140,10 +140,7 @@ jar { publishing { publications { mavenJava(MavenPublication) { - // add all the jars that should be included when publishing to maven - artifact(remapJar) { - builtBy remapJar - } + from components.java } } From 3a8bc41dd4a91fbaf330163da8080e5f1a72c934 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Fri, 7 Apr 2023 19:03:00 -0400 Subject: [PATCH 09/25] Fix mixin warnings --- .../mixin/bugfix/tf_cme_on_load/TwilightForestModMixin.java | 2 +- .../org/embeddedt/modernfix/mixin/devenv/NarratorMixin.java | 2 +- .../modernfix/mixin/perf/async_jei/InputConstantsMixin.java | 2 +- .../mixin/perf/cache_strongholds/ChunkGeneratorMixin.java | 2 +- .../modernfix/mixin/perf/kubejs/CustomIngredientMixin.java | 2 +- .../modernfix/mixin/perf/kubejs/TagIngredientJSMixin.java | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/embeddedt/modernfix/mixin/bugfix/tf_cme_on_load/TwilightForestModMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/bugfix/tf_cme_on_load/TwilightForestModMixin.java index 67f0bd2c..c05751f3 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/bugfix/tf_cme_on_load/TwilightForestModMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/bugfix/tf_cme_on_load/TwilightForestModMixin.java @@ -15,7 +15,7 @@ public class TwilightForestModMixin { } - @Inject(method = "lambda$init$1", at = @At(value = "INVOKE", target = "Ltwilightforest/block/TFBlocks;tfCompostables()V", ordinal = 0)) + @Inject(method = "lambda$init$1", at = @At(value = "INVOKE", target = "Ltwilightforest/block/TFBlocks;tfCompostables()V", ordinal = 0), remap = false) private static void doBiomeTypes(CallbackInfo ci) { BiomeKeys.addBiomeTypes(); } diff --git a/src/main/java/org/embeddedt/modernfix/mixin/devenv/NarratorMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/devenv/NarratorMixin.java index 6c0754ae..1397a848 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/devenv/NarratorMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/devenv/NarratorMixin.java @@ -9,7 +9,7 @@ import org.spongepowered.asm.mixin.injection.Redirect; @Mixin(NarratorChatListener.class) public class NarratorMixin { - @Redirect(method = "", at = @At(value = "INVOKE", target = "Lcom/mojang/text2speech/Narrator;getNarrator()Lcom/mojang/text2speech/Narrator;")) + @Redirect(method = "", at = @At(value = "INVOKE", target = "Lcom/mojang/text2speech/Narrator;getNarrator()Lcom/mojang/text2speech/Narrator;", remap = false)) private Narrator useDummyNarrator() { return new NarratorDummy(); } diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/async_jei/InputConstantsMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/async_jei/InputConstantsMixin.java index add53d70..d6a60cdb 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/async_jei/InputConstantsMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/async_jei/InputConstantsMixin.java @@ -9,7 +9,7 @@ import org.spongepowered.asm.mixin.injection.Redirect; @Mixin(InputConstants.class) public class InputConstantsMixin { - @Redirect(method = "isKeyDown", at = @At(value = "INVOKE", target = "Lorg/lwjgl/glfw/GLFW;glfwGetKey(JI)I")) + @Redirect(method = "isKeyDown", at = @At(value = "INVOKE", target = "Lorg/lwjgl/glfw/GLFW;glfwGetKey(JI)I", remap = false)) private static int offThreadKeyFetch(long win, int k) { if(RenderSystem.isOnRenderThreadOrInit()) return GLFW.glfwGetKey(win, k); diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/cache_strongholds/ChunkGeneratorMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/cache_strongholds/ChunkGeneratorMixin.java index a72df465..b8cf36a7 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/cache_strongholds/ChunkGeneratorMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/cache_strongholds/ChunkGeneratorMixin.java @@ -22,7 +22,7 @@ import java.util.concurrent.ExecutionException; public class ChunkGeneratorMixin { @Shadow @Final private List strongholdPositions; - @Inject(method = "generateStrongholds", at = @At(value = "INVOKE", target = "Lcom/google/common/collect/Lists;newArrayList()Ljava/util/ArrayList;", ordinal = 0), cancellable = true) + @Inject(method = "generateStrongholds", at = @At(value = "INVOKE", target = "Lcom/google/common/collect/Lists;newArrayList()Ljava/util/ArrayList;", ordinal = 0, remap = false), cancellable = true) private void useCachedDataIfAvailable(CallbackInfo ci) { ServerLevel level = searchLevel(); if(level == null) { diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/CustomIngredientMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/CustomIngredientMixin.java index 8257fa5e..1cb9f048 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/CustomIngredientMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/CustomIngredientMixin.java @@ -14,7 +14,7 @@ import java.util.Set; public abstract class CustomIngredientMixin implements ICachedIngredientJS { @Shadow @Final private Ingredient ingredient; - @Shadow public abstract Set getStacks(); + @Shadow(remap = false) public abstract Set getStacks(); @Override public Set getCachedStacks() { diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/TagIngredientJSMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/TagIngredientJSMixin.java index 88a75047..ac2ecf81 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/TagIngredientJSMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/kubejs/TagIngredientJSMixin.java @@ -19,7 +19,7 @@ import java.util.Set; public abstract class TagIngredientJSMixin implements ICachedIngredientJS { @Shadow public abstract Tag getActualTag(); - @Shadow public abstract Set getStacks(); + @Shadow(remap = false) public abstract Set getStacks(); /** * @author embeddedt From 26d76de7ef02b509b3a5a259c301cf83308085b8 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sat, 8 Apr 2023 17:01:16 -0400 Subject: [PATCH 10/25] Dynamic model loading --- build.gradle | 1 + .../modernfix/blockstate/FakeStateMap.java | 181 +++++++++++ .../classloading/ModernFixResourceFinder.java | 40 ++- .../core/config/ModernFixEarlyConfig.java | 7 +- .../DynamicBakedModelProvider.java | 119 +++++++ .../DynamicModelProvider.java | 41 +++ .../dynamicresources/ModelLocationCache.java | 37 +++ .../BlockModelShaperMixin.java | 49 +++ .../ItemModelShaperMixin.java | 53 ++++ .../dynamic_resources/ModelBakeryMixin.java | 297 ++++++++++++++++++ .../faster_baking/BlockModelShapesMixin.java | 46 --- .../perf/faster_baking/ModelBakeryMixin.java | 161 ---------- .../perf/faster_baking/ModelManagerMixin.java | 40 --- .../BooleanPropertyMixin.java | 2 +- .../OBJLoaderMixin.java | 2 +- .../PropertyMixin.java | 2 +- .../SelectorMixin.java | 3 +- .../TransformationMatrixMixin.java | 2 +- .../BlockModelShaperMixin.java | 26 -- .../ModelBakeryMixin.java | 114 ------- .../multipart/MultipartMixin.java | 17 - .../multipart/VariantListMixin.java | 32 -- .../StateDefinitionMixin.java | 29 ++ .../modernfix/models/LazyBakedModel.java | 138 -------- .../modernfix/textures/StbStitcher.java | 10 +- .../embeddedt/modernfix/util/FileUtil.java | 26 +- src/main/resources/modernfix.mixins.json | 23 +- 27 files changed, 879 insertions(+), 619 deletions(-) create mode 100644 src/main/java/org/embeddedt/modernfix/blockstate/FakeStateMap.java create mode 100644 src/main/java/org/embeddedt/modernfix/dynamicresources/DynamicBakedModelProvider.java create mode 100644 src/main/java/org/embeddedt/modernfix/dynamicresources/DynamicModelProvider.java create mode 100644 src/main/java/org/embeddedt/modernfix/dynamicresources/ModelLocationCache.java create mode 100644 src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/BlockModelShaperMixin.java create mode 100644 src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ItemModelShaperMixin.java create mode 100644 src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ModelBakeryMixin.java delete mode 100644 src/main/java/org/embeddedt/modernfix/mixin/perf/faster_baking/BlockModelShapesMixin.java delete mode 100644 src/main/java/org/embeddedt/modernfix/mixin/perf/faster_baking/ModelBakeryMixin.java delete mode 100644 src/main/java/org/embeddedt/modernfix/mixin/perf/faster_baking/ModelManagerMixin.java rename src/main/java/org/embeddedt/modernfix/mixin/perf/{parallelize_model_loading => model_optimizations}/BooleanPropertyMixin.java (91%) rename src/main/java/org/embeddedt/modernfix/mixin/perf/{parallelize_model_loading => model_optimizations}/OBJLoaderMixin.java (95%) rename src/main/java/org/embeddedt/modernfix/mixin/perf/{parallelize_model_loading => model_optimizations}/PropertyMixin.java (95%) rename src/main/java/org/embeddedt/modernfix/mixin/perf/{parallelize_model_loading => model_optimizations}/SelectorMixin.java (90%) rename src/main/java/org/embeddedt/modernfix/mixin/perf/{parallelize_model_loading => model_optimizations}/TransformationMatrixMixin.java (91%) delete mode 100644 src/main/java/org/embeddedt/modernfix/mixin/perf/parallelize_model_loading/BlockModelShaperMixin.java delete mode 100644 src/main/java/org/embeddedt/modernfix/mixin/perf/parallelize_model_loading/ModelBakeryMixin.java delete mode 100644 src/main/java/org/embeddedt/modernfix/mixin/perf/parallelize_model_loading/multipart/MultipartMixin.java delete mode 100644 src/main/java/org/embeddedt/modernfix/mixin/perf/parallelize_model_loading/multipart/VariantListMixin.java create mode 100644 src/main/java/org/embeddedt/modernfix/mixin/perf/state_definition_construct/StateDefinitionMixin.java delete mode 100644 src/main/java/org/embeddedt/modernfix/models/LazyBakedModel.java diff --git a/build.gradle b/build.gradle index ae85e2ce..31dd054f 100644 --- a/build.gradle +++ b/build.gradle @@ -95,6 +95,7 @@ dependencies { modCompileOnly("curse.maven:jepb-437558:3172880") modCompileOnly("curse.maven:babel-436964:3196072") modCompileOnly("curse.maven:twforest-227639:3575220") + modRuntimeOnly("curse.maven:ferritecore-429235:4074330") } tasks.withType(JavaCompile) { diff --git a/src/main/java/org/embeddedt/modernfix/blockstate/FakeStateMap.java b/src/main/java/org/embeddedt/modernfix/blockstate/FakeStateMap.java new file mode 100644 index 00000000..42194e5d --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/blockstate/FakeStateMap.java @@ -0,0 +1,181 @@ +package org.embeddedt.modernfix.blockstate; + +import com.google.common.collect.ImmutableSet; +import net.minecraft.world.level.block.state.properties.Property; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.*; + +/** + * Fake "map" implementation used to hold the states. + * + * Intentionally throws on methods that would be inefficient so that we know + * if an incompatible mod is present. + */ +public class FakeStateMap implements Map, Comparable>, S> { + private final Map, Comparable>[] keys; + private final Object[] values; + private int usedSlots; + public FakeStateMap(int numStates) { + this.keys = new Map[numStates]; + this.values = new Object[numStates]; + this.usedSlots = 0; + } + + @Override + public int size() { + return usedSlots; + } + + @Override + public boolean isEmpty() { + return size() == 0; + } + + @Override + public boolean containsKey(Object o) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean containsValue(Object o) { + throw new UnsupportedOperationException(); + } + + @Override + public S get(Object o) { + throw new UnsupportedOperationException(); + } + + @Nullable + @Override + public S put(Map, Comparable> propertyComparableMap, S s) { + keys[usedSlots] = propertyComparableMap; + values[usedSlots] = s; + usedSlots++; + return null; + } + + @Override + public S remove(Object o) { + throw new UnsupportedOperationException(); + } + + @Override + public void putAll(@NotNull Map, Comparable>, ? extends S> map) { + for(Entry, Comparable>, ? extends S> entry : map.entrySet()) { + this.put(entry.getKey(), entry.getValue()); + } + } + + @Override + public void clear() { + for(int i = 0; i < this.keys.length; i++) { + this.keys[i] = null; + this.values[i] = null; + } + this.usedSlots = 0; + } + + @NotNull + @Override + public Set, Comparable>> keySet() { + throw new UnsupportedOperationException(); + } + + @NotNull + @Override + public Collection values() { + throw new UnsupportedOperationException(); + } + + @NotNull + @Override + public Set, Comparable>, S>> entrySet() { + return new Set, Comparable>, S>>() { + @Override + public int size() { + return usedSlots; + } + + @Override + public boolean isEmpty() { + return FakeStateMap.this.isEmpty(); + } + + @Override + public boolean contains(Object o) { + throw new UnsupportedOperationException(); + } + + @NotNull + @Override + public Iterator, Comparable>, S>> iterator() { + return new Iterator, Comparable>, S>>() { + int currentIdx = 0; + @Override + public boolean hasNext() { + return currentIdx < usedSlots; + } + + @Override + public Entry, Comparable>, S> next() { + if(currentIdx >= usedSlots) + throw new IndexOutOfBoundsException(); + Entry, Comparable>, S> entry = new AbstractMap.SimpleImmutableEntry<>(keys[currentIdx], (S)values[currentIdx]); + currentIdx++; + return entry; + } + }; + } + + @NotNull + @Override + public Object[] toArray() { + throw new UnsupportedOperationException(); + } + + @NotNull + @Override + public T[] toArray(@NotNull T[] ts) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean add(Entry, Comparable>, S> mapSEntry) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean remove(Object o) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean containsAll(@NotNull Collection collection) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean addAll(@NotNull Collection, Comparable>, S>> collection) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean retainAll(@NotNull Collection collection) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean removeAll(@NotNull Collection collection) { + throw new UnsupportedOperationException(); + } + + @Override + public void clear() { + throw new UnsupportedOperationException(); + } + }; + } +} diff --git a/src/main/java/org/embeddedt/modernfix/classloading/ModernFixResourceFinder.java b/src/main/java/org/embeddedt/modernfix/classloading/ModernFixResourceFinder.java index 432ede05..c11dcb56 100644 --- a/src/main/java/org/embeddedt/modernfix/classloading/ModernFixResourceFinder.java +++ b/src/main/java/org/embeddedt/modernfix/classloading/ModernFixResourceFinder.java @@ -1,5 +1,8 @@ package org.embeddedt.modernfix.classloading; +import com.google.common.collect.Interner; +import com.google.common.collect.Interners; +import com.google.common.collect.Iterators; import com.google.common.collect.Lists; import cpw.mods.modlauncher.api.LamdbaExceptionUtils; import net.minecraftforge.fml.loading.FMLLoader; @@ -14,6 +17,7 @@ import org.apache.logging.log4j.Logger; import java.io.IOException; import java.lang.reflect.Field; +import java.net.MalformedURLException; import java.net.URL; import java.nio.file.FileSystem; import java.nio.file.Files; @@ -23,7 +27,7 @@ import java.util.regex.Pattern; import java.util.stream.Stream; public class ModernFixResourceFinder { - private static HashMap> urlsForClass = null; + private static HashMap>> urlsForClass = null; private static final Class MINECRAFT_LOCATOR; private static Field explodedDirModsField = null; private static final Logger LOGGER = LogManager.getLogger("ModernFixResourceFinder"); @@ -35,6 +39,8 @@ public class ModernFixResourceFinder { throw new RuntimeException(e); } } + private static final Interner PATH_INTERNER = Interners.newStrongInterner(); + public static synchronized void init() throws ReflectiveOperationException { urlsForClass = new HashMap<>(); //LOGGER.info("Start building list of class locations..."); @@ -50,22 +56,20 @@ public class ModernFixResourceFinder { .map(root::relativize) .forEach(path -> { String strPath = path.toString(); - URL url = (URL)LamdbaExceptionUtils.uncheck(() -> { - return new URL("modjar://" + fileInfo.getMods().get(0).getModId() + "/" + strPath); - }); - List urlList = urlsForClass.get(strPath); + Pair pathPair = Pair.of(fileInfo.getMods().get(0).getModId(), PATH_INTERNER.intern(strPath)); + List> urlList = urlsForClass.get(strPath); if(urlList != null) { if(urlList.size() > 1) - urlList.add(url); + urlList.add(pathPair); else { /* Convert singleton to real list */ - ArrayList newList = new ArrayList<>(urlList); - newList.add(url); + ArrayList> newList = new ArrayList<>(urlList); + newList.add(pathPair); urlsForClass.put(strPath, newList); } } else { /* Use a singleton list initially to keep memory usage down */ - urlsForClass.put(strPath, Collections.singletonList(url)); + urlsForClass.put(strPath, Collections.singletonList(pathPair)); } }); } catch(IOException e) { @@ -73,9 +77,9 @@ public class ModernFixResourceFinder { } } } - for(List list : urlsForClass.values()) { + for(List> list : urlsForClass.values()) { if(list instanceof ArrayList) - ((ArrayList)list).trimToSize(); + ((ArrayList>)list).trimToSize(); } //LOGGER.info("Finish building"); } @@ -106,10 +110,16 @@ public class ModernFixResourceFinder { public static Enumeration findAllURLsForResource(String input) { input = SLASH_REPLACER.matcher(input).replaceAll("/"); - List urlList = urlsForClass.get(input); - if(urlList != null) - return Collections.enumeration(urlList); - else { + List> urlList = urlsForClass.get(input); + if(urlList != null) { + return Iterators.asEnumeration(urlList.stream().map(pair -> { + try { + return new URL("modjar://" + pair.getLeft() + "/" + pair.getRight()); + } catch(MalformedURLException e) { + throw new RuntimeException(e); + } + }).iterator()); + } else { return Collections.emptyEnumeration(); } } diff --git a/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java b/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java index fc2c23d7..9d5625e9 100644 --- a/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java +++ b/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java @@ -36,8 +36,10 @@ public class ModernFixEarlyConfig { this.addMixinRule("perf.boost_worker_count", true); this.addMixinRule("perf.skip_first_datapack_reload", true); this.addMixinRule("perf.reuse_datapacks", true); - this.addMixinRule("perf.parallelize_model_loading", true); - this.addMixinRule("perf.parallelize_model_loading.multipart", false); + this.addMixinRule("perf.model_optimizations", true); + this.addMixinRule("perf.dynamic_resources", false); + /* Use a simpler ArrayMap if FerriteCore is using the map intelligently anyway */ + this.addMixinRule("perf.state_definition_construct", modPresent("ferritecore")); this.addMixinRule("perf.cache_strongholds", true); this.addMixinRule("perf.cache_upgraded_structures", true); this.addMixinRule("bugfix.concurrency", true); @@ -57,7 +59,6 @@ public class ModernFixEarlyConfig { this.addMixinRule("perf.flatten_model_predicates", true); this.addMixinRule("perf.deduplicate_location", false); this.addMixinRule("perf.cache_blockstate_cache_arrays", true); - this.addMixinRule("perf.faster_baking", true); this.addMixinRule("perf.cache_model_materials", true); this.addMixinRule("perf.datapack_reload_exceptions", true); this.addMixinRule("perf.async_locator", true); diff --git a/src/main/java/org/embeddedt/modernfix/dynamicresources/DynamicBakedModelProvider.java b/src/main/java/org/embeddedt/modernfix/dynamicresources/DynamicBakedModelProvider.java new file mode 100644 index 00000000..30dea59d --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/dynamicresources/DynamicBakedModelProvider.java @@ -0,0 +1,119 @@ +package org.embeddedt.modernfix.dynamicresources; + +import com.mojang.math.Transformation; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.client.resources.model.BlockModelRotation; +import net.minecraft.client.resources.model.ModelBakery; +import net.minecraft.resources.ResourceLocation; +import org.apache.commons.lang3.tuple.Triple; +import org.jetbrains.annotations.NotNull; + +import javax.annotation.Nullable; +import java.util.AbstractMap; +import java.util.Collection; +import java.util.Map; +import java.util.Set; +import java.util.function.BiFunction; +import java.util.stream.Collectors; + +public class DynamicBakedModelProvider implements Map { + private final ModelBakery bakery; + private final Map, BakedModel> bakedCache; + private final Map permanentOverrides; + + public DynamicBakedModelProvider(ModelBakery bakery, Map, BakedModel> cache) { + this.bakery = bakery; + this.bakedCache = cache; + this.permanentOverrides = new Object2ObjectOpenHashMap<>(); + } + private static Triple vanillaKey(Object o) { + return Triple.of((ResourceLocation)o, BlockModelRotation.X0_Y0.getRotation(), false); + } + @Override + public int size() { + return bakedCache.size(); + } + + @Override + public boolean isEmpty() { + return bakedCache.isEmpty(); + } + + @Override + public boolean containsKey(Object o) { + return permanentOverrides.containsKey(o) || bakedCache.containsKey(vanillaKey(o)); + } + + @Override + public boolean containsValue(Object o) { + return permanentOverrides.containsValue(o) || bakedCache.containsValue(o); + } + + @Override + public BakedModel get(Object o) { + BakedModel model = permanentOverrides.get(o); + return model != null ? model : bakery.bake((ResourceLocation)o, BlockModelRotation.X0_Y0); + } + + @Nullable + @Override + public BakedModel put(ResourceLocation resourceLocation, BakedModel bakedModel) { + BakedModel m = permanentOverrides.put(resourceLocation, bakedModel); + if(m != null) + return m; + else + return bakedCache.get(vanillaKey(resourceLocation)); + } + + @Override + public BakedModel remove(Object o) { + BakedModel m = permanentOverrides.remove(o); + if(m != null) + return m; + return bakedCache.remove(vanillaKey(o)); + } + + @Override + public void putAll(@NotNull Map map) { + permanentOverrides.putAll(map); + } + + @Override + public void clear() { + throw new UnsupportedOperationException(); + } + + @NotNull + @Override + public Set keySet() { + return bakedCache.keySet().stream().map(Triple::getLeft).collect(Collectors.toSet()); + } + + @NotNull + @Override + public Collection values() { + return bakedCache.values(); + } + + @NotNull + @Override + public Set> entrySet() { + return bakedCache.entrySet().stream().map(entry -> new AbstractMap.SimpleImmutableEntry<>(entry.getKey().getLeft(), entry.getValue())).collect(Collectors.toSet()); + } + + @Override + public void replaceAll(BiFunction function) { + Set overridenLocations = permanentOverrides.keySet(); + permanentOverrides.replaceAll(function); + boolean uvLock = BlockModelRotation.X0_Y0.isUvLocked(); + Transformation rotation = BlockModelRotation.X0_Y0.getRotation(); + bakedCache.replaceAll((loc, oldModel) -> { + if(loc.getMiddle() != rotation || loc.getRight() != uvLock || overridenLocations.contains(loc.getLeft())) + return oldModel; + else + return function.apply(loc.getLeft(), oldModel); + }); + } +} diff --git a/src/main/java/org/embeddedt/modernfix/dynamicresources/DynamicModelProvider.java b/src/main/java/org/embeddedt/modernfix/dynamicresources/DynamicModelProvider.java new file mode 100644 index 00000000..67bd354c --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/dynamicresources/DynamicModelProvider.java @@ -0,0 +1,41 @@ +package org.embeddedt.modernfix.dynamicresources; + +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import net.minecraft.client.resources.model.UnbakedModel; +import net.minecraft.resources.ResourceLocation; + +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; + +/** + * Handles loading models dynamically, rather than at startup time. + */ +public class DynamicModelProvider { + private final Map internalModels; + private final Cache> loadedModels = + CacheBuilder.newBuilder() + .expireAfterAccess(3, TimeUnit.MINUTES) + .maximumSize(1000) + .concurrencyLevel(8) + .softValues() + .build(); + + public DynamicModelProvider(Map initialModels) { + this.internalModels = initialModels; + } + + public UnbakedModel getModel(ResourceLocation location) { + try { + return loadedModels.get(location, () -> Optional.ofNullable(loadModel(location))).orElse(null); + } catch(ExecutionException e) { + throw new RuntimeException(e.getCause()); + } + } + + private UnbakedModel loadModel(ResourceLocation location) { + return null; /* TODO :) */ + } +} diff --git a/src/main/java/org/embeddedt/modernfix/dynamicresources/ModelLocationCache.java b/src/main/java/org/embeddedt/modernfix/dynamicresources/ModelLocationCache.java new file mode 100644 index 00000000..031fdc0c --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/dynamicresources/ModelLocationCache.java @@ -0,0 +1,37 @@ +package org.embeddedt.modernfix.dynamicresources; + +import com.mojang.datafixers.util.Pair; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import net.minecraft.Util; +import net.minecraft.client.renderer.block.BlockModelShaper; +import net.minecraft.client.resources.model.ModelResourceLocation; +import net.minecraft.core.Registry; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; + +import java.util.ArrayList; +import java.util.Map; +import java.util.concurrent.CompletableFuture; + +public class ModelLocationCache { + private static final Map locationCache = new Object2ObjectOpenHashMap<>(); + public static void rebuildLocationCache() { + locationCache.clear(); + ArrayList>> futures = new ArrayList<>(); + for(Block block : Registry.BLOCK) { + block.getStateDefinition().getPossibleStates().forEach((state) -> { + futures.add(CompletableFuture.supplyAsync(() -> { + return Pair.of(state, BlockModelShaper.stateToModelLocation(state)); + }, Util.backgroundExecutor())); + }); + } + for(CompletableFuture> future : futures) { + Pair pair = future.join(); + locationCache.put(pair.getFirst(), pair.getSecond()); + } + } + + public static ModelResourceLocation get(BlockState state) { + return locationCache.get(state); + } +} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/BlockModelShaperMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/BlockModelShaperMixin.java new file mode 100644 index 00000000..91d45970 --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/BlockModelShaperMixin.java @@ -0,0 +1,49 @@ +package org.embeddedt.modernfix.mixin.perf.dynamic_resources; + +import com.mojang.datafixers.util.Pair; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import net.minecraft.Util; +import net.minecraft.client.renderer.block.BlockModelShaper; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.client.resources.model.ModelManager; +import net.minecraft.client.resources.model.ModelResourceLocation; +import net.minecraft.core.Registry; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.Property; +import org.embeddedt.modernfix.dynamicresources.ModelLocationCache; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; + +@Mixin(BlockModelShaper.class) +public class BlockModelShaperMixin { + @Shadow @Final private ModelManager modelManager; + + /** + * @author embeddedt + * @reason no need to rebuild model cache, and location cache is done elsewhere + */ + @Overwrite + public void rebuildCache() { + } + + @Overwrite + public BakedModel getBlockModel(BlockState state) { + BakedModel model = modelManager.getModel(ModelLocationCache.get(state)); + if (model == null) { + model = modelManager.getMissingModel(); + } + return model; + } +} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ItemModelShaperMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ItemModelShaperMixin.java new file mode 100644 index 00000000..0ca70841 --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ItemModelShaperMixin.java @@ -0,0 +1,53 @@ +package org.embeddedt.modernfix.mixin.perf.dynamic_resources; + +import net.minecraft.client.renderer.ItemModelShaper; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.client.resources.model.ModelManager; +import net.minecraft.client.resources.model.ModelResourceLocation; +import net.minecraft.world.item.Item; +import net.minecraftforge.client.ItemModelMesherForge; +import net.minecraftforge.registries.IRegistryDelegate; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; + +import java.util.Map; + +@Mixin(ItemModelMesherForge.class) +public abstract class ItemModelShaperMixin extends ItemModelShaper { + @Shadow @Final private Map, ModelResourceLocation> locations; + + public ItemModelShaperMixin(ModelManager arg) { + super(arg); + } + + /** + * @reason Get the stored location for that item and meta, and get the model + * from that location from the model manager. + **/ + @Overwrite + @Override + public BakedModel getItemModel(Item item) { + ModelResourceLocation map = locations.get(item.delegate); + return map == null ? null : getModelManager().getModel(map); + } + + /** + * @reason Don't get all models during init (with dynamic loading, that would + * generate them all). Just store location instead. + **/ + @Overwrite + @Override + public void register(Item item, ModelResourceLocation location) { + locations.put(item.delegate, location); + } + + /** + * @reason Disable cache rebuilding (with dynamic loading, that would generate + * all models). + **/ + @Overwrite + @Override + public void rebuildCache() {} +} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ModelBakeryMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ModelBakeryMixin.java new file mode 100644 index 00000000..015408f9 --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ModelBakeryMixin.java @@ -0,0 +1,297 @@ +package org.embeddedt.modernfix.mixin.perf.dynamic_resources; + +import com.google.common.base.Stopwatch; +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.RemovalNotification; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import com.google.gson.JsonElement; +import com.google.gson.JsonParser; +import com.mojang.datafixers.util.Pair; +import com.mojang.math.Transformation; +import net.minecraft.Util; +import net.minecraft.client.color.block.BlockColors; +import net.minecraft.client.renderer.block.model.BlockModel; +import net.minecraft.client.renderer.block.model.ItemModelGenerator; +import net.minecraft.client.renderer.texture.AtlasSet; +import net.minecraft.client.renderer.texture.TextureAtlas; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.renderer.texture.TextureManager; +import net.minecraft.client.resources.model.*; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.resources.Resource; +import net.minecraft.server.packs.resources.ResourceManager; +import net.minecraft.util.profiling.ProfilerFiller; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition; +import net.minecraftforge.client.ForgeHooksClient; +import net.minecraftforge.client.model.ModelLoaderRegistry; +import org.apache.commons.lang3.tuple.Triple; +import org.apache.logging.log4j.Logger; +import org.embeddedt.modernfix.ModernFix; +import org.embeddedt.modernfix.dynamicresources.DynamicBakedModelProvider; +import org.embeddedt.modernfix.dynamicresources.ModelLocationCache; +import org.spongepowered.asm.mixin.*; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import javax.annotation.Nullable; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; +import java.util.function.Function; +import java.util.stream.Collectors; + +@Mixin(ModelBakery.class) +public abstract class ModelBakeryMixin { + + private static final boolean debugDynamicModelLoading = Boolean.getBoolean("modernfix.debugDynamicModelLoading"); + + @Shadow @Final @Mutable public Map unbakedCache; + + @Shadow @Final public static ModelResourceLocation MISSING_MODEL_LOCATION; + + @Shadow protected abstract BlockModel loadBlockModel(ResourceLocation location) throws IOException; + + @Shadow @Final protected static Set UNREFERENCED_TEXTURES; + @Shadow private Map> atlasPreparations; + @Shadow @Final protected ResourceManager resourceManager; + @Shadow @Nullable private AtlasSet atlasSet; + @Shadow @Final private Set loadingStack; + + @Shadow protected abstract void loadModel(ResourceLocation blockstateLocation) throws Exception; + + @Shadow @Final private static Logger LOGGER; + + @Shadow @Final @Mutable + private Map bakedTopLevelModels; + + @Shadow @Final @Mutable private Map, BakedModel> bakedCache; + + @Shadow @Final public static BlockModel GENERATION_MARKER; + + @Shadow @Final private static ItemModelGenerator ITEM_MODEL_GENERATOR; + + @Shadow @Final public static BlockModel BLOCK_ENTITY_MARKER; + + private Cache, BakedModel> loadedBakedModels; + private Cache loadedModels; + + + @Inject(method = "(Lnet/minecraft/server/packs/resources/ResourceManager;Lnet/minecraft/client/color/block/BlockColors;Z)V", at = @At("RETURN")) + private void replaceTopLevelBakedModels(ResourceManager manager, BlockColors colors, boolean vanillaBakery, CallbackInfo ci) { + this.loadedBakedModels = CacheBuilder.newBuilder() + .expireAfterAccess(3, TimeUnit.MINUTES) + .maximumSize(1000) + .concurrencyLevel(8) + .removalListener(this::onModelRemoved) + .softValues() + .build(); + this.loadedModels = CacheBuilder.newBuilder() + .expireAfterAccess(3, TimeUnit.MINUTES) + .maximumSize(1000) + .concurrencyLevel(8) + .removalListener(this::onModelRemoved) + .softValues() + .build(); + this.bakedCache = loadedBakedModels.asMap(); + this.unbakedCache = loadedModels.asMap(); + this.bakedTopLevelModels = new DynamicBakedModelProvider((ModelBakery)(Object)this, bakedCache); + } + + private void onModelRemoved(RemovalNotification notification) { + if(!debugDynamicModelLoading) + return; + Object k = notification.getKey(); + if(k == null) + return; + ResourceLocation rl; + boolean baked = false; + if(k instanceof ResourceLocation) { + rl = (ResourceLocation)k; + } else { + rl = ((Triple)k).getLeft(); + baked = true; + } + ModernFix.LOGGER.warn("Evicted {} model {}", baked ? "baked" : "unbaked", rl); + } + + private UnbakedModel missingModel; + + private static boolean firstReload = true; + + /** + * @author embeddedt + * @reason don't load any models initially, just set up initial data structures + */ + @Overwrite + protected void processLoading(ProfilerFiller arg, int maxMipLevels) { + ModelLoaderRegistry.onModelLoadingStart(); + if(firstReload) { + ModelLocationCache.rebuildLocationCache(); + firstReload = false; + } + try { + this.missingModel = this.loadBlockModel(MISSING_MODEL_LOCATION); + } catch (IOException var10) { + ModernFix.LOGGER.error("Error loading missing model, should never happen :(", var10); + throw new RuntimeException(var10); + } + // Gather model materials + Set initialMaterials = new HashSet<>(UNREFERENCED_TEXTURES); + gatherModelMaterials(initialMaterials); + ForgeHooksClient.gatherFluidTextures(initialMaterials); + Map> map = initialMaterials.stream().collect(Collectors.groupingBy(Material::atlasLocation)); + this.atlasPreparations = Maps.newHashMap(); + for(Map.Entry> entry : map.entrySet()) { + TextureAtlas atlas = new TextureAtlas(entry.getKey()); + TextureAtlas.Preparations atlastexture$sheetdata = atlas.prepareToStitch(this.resourceManager, entry.getValue().stream().map(Material::texture), arg, maxMipLevels); + this.atlasPreparations.put(entry.getKey(), Pair.of(atlas, atlastexture$sheetdata)); + } + } + + /** + * Scan the models folder and try to load, parse, and get materials from as many models as possible. + */ + private void gatherModelMaterials(Set materialSet) { + Stopwatch stopwatch = Stopwatch.createStarted(); + Collection allModels = this.resourceManager.listResources("models", path -> path.endsWith(".json")); + List>> modelBytes = new ArrayList<>(); + for(ResourceLocation fileLocation : allModels) { + modelBytes.add(CompletableFuture.supplyAsync(() -> { + try(Resource resource = this.resourceManager.getResource(fileLocation)) { + JsonParser parser = new JsonParser(); + // strip models/ and .json from the name + ResourceLocation model = new ResourceLocation(fileLocation.getNamespace(), fileLocation.getPath().substring(7, fileLocation.getPath().length()-5)); + return Pair.of(model, parser.parse(new InputStreamReader(resource.getInputStream(), StandardCharsets.UTF_8))); + } catch(IOException e) { + ModernFix.LOGGER.error("Error reading model " + fileLocation, e); + return Pair.of(fileLocation, null); + } + }, Util.backgroundExecutor())); + } + allModels.clear(); + CompletableFuture.allOf(modelBytes.toArray(new CompletableFuture[0])).join(); + Set> errorSet = Sets.newLinkedHashSet(); + Map basicModels = new HashMap<>(); + try { + basicModels.put(MISSING_MODEL_LOCATION, this.loadBlockModel(MISSING_MODEL_LOCATION)); + basicModels.put(new ResourceLocation("builtin/generated"), GENERATION_MARKER); + basicModels.put(new ResourceLocation("builtin/entity"), BLOCK_ENTITY_MARKER); + } catch(IOException e) { + throw new RuntimeException("Exception when populating built-in models", e); + } + for(CompletableFuture> future : modelBytes) { + Pair pair = future.join(); + try { + if(pair.getSecond() != null) { + BlockModel model = ModelLoaderRegistry.ExpandedBlockModelDeserializer.INSTANCE.fromJson(pair.getSecond(), BlockModel.class); + model.name = pair.getFirst().toString(); + basicModels.put(pair.getFirst(), model); + } + } catch(Exception e) { + ModernFix.LOGGER.warn("Unable to load " + pair.getFirst(), e); + } + } + modelBytes.clear(); + Function modelGetter = loc -> basicModels.getOrDefault(loc, (BlockModel)this.missingModel); + for(BlockModel model : basicModels.values()) { + materialSet.addAll(model.getMaterials(modelGetter, errorSet)); + } + //errorSet.stream().filter(pair -> !pair.getSecond().equals(MISSING_MODEL_LOCATION_STRING)).forEach(pair -> LOGGER.warn("Unable to resolve texture reference: {} in {}", pair.getFirst(), pair.getSecond())); + stopwatch.stop(); + ModernFix.LOGGER.info("Resolving model textures took " + stopwatch); + } + + @Inject(method = "uploadTextures", at = @At(value = "FIELD", target = "Lnet/minecraft/client/resources/model/ModelBakery;topLevelModels:Ljava/util/Map;", ordinal = 0), cancellable = true) + private void skipBake(TextureManager resourceManager, ProfilerFiller profiler, CallbackInfoReturnable cir) { + profiler.pop(); + cir.setReturnValue(atlasSet); + } + + /** + * Use the already loaded missing model instead of the cache entry (which will probably get evicted). + */ + @Redirect(method = "loadModel", at = @At(value = "INVOKE", target = "Ljava/util/Map;get(Ljava/lang/Object;)Ljava/lang/Object;", ordinal = 1)) + private Object getMissingModel(Map map, Object rl) { + if(rl == MISSING_MODEL_LOCATION && map == unbakedCache) + return missingModel; + return unbakedCache.get(rl); + } + + + /** + * @author embeddedt + * @reason synchronize + */ + @Overwrite + public synchronized UnbakedModel getModel(ResourceLocation modelLocation) { + if(modelLocation.equals(MISSING_MODEL_LOCATION)) + return missingModel; + if (this.unbakedCache.containsKey(modelLocation)) { + return this.unbakedCache.get(modelLocation); + } else if (this.loadingStack.contains(modelLocation)) { + throw new IllegalStateException("Circular reference while loading " + modelLocation); + } else { + this.loadingStack.add(modelLocation); + UnbakedModel iunbakedmodel = missingModel; + + while(!this.loadingStack.isEmpty()) { + ResourceLocation resourcelocation = this.loadingStack.iterator().next(); + + try { + if (!this.unbakedCache.containsKey(resourcelocation)) { + if(debugDynamicModelLoading) + LOGGER.info("Loading {}", resourcelocation); + this.loadModel(resourcelocation); + } + } catch (ModelBakery.BlockStateDefinitionException var9) { + LOGGER.warn(var9.getMessage()); + this.unbakedCache.put(resourcelocation, iunbakedmodel); + } catch (Exception var10) { + LOGGER.warn("Unable to load model: '{}' referenced from: {}: {}", resourcelocation, modelLocation, var10); + this.unbakedCache.put(resourcelocation, iunbakedmodel); + } finally { + this.loadingStack.remove(resourcelocation); + } + } + + return this.unbakedCache.getOrDefault(modelLocation, iunbakedmodel); + } + } + + @Overwrite + public synchronized BakedModel getBakedModel(ResourceLocation arg, ModelState arg2, Function textureGetter) { + Triple triple = Triple.of(arg, arg2.getRotation(), arg2.isUvLocked()); + if (this.bakedCache.containsKey(triple)) { + return this.bakedCache.get(triple); + } else if (this.atlasSet == null) { + throw new IllegalStateException("bake called too early"); + } else { + if(debugDynamicModelLoading) + LOGGER.info("Baking {}", arg); + UnbakedModel iunbakedmodel = this.getModel(arg); + iunbakedmodel.getMaterials(this::getModel, new HashSet<>()); + BakedModel ibakedmodel = null; + if (iunbakedmodel instanceof BlockModel) { + BlockModel blockmodel = (BlockModel)iunbakedmodel; + if (blockmodel.getRootModel() == GENERATION_MARKER) { + ibakedmodel = ITEM_MODEL_GENERATOR.generateBlockModel(textureGetter, blockmodel).bake((ModelBakery)(Object)this, blockmodel, this.atlasSet::getSprite, arg2, arg, false); + } + } + if(ibakedmodel == null) { + ibakedmodel = iunbakedmodel.bake((ModelBakery) (Object) this, textureGetter, arg2, arg); + } + this.bakedCache.put(triple, ibakedmodel); + return ibakedmodel; + } + } +} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/faster_baking/BlockModelShapesMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/faster_baking/BlockModelShapesMixin.java deleted file mode 100644 index c397f9a9..00000000 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/faster_baking/BlockModelShapesMixin.java +++ /dev/null @@ -1,46 +0,0 @@ -package org.embeddedt.modernfix.mixin.perf.faster_baking; - -import com.mojang.datafixers.util.Pair; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.client.renderer.block.BlockModelShaper; -import net.minecraft.client.resources.model.BakedModel; -import net.minecraft.client.resources.model.ModelManager; -import net.minecraft.Util; -import net.minecraft.core.Registry; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; -import org.spongepowered.asm.mixin.Shadow; - -import java.util.ArrayList; -import java.util.Map; -import java.util.concurrent.CompletableFuture; - -@Mixin(BlockModelShaper.class) -public abstract class BlockModelShapesMixin { - @Shadow @Final private ModelManager modelManager; - - @Shadow @Final private Map modelByStateCache; - - /** - * @author embeddedt - * @reason parallelize cache rebuild - */ - @Overwrite - public void rebuildCache() { - this.modelByStateCache.clear(); - ArrayList>> futures = new ArrayList<>(); - for(Block block : Registry.BLOCK) { - block.getStateDefinition().getPossibleStates().forEach((state) -> { - futures.add(CompletableFuture.supplyAsync(() -> { - return Pair.of(state, this.modelManager.getModel(BlockModelShaper.stateToModelLocation(state))); - }, Util.backgroundExecutor())); - }); - } - for(CompletableFuture> future : futures) { - Pair pair = future.join(); - this.modelByStateCache.put(pair.getFirst(), pair.getSecond()); - } - } -} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/faster_baking/ModelBakeryMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/faster_baking/ModelBakeryMixin.java deleted file mode 100644 index 5f5bae31..00000000 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/faster_baking/ModelBakeryMixin.java +++ /dev/null @@ -1,161 +0,0 @@ -package org.embeddedt.modernfix.mixin.perf.faster_baking; - -import com.google.common.collect.ImmutableSet; -import com.mojang.datafixers.util.Pair; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.block.model.MultiVariant; -import net.minecraft.client.renderer.block.model.multipart.MultiPart; -import net.minecraft.client.renderer.texture.TextureAtlas; -import net.minecraft.client.renderer.texture.AtlasSet; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.client.renderer.texture.TextureManager; -import net.minecraft.util.profiling.ProfilerFiller; -import net.minecraft.resources.ResourceLocation; -import com.mojang.math.Transformation; -import net.minecraftforge.client.event.ModelBakeEvent; -import net.minecraftforge.fml.loading.progress.StartupMessageManager; -import org.apache.commons.lang3.tuple.Triple; -import org.embeddedt.modernfix.core.config.ModernFixConfig; -import org.embeddedt.modernfix.duck.IExtendedModelBakery; -import org.embeddedt.modernfix.models.LazyBakedModel; -import org.embeddedt.modernfix.util.ModUtil; -import org.spongepowered.asm.mixin.*; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import javax.annotation.Nullable; -import java.util.*; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ConcurrentHashMap; -import java.util.function.Function; -import java.util.stream.Collectors; - -import static org.embeddedt.modernfix.ModernFix.LOGGER; - -import net.minecraft.client.renderer.block.model.BlockModel; -import net.minecraft.client.resources.model.BakedModel; -import net.minecraft.client.resources.model.BlockModelRotation; -import net.minecraft.client.resources.model.Material; -import net.minecraft.client.resources.model.ModelBakery; -import net.minecraft.client.resources.model.ModelResourceLocation; -import net.minecraft.client.resources.model.ModelState; -import net.minecraft.client.resources.model.UnbakedModel; - -@Mixin(ModelBakery.class) -public abstract class ModelBakeryMixin implements IExtendedModelBakery { - @Shadow @Final private Map topLevelModels; - - @Shadow @Final private Map bakedTopLevelModels; - - @Shadow @Deprecated @Nullable public abstract BakedModel bake(ResourceLocation pLocation, ModelState pTransform); - - @Shadow private Map> atlasPreparations; - - @Shadow @Nullable private AtlasSet atlasSet; - - @Shadow @Nullable public abstract BakedModel getBakedModel(ResourceLocation pLocation, ModelState pTransform, Function textureGetter); - - @Shadow @Final public static ModelResourceLocation MISSING_MODEL_LOCATION; - - @Shadow @Final private Map, BakedModel> bakedCache; - - @Shadow @Final private Map unbakedCache; - - private BakedModel bakeIfPossible(ResourceLocation p_229350_1_) { - BakedModel ibakedmodel = null; - - try { - ibakedmodel = this.bake(p_229350_1_, BlockModelRotation.X0_Y0); - } catch (Exception exception) { - exception.printStackTrace(); - LOGGER.warn("Unable to bake model: '{}': {}", p_229350_1_, exception); - } - - return ibakedmodel; - } - - private boolean requiresBake(UnbakedModel model) { - if(model instanceof BlockModel && ((BlockModel)model).customData.hasCustomGeometry()) - return true; - else - return false; - } - - @Inject(method = "processLoading", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/profiling/ProfilerFiller;pop()V")) - private void bakeModels(ProfilerFiller pProfiler, int p_i226056_4_, CallbackInfo ci) { - pProfiler.popPush("atlas"); - Minecraft.getInstance().executeBlocking(() -> { - for(Pair pair : this.atlasPreparations.values()) { - TextureAtlas atlastexture = pair.getFirst(); - TextureAtlas.Preparations atlastexture$sheetdata = pair.getSecond(); - atlastexture.reload(atlastexture$sheetdata); - } - }); - pProfiler.popPush("baking"); - StartupMessageManager.mcLoaderConsumer().ifPresent(c -> c.accept("Baking models")); - this.atlasSet = new AtlasSet(this.atlasPreparations.values().stream().map(Pair::getFirst).collect(Collectors.toList())); - BakedModel missingModel = this.bake(MISSING_MODEL_LOCATION, BlockModelRotation.X0_Y0); - this.bakedTopLevelModels.put(MISSING_MODEL_LOCATION, missingModel); - Collection modsListening = ModUtil.findAllModsListeningToEvent(ModelBakeEvent.class); - LOGGER.debug("Found ModelBakeEvent listeners: [" + String.join(", ", modsListening) + "]"); - Set incompatibleLazyBakedModels = ImmutableSet.builder() - .addAll(modsListening) - .build(); - /* First, bake any incompatible models ahead of time (for mods that have custom models) */ - new ArrayList<>(this.unbakedCache.keySet()).forEach(location -> { - if(incompatibleLazyBakedModels.contains(location.getNamespace())) { - this.bakeIfPossible(location); - } - }); - List multiparts = new ArrayList<>(); - /* Then store them as top-level models if needed, and set up the lazy models */ - this.topLevelModels.forEach((location, value) -> { - if (requiresBake(value) || incompatibleLazyBakedModels.contains(location.getNamespace())) { - BakedModel model = this.bakeIfPossible(location); - if (model != null) - this.bakedTopLevelModels.put(location, model); - } else { - if(value instanceof MultiPart || value instanceof MultiVariant) { - multiparts.add(location); - } else { - this.bakedTopLevelModels.put(location, new LazyBakedModel(() -> { - synchronized (this.bakedCache) { - BakedModel ibakedmodel = this.bakeIfPossible(location); - - return ibakedmodel != null ? ibakedmodel : missingModel; - } - })); - } - } - }); - multiparts.forEach(location -> { - BakedModel model = this.bakeIfPossible(location); - if (model != null) - this.bakedTopLevelModels.put(location, model); - }); - } - - /** - * @author embeddedt - * @reason texture loading and baking are moved earlier in the launch process, only render thread stuff is done here - */ - @Overwrite - public AtlasSet uploadTextures(TextureManager pResourceManager, ProfilerFiller pProfiler) { - pProfiler.push("atlas_upload"); - for(Pair pair : this.atlasPreparations.values()) { - TextureAtlas atlastexture = pair.getFirst(); - TextureAtlas.Preparations atlastexture$sheetdata = pair.getSecond(); - pResourceManager.register(atlastexture.location(), atlastexture); - pResourceManager.bind(atlastexture.location()); - atlastexture.updateFilter(atlastexture$sheetdata); - } - pProfiler.pop(); - return this.atlasSet; - } - - @Override - public AtlasSet getUnfinishedAtlasSet() { - return this.atlasSet; - } -} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/faster_baking/ModelManagerMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/faster_baking/ModelManagerMixin.java deleted file mode 100644 index 3e485c35..00000000 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/faster_baking/ModelManagerMixin.java +++ /dev/null @@ -1,40 +0,0 @@ -package org.embeddedt.modernfix.mixin.perf.faster_baking; - -import it.unimi.dsi.fastutil.objects.Object2IntMap; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.block.BlockModelShaper; -import net.minecraft.client.resources.model.BakedModel; -import net.minecraft.client.resources.model.ModelBakery; -import net.minecraft.client.resources.model.ModelManager; -import net.minecraft.client.renderer.texture.AtlasSet; -import net.minecraft.client.renderer.texture.TextureManager; -import net.minecraft.util.profiling.ProfilerFiller; -import net.minecraft.server.packs.resources.ResourceManager; -import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.client.model.ModelLoader; -import net.minecraftforge.fml.common.ObfuscationReflectionHelper; -import org.embeddedt.modernfix.duck.IExtendedModelBakery; -import org.embeddedt.modernfix.models.LazyBakedModel; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import org.spongepowered.asm.mixin.injection.callback.LocalCapture; - -import javax.annotation.Nullable; -import java.util.Map; - -@Mixin(ModelManager.class) -public class ModelManagerMixin { - - @Inject(method = "apply(Lnet/minecraft/client/resources/model/ModelBakery;Lnet/minecraft/server/packs/resources/ResourceManager;Lnet/minecraft/util/profiling/ProfilerFiller;)V", - at = @At(value = "RETURN")) - private void allowBake(ModelBakery pObject, ResourceManager pResourceManager, ProfilerFiller pProfiler, CallbackInfo ci) { - LazyBakedModel.allowBakeForFlags = true; - } -} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/parallelize_model_loading/BooleanPropertyMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/model_optimizations/BooleanPropertyMixin.java similarity index 91% rename from src/main/java/org/embeddedt/modernfix/mixin/perf/parallelize_model_loading/BooleanPropertyMixin.java rename to src/main/java/org/embeddedt/modernfix/mixin/perf/model_optimizations/BooleanPropertyMixin.java index a5fb1b72..934449b7 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/parallelize_model_loading/BooleanPropertyMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/model_optimizations/BooleanPropertyMixin.java @@ -1,4 +1,4 @@ -package org.embeddedt.modernfix.mixin.perf.parallelize_model_loading; +package org.embeddedt.modernfix.mixin.perf.model_optimizations; import com.google.common.collect.ImmutableSet; import net.minecraft.world.level.block.state.properties.BooleanProperty; diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/parallelize_model_loading/OBJLoaderMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/model_optimizations/OBJLoaderMixin.java similarity index 95% rename from src/main/java/org/embeddedt/modernfix/mixin/perf/parallelize_model_loading/OBJLoaderMixin.java rename to src/main/java/org/embeddedt/modernfix/mixin/perf/model_optimizations/OBJLoaderMixin.java index 79b3c1f8..33f700d4 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/parallelize_model_loading/OBJLoaderMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/model_optimizations/OBJLoaderMixin.java @@ -1,4 +1,4 @@ -package org.embeddedt.modernfix.mixin.perf.parallelize_model_loading; +package org.embeddedt.modernfix.mixin.perf.model_optimizations; import net.minecraft.resources.ResourceLocation; import net.minecraftforge.client.model.obj.MaterialLibrary; diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/parallelize_model_loading/PropertyMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/model_optimizations/PropertyMixin.java similarity index 95% rename from src/main/java/org/embeddedt/modernfix/mixin/perf/parallelize_model_loading/PropertyMixin.java rename to src/main/java/org/embeddedt/modernfix/mixin/perf/model_optimizations/PropertyMixin.java index 4ff99e9c..4d64c0ba 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/parallelize_model_loading/PropertyMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/model_optimizations/PropertyMixin.java @@ -1,4 +1,4 @@ -package org.embeddedt.modernfix.mixin.perf.parallelize_model_loading; +package org.embeddedt.modernfix.mixin.perf.model_optimizations; import net.minecraft.world.level.block.state.properties.Property; import org.embeddedt.modernfix.dedup.IdentifierCaches; diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/parallelize_model_loading/SelectorMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/model_optimizations/SelectorMixin.java similarity index 90% rename from src/main/java/org/embeddedt/modernfix/mixin/perf/parallelize_model_loading/SelectorMixin.java rename to src/main/java/org/embeddedt/modernfix/mixin/perf/model_optimizations/SelectorMixin.java index 19c88421..e52d84c4 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/parallelize_model_loading/SelectorMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/model_optimizations/SelectorMixin.java @@ -1,6 +1,5 @@ -package org.embeddedt.modernfix.mixin.perf.parallelize_model_loading; +package org.embeddedt.modernfix.mixin.perf.model_optimizations; -import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.client.renderer.block.model.multipart.Selector; diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/parallelize_model_loading/TransformationMatrixMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/model_optimizations/TransformationMatrixMixin.java similarity index 91% rename from src/main/java/org/embeddedt/modernfix/mixin/perf/parallelize_model_loading/TransformationMatrixMixin.java rename to src/main/java/org/embeddedt/modernfix/mixin/perf/model_optimizations/TransformationMatrixMixin.java index 184b4006..286d030f 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/parallelize_model_loading/TransformationMatrixMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/model_optimizations/TransformationMatrixMixin.java @@ -1,4 +1,4 @@ -package org.embeddedt.modernfix.mixin.perf.parallelize_model_loading; +package org.embeddedt.modernfix.mixin.perf.model_optimizations; import com.mojang.math.Matrix4f; import com.mojang.math.Transformation; diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/parallelize_model_loading/BlockModelShaperMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/parallelize_model_loading/BlockModelShaperMixin.java deleted file mode 100644 index 9da0fed8..00000000 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/parallelize_model_loading/BlockModelShaperMixin.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.embeddedt.modernfix.mixin.perf.parallelize_model_loading; - -import com.google.common.collect.Interner; -import com.google.common.collect.Interners; -import net.minecraft.client.renderer.block.BlockModelShaper; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.Property; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -@Mixin(BlockModelShaper.class) -public class BlockModelShaperMixin { - private static Map stateToPropertiesCache = new ConcurrentHashMap<>(); - - @Redirect(method = "stateToModelLocation(Lnet/minecraft/resources/ResourceLocation;Lnet/minecraft/world/level/block/state/BlockState;)Lnet/minecraft/client/resources/model/ModelResourceLocation;", - at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/block/BlockModelShaper;statePropertiesToString(Ljava/util/Map;)Ljava/lang/String;")) - private static String getCachedProperty(Map, Comparable> values, ResourceLocation location, BlockState state) { - /* We intentionally don't use the values parameter inside the lambda to avoid an allocation */ - return stateToPropertiesCache.computeIfAbsent(state, s -> BlockModelShaper.statePropertiesToString(s.getValues())); - } -} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/parallelize_model_loading/ModelBakeryMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/parallelize_model_loading/ModelBakeryMixin.java deleted file mode 100644 index e696f92f..00000000 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/parallelize_model_loading/ModelBakeryMixin.java +++ /dev/null @@ -1,114 +0,0 @@ -package org.embeddedt.modernfix.mixin.perf.parallelize_model_loading; - -import com.mojang.datafixers.util.Pair; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.util.profiling.ProfilerFiller; -import net.minecraft.server.packs.resources.Resource; -import net.minecraft.server.packs.resources.ResourceManager; -import net.minecraft.world.level.block.state.StateDefinition; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.Util; -import net.minecraft.core.Registry; -import net.minecraftforge.fml.loading.progress.StartupMessageManager; -import org.embeddedt.modernfix.ModernFix; -import org.embeddedt.modernfix.util.AsyncStopwatch; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.Redirect; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.nio.charset.StandardCharsets; -import java.util.*; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ConcurrentHashMap; -import java.util.function.Function; -import java.util.stream.Stream; - -import net.minecraft.client.renderer.block.model.BlockModelDefinition; -import net.minecraft.client.resources.model.ModelBakery; -import net.minecraft.client.resources.model.ModelResourceLocation; - -@Mixin(ModelBakery.class) -public abstract class ModelBakeryMixin { - @Shadow @Final protected ResourceManager resourceManager; - - private Map>> deserializedBlockstateCache = null; - - @Inject(method = "processLoading", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/profiling/ProfilerFiller;popPush(Ljava/lang/String;)V", ordinal = 0)) - private void preloadJsonModels(ProfilerFiller profilerIn, int maxMipmapLevel, CallbackInfo ci) { - StartupMessageManager.mcLoaderConsumer().ifPresent(c -> c.accept("Loading models")); - profilerIn.popPush("loadblockstates"); - AsyncStopwatch.measureAndLogSerialRunningTime("Parallel blockstate loading", () -> { - ThreadLocal containerHolder = ThreadLocal.withInitial(BlockModelDefinition.Context::new); - this.deserializedBlockstateCache = new ConcurrentHashMap<>(); - ArrayList> futures = new ArrayList<>(); - for(Block block : Registry.BLOCK) { - ResourceLocation blockLocation = Registry.BLOCK.getKey(block); - futures.add(CompletableFuture.runAsync(() -> { - ResourceLocation blockStateJSON = new ResourceLocation(blockLocation.getNamespace(), "blockstates/" + blockLocation.getPath() + ".json"); - List blockStates; - try { - /* Some mods' custom resource pack implementations don't seem to like concurrency here */ - synchronized(this.resourceManager) { - blockStates = this.resourceManager.getResources(blockStateJSON); - } - } catch(IOException e) { - ModernFix.LOGGER.warn("Exception loading blockstate definition: {}: {}", blockLocation, e); - return; - } - List> definitions = new ArrayList<>(); - StateDefinition stateContainer = block.getStateDefinition(); - BlockModelDefinition.Context context = containerHolder.get(); - context.setDefinition(stateContainer); - for(Resource resource : blockStates) { - try (InputStream inputstream = resource.getInputStream()) { - BlockModelDefinition definition = BlockModelDefinition.fromStream(context, new InputStreamReader(inputstream, StandardCharsets.UTF_8)); - definitions.add(Pair.of(resource.getSourceName(), definition)); - } catch (Exception exception1) { - ModernFix.LOGGER.warn(String.format("Exception loading blockstate definition: '%s' in resourcepack: '%s': %s", resource.getLocation(), resource.getSourceName(), exception1.getMessage())); - return; - } - } - this.deserializedBlockstateCache.put(blockLocation, definitions); - }, Util.backgroundExecutor())); - } - CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join(); - }); - } - - @Inject(method = "processLoading", at = @At("RETURN"), remap = false) - private void clearModelCache(ProfilerFiller profilerIn, int maxMipmapLevel, CallbackInfo ci) { - deserializedBlockstateCache.clear(); - } - - private List replacementList = null; - - @Redirect(method = "loadModel", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/packs/resources/ResourceManager;getResources(Lnet/minecraft/resources/ResourceLocation;)Ljava/util/List;", ordinal = 0)) - private List getResourceList(ResourceManager instance, ResourceLocation jsonLocation, ResourceLocation originalBlockLocation) throws IOException { - replacementList = null; - if(this.deserializedBlockstateCache != null) { - if(!(originalBlockLocation instanceof ModelResourceLocation)) { - throw new AssertionError("Injector in unexpected spot?"); - } - ModelResourceLocation mrl = (ModelResourceLocation)originalBlockLocation; - ResourceLocation location = new ResourceLocation(mrl.getNamespace(), mrl.getPath()); - List theList = this.deserializedBlockstateCache.get(location); - if(theList != null && theList.size() > 0) { - replacementList = theList; - return theList; - } - } - return instance.getResources(jsonLocation); - } - - @Redirect(method = "loadModel", at = @At(value = "INVOKE", target = "Ljava/util/stream/Stream;map(Ljava/util/function/Function;)Ljava/util/stream/Stream;", ordinal = 0)) - private Stream fakeResourceList(Stream instance, Function function) { - return replacementList != null ? instance : instance.map(function); - } -} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/parallelize_model_loading/multipart/MultipartMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/parallelize_model_loading/multipart/MultipartMixin.java deleted file mode 100644 index 5d375be1..00000000 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/parallelize_model_loading/multipart/MultipartMixin.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.embeddedt.modernfix.mixin.perf.parallelize_model_loading.multipart; - -import net.minecraft.client.renderer.block.model.multipart.MultiPart; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -import java.util.List; -import java.util.stream.Stream; - -@Mixin(MultiPart.class) -public class MultipartMixin { - @Redirect(method = "getMaterials", at = @At(value = "INVOKE", target = "Ljava/util/List;stream()Ljava/util/stream/Stream;", ordinal = 0)) - private Stream makeStreamParallel(List instance) { - return instance.parallelStream(); - } -} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/parallelize_model_loading/multipart/VariantListMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/parallelize_model_loading/multipart/VariantListMixin.java deleted file mode 100644 index ead9af25..00000000 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/parallelize_model_loading/multipart/VariantListMixin.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.embeddedt.modernfix.mixin.perf.parallelize_model_loading.multipart; - -import com.mojang.datafixers.util.Pair; -import net.minecraft.client.resources.model.UnbakedModel; -import net.minecraft.client.resources.model.Material; -import net.minecraft.client.renderer.block.model.Variant; -import net.minecraft.client.renderer.block.model.MultiVariant; -import net.minecraft.resources.ResourceLocation; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; -import org.spongepowered.asm.mixin.Shadow; - -import java.util.Collection; -import java.util.List; -import java.util.Set; -import java.util.function.Function; -import java.util.stream.Collectors; - -@Mixin(MultiVariant.class) -public abstract class VariantListMixin { - @Shadow public abstract List getVariants(); - - /** - * @author embeddedt - * @reason Parallelize calls to getMaterials - */ - @Overwrite - public Collection getMaterials(Function pModelGetter, Set> pMissingTextureErrors) { - List models = this.getVariants().stream().map(Variant::getModelLocation).distinct().map(pModelGetter).collect(Collectors.toList()); - return models.parallelStream().flatMap(model -> model.getMaterials(pModelGetter, pMissingTextureErrors).stream()).collect(Collectors.toSet()); - } -} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/state_definition_construct/StateDefinitionMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/state_definition_construct/StateDefinitionMixin.java new file mode 100644 index 00000000..dd6157c3 --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/state_definition_construct/StateDefinitionMixin.java @@ -0,0 +1,29 @@ +package org.embeddedt.modernfix.mixin.perf.state_definition_construct; + +import com.google.common.collect.ImmutableSortedMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; +import net.minecraft.world.level.block.state.StateDefinition; +import net.minecraft.world.level.block.state.StateHolder; +import net.minecraft.world.level.block.state.properties.Property; +import org.embeddedt.modernfix.blockstate.FakeStateMap; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyVariable; + +import java.util.Map; + +@Mixin(StateDefinition.class) +public class StateDefinitionMixin> { + @Shadow @Final private ImmutableSortedMap> propertiesByName; + + @ModifyVariable(method = "", at = @At(value = "STORE", ordinal = 0), ordinal = 1, index = 8) + private Map, Comparable>, S> useArrayMap(Map, Comparable>, S> in) { + int numStates = 1; + for(Property prop : this.propertiesByName.values()) { + numStates *= prop.getPossibleValues().size(); + } + return new FakeStateMap<>(numStates); + } +} diff --git a/src/main/java/org/embeddedt/modernfix/models/LazyBakedModel.java b/src/main/java/org/embeddedt/modernfix/models/LazyBakedModel.java deleted file mode 100644 index d5b87496..00000000 --- a/src/main/java/org/embeddedt/modernfix/models/LazyBakedModel.java +++ /dev/null @@ -1,138 +0,0 @@ -package org.embeddedt.modernfix.models; - -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.datafixers.util.Pair; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.block.model.BakedQuad; -import net.minecraft.client.resources.model.BakedModel; -import net.minecraft.client.renderer.block.model.ItemTransforms; -import net.minecraft.client.renderer.block.model.ItemOverrides; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.world.item.ItemStack; -import net.minecraft.core.Direction; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.BlockAndTintGetter; -import net.minecraftforge.client.model.data.EmptyModelData; -import net.minecraftforge.client.model.data.IModelData; -import org.embeddedt.modernfix.ModernFix; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import java.util.List; -import java.util.Random; -import java.util.function.Supplier; - -public class LazyBakedModel implements BakedModel { - private BakedModel delegate = null; - private Supplier delegateSupplier; - - /** - * This flag is changed to true when we should bake instead of returning reasonable defaults for certain - * method calls. - */ - public static boolean allowBakeForFlags = false; - - public LazyBakedModel(Supplier delegateSupplier) { - this.delegateSupplier = delegateSupplier; - } - - public BakedModel computeDelegate() { - if(this.delegate == null) { - this.delegate = this.delegateSupplier.get(); - this.delegateSupplier = null; - } - return this.delegate; - } - - @Override - public List getQuads(@Nullable BlockState pState, @Nullable Direction pSide, Random pRand) { - return computeDelegate().getQuads(pState, pSide, pRand); - } - - @Override - public boolean useAmbientOcclusion() { - return computeDelegate().useAmbientOcclusion(); - } - - @Override - public boolean isGui3d() { - return computeDelegate().isGui3d(); - } - - @Override - public boolean usesBlockLight() { - return computeDelegate().usesBlockLight(); - } - - @Override - public boolean isCustomRenderer() { - if(this.delegate != null) - return this.delegate.isCustomRenderer(); - if(!LazyBakedModel.allowBakeForFlags) - return false; - return computeDelegate().isCustomRenderer(); - } - - @Override - public TextureAtlasSprite getParticleIcon() { - return computeDelegate().getParticleIcon(); - } - - @Override - public ItemTransforms getTransforms() { - return computeDelegate().getTransforms(); - } - - @Override - public ItemOverrides getOverrides() { - return computeDelegate().getOverrides(); - } - - @Override - public BakedModel getBakedModel() { - return computeDelegate().getBakedModel(); - } - - @Nonnull - @Override - public List getQuads(@Nullable BlockState state, @Nullable Direction side, @Nonnull Random rand, @Nonnull IModelData extraData) { - return computeDelegate().getQuads(state, side, rand, extraData); - } - - @Override - public boolean isAmbientOcclusion(BlockState state) { - return computeDelegate().isAmbientOcclusion(state); - } - - @Override - public boolean doesHandlePerspectives() { - return computeDelegate().doesHandlePerspectives(); - } - - @Override - public BakedModel handlePerspective(ItemTransforms.TransformType cameraTransformType, PoseStack mat) { - return computeDelegate().handlePerspective(cameraTransformType, mat); - } - - @Nonnull - @Override - public IModelData getModelData(@Nonnull BlockAndTintGetter world, @Nonnull BlockPos pos, @Nonnull BlockState state, @Nonnull IModelData tileData) { - return computeDelegate().getModelData(world, pos, state, tileData); - } - - @Override - public TextureAtlasSprite getParticleTexture(@Nonnull IModelData data) { - return computeDelegate().getParticleTexture(data); - } - - @Override - public boolean isLayered() { - return computeDelegate().isLayered(); - } - - @Override - public List> getLayerModels(ItemStack itemStack, boolean fabulous) { - return computeDelegate().getLayerModels(itemStack, fabulous); - } -} diff --git a/src/main/java/org/embeddedt/modernfix/textures/StbStitcher.java b/src/main/java/org/embeddedt/modernfix/textures/StbStitcher.java index d5958c08..42c2fdf8 100644 --- a/src/main/java/org/embeddedt/modernfix/textures/StbStitcher.java +++ b/src/main/java/org/embeddedt/modernfix/textures/StbStitcher.java @@ -92,18 +92,18 @@ public class StbStitcher { } } - private static STBRPRect setWrapper(STBRPRect rect, int id, int width, int height, int x, int y, boolean was_packed) { + public static STBRPRect setWrapper(STBRPRect rect, int id, int width, int height, int x, int y, boolean was_packed) { try { if(MH_rect_shortSet != null) - return (STBRPRect)MH_rect_shortSet.invokeExact(rect, id, (short)width, (short)height, (short)0, (short)0, false); + return (STBRPRect)MH_rect_shortSet.invokeExact(rect, id, (short)width, (short)height, (short)x, (short)y, was_packed); else - return (STBRPRect)MH_rect_intSet.invokeExact(rect, id, width, height, 0, 0, false); + return (STBRPRect)MH_rect_intSet.invokeExact(rect, id, width, height, x, y, was_packed); } catch(Throwable e) { throw new AssertionError(e); } } - private static int getX(STBRPRect rect) { + public static int getX(STBRPRect rect) { try { if(MH_rect_shortX != null) return (short)MH_rect_shortX.invokeExact(rect); @@ -114,7 +114,7 @@ public class StbStitcher { } } - private static int getY(STBRPRect rect) { + public static int getY(STBRPRect rect) { try { if(MH_rect_shortX != null) return (short)MH_rect_shortY.invokeExact(rect); diff --git a/src/main/java/org/embeddedt/modernfix/util/FileUtil.java b/src/main/java/org/embeddedt/modernfix/util/FileUtil.java index 51045bda..41f2c4f5 100644 --- a/src/main/java/org/embeddedt/modernfix/util/FileUtil.java +++ b/src/main/java/org/embeddedt/modernfix/util/FileUtil.java @@ -9,14 +9,34 @@ public class FileUtil { return file; } - private static final Pattern SLASH_PATTERN = Pattern.compile("(?:\\\\+|\\/+)"); - /** * Normalize a path by removing double slashes, etc. + *

+ * This implementation avoids creating a new string unless there are actually double slashes present + * in the input path. * @param path input path * @return a normalized version of the path */ public static String normalize(String path) { - return SLASH_PATTERN.matcher(path).replaceAll("/"); + char prevChar = 0; + StringBuilder sb = null; + for(int i = 0; i < path.length(); i++) { + char thisChar = path.charAt(i); + if(prevChar != '/' || thisChar != prevChar) { + /* This character should end up in the final string. If we are using the builder, add it there. */ + if(sb != null) + sb.append(thisChar); + } else { + /* This character should not end up in the final string. We need to make a buidler if we haven't + * done so yet. + */ + if(sb == null) { + sb = new StringBuilder(path.length()); + sb.append(path, 0, i); + } + } + prevChar = thisChar; + } + return sb == null ? path : sb.toString(); } } diff --git a/src/main/resources/modernfix.mixins.json b/src/main/resources/modernfix.mixins.json index d156cbc4..47cd50be 100644 --- a/src/main/resources/modernfix.mixins.json +++ b/src/main/resources/modernfix.mixins.json @@ -60,7 +60,8 @@ "perf.cache_strongholds.ChunkGeneratorMixin", "perf.cache_upgraded_structures.StructureManagerMixin", "perf.cache_strongholds.ServerLevelMixin", - "devenv.MinecraftServerMixin", + "perf.state_definition_construct.StateDefinitionMixin", + "devenv.MinecraftServerMixin" ], "client": [ "core.MinecraftMixin", @@ -71,15 +72,14 @@ "bugfix.concurrency.RenderTypeMixin", "bugfix.concurrency.MinecraftMixin", "bugfix.concurrency.StaticTagHelperMixin", - "perf.parallelize_model_loading.BlockModelShaperMixin", - "perf.parallelize_model_loading.ModelBakeryMixin", - "perf.parallelize_model_loading.OBJLoaderMixin", - "perf.parallelize_model_loading.multipart.MultipartMixin", - "perf.parallelize_model_loading.multipart.VariantListMixin", - "perf.parallelize_model_loading.SelectorMixin", - "perf.parallelize_model_loading.TransformationMatrixMixin", - "perf.parallelize_model_loading.BooleanPropertyMixin", - "perf.parallelize_model_loading.PropertyMixin", + "perf.dynamic_resources.BlockModelShaperMixin", + "perf.dynamic_resources.ItemModelShaperMixin", + "perf.dynamic_resources.ModelBakeryMixin", + "perf.model_optimizations.OBJLoaderMixin", + "perf.model_optimizations.SelectorMixin", + "perf.model_optimizations.TransformationMatrixMixin", + "perf.model_optimizations.BooleanPropertyMixin", + "perf.model_optimizations.PropertyMixin", "perf.async_jei.InputConstantsMixin", "perf.async_jei.IngredientListElementFactoryMixin", "perf.async_jei.ClientLifecycleHandlerMixin", @@ -93,9 +93,6 @@ "perf.flatten_model_predicates.PropertyValueConditionMixin", "perf.blast_search_trees.MinecraftMixin", "perf.blast_search_trees.IngredientFilterInvoker", - "perf.faster_baking.ModelBakeryMixin", - "perf.faster_baking.BlockModelShapesMixin", - "perf.faster_baking.ModelManagerMixin", "perf.cache_model_materials.VanillaModelMixin", "perf.cache_model_materials.MultipartMixin", "perf.faster_texture_stitching.StitcherMixin", From 4f35a6cda38430b1e3d35f47589d3dca5bddbbe1 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sat, 8 Apr 2023 17:08:35 -0400 Subject: [PATCH 11/25] Make material gatherer resilient to JSON errors --- .../mixin/perf/dynamic_resources/ModelBakeryMixin.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ModelBakeryMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ModelBakeryMixin.java index 015408f9..3244f626 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ModelBakeryMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ModelBakeryMixin.java @@ -7,7 +7,9 @@ import com.google.common.cache.RemovalNotification; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; import com.google.gson.JsonParser; +import com.google.gson.JsonSyntaxException; import com.mojang.datafixers.util.Pair; import com.mojang.math.Transformation; import net.minecraft.Util; @@ -172,8 +174,8 @@ public abstract class ModelBakeryMixin { // strip models/ and .json from the name ResourceLocation model = new ResourceLocation(fileLocation.getNamespace(), fileLocation.getPath().substring(7, fileLocation.getPath().length()-5)); return Pair.of(model, parser.parse(new InputStreamReader(resource.getInputStream(), StandardCharsets.UTF_8))); - } catch(IOException e) { - ModernFix.LOGGER.error("Error reading model " + fileLocation, e); + } catch(IOException | JsonParseException e) { + ModernFix.LOGGER.error("Error reading model {}: {}", fileLocation, e); return Pair.of(fileLocation, null); } }, Util.backgroundExecutor())); @@ -198,7 +200,7 @@ public abstract class ModelBakeryMixin { basicModels.put(pair.getFirst(), model); } } catch(Exception e) { - ModernFix.LOGGER.warn("Unable to load " + pair.getFirst(), e); + ModernFix.LOGGER.warn("Unable to load {}: {}", pair.getFirst(), e); } } modelBytes.clear(); From e724c4dfb1893e4bd78077da2d63274c04f56d46 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sat, 8 Apr 2023 17:28:17 -0400 Subject: [PATCH 12/25] Strengthen exception when parsing models --- .../mixin/perf/dynamic_resources/ModelBakeryMixin.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ModelBakeryMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ModelBakeryMixin.java index 3244f626..0cb14a1a 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ModelBakeryMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ModelBakeryMixin.java @@ -199,8 +199,8 @@ public abstract class ModelBakeryMixin { model.name = pair.getFirst().toString(); basicModels.put(pair.getFirst(), model); } - } catch(Exception e) { - ModernFix.LOGGER.warn("Unable to load {}: {}", pair.getFirst(), e); + } catch(Throwable e) { + ModernFix.LOGGER.warn("Unable to parse {}: {}", pair.getFirst(), e); } } modelBytes.clear(); From e4d3ffbac1d1558f470c518d32688ff508b9701f Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sat, 8 Apr 2023 18:40:50 -0400 Subject: [PATCH 13/25] Don't keep Interner instance around after collecting resources --- .../modernfix/classloading/ModernFixResourceFinder.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/embeddedt/modernfix/classloading/ModernFixResourceFinder.java b/src/main/java/org/embeddedt/modernfix/classloading/ModernFixResourceFinder.java index c11dcb56..aae72683 100644 --- a/src/main/java/org/embeddedt/modernfix/classloading/ModernFixResourceFinder.java +++ b/src/main/java/org/embeddedt/modernfix/classloading/ModernFixResourceFinder.java @@ -39,10 +39,10 @@ public class ModernFixResourceFinder { throw new RuntimeException(e); } } - private static final Interner PATH_INTERNER = Interners.newStrongInterner(); public static synchronized void init() throws ReflectiveOperationException { urlsForClass = new HashMap<>(); + Interner pathInterner = Interners.newStrongInterner(); //LOGGER.info("Start building list of class locations..."); for(ModFileInfo fileInfo : LoadingModList.get().getModFiles()) { ModFile file = fileInfo.getFile(); @@ -56,7 +56,7 @@ public class ModernFixResourceFinder { .map(root::relativize) .forEach(path -> { String strPath = path.toString(); - Pair pathPair = Pair.of(fileInfo.getMods().get(0).getModId(), PATH_INTERNER.intern(strPath)); + Pair pathPair = Pair.of(fileInfo.getMods().get(0).getModId(), pathInterner.intern(strPath)); List> urlList = urlsForClass.get(strPath); if(urlList != null) { if(urlList.size() > 1) From 395e14ba9baee50d084e0f06f3ba941aff52be9b Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sat, 8 Apr 2023 19:08:03 -0400 Subject: [PATCH 14/25] Fix leaking mixin injectors --- .../modernfix/core/ModernFixMixinPlugin.java | 15 ++ .../embeddedt/modernfix/util/DummyList.java | 131 ++++++++++++++++++ 2 files changed, 146 insertions(+) create mode 100644 src/main/java/org/embeddedt/modernfix/util/DummyList.java diff --git a/src/main/java/org/embeddedt/modernfix/core/ModernFixMixinPlugin.java b/src/main/java/org/embeddedt/modernfix/core/ModernFixMixinPlugin.java index 37c436a7..0c22fd8d 100644 --- a/src/main/java/org/embeddedt/modernfix/core/ModernFixMixinPlugin.java +++ b/src/main/java/org/embeddedt/modernfix/core/ModernFixMixinPlugin.java @@ -10,9 +10,12 @@ import org.apache.logging.log4j.Logger; import org.embeddedt.modernfix.classloading.ModernFixResourceFinder; import org.embeddedt.modernfix.core.config.ModernFixEarlyConfig; import org.embeddedt.modernfix.core.config.Option; +import org.embeddedt.modernfix.util.DummyList; import org.objectweb.asm.tree.*; import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; import org.spongepowered.asm.mixin.extensibility.IMixinInfo; +import org.spongepowered.asm.mixin.injection.struct.InjectionInfo; +import org.spongepowered.asm.mixin.injection.struct.InjectorGroupInfo; import java.io.File; import java.io.IOException; @@ -72,6 +75,18 @@ public class ModernFixMixinPlugin implements IMixinConfigPlugin { } catch(RuntimeException | ReflectiveOperationException e) { logger.error("Failed to make classloading changes", e); } + + /* https://github.com/FabricMC/Mixin/pull/99 */ + try { + Field groupMembersField = InjectorGroupInfo.class.getDeclaredField("members"); + groupMembersField.setAccessible(true); + Field noGroupField = InjectorGroupInfo.Map.class.getDeclaredField("NO_GROUP"); + noGroupField.setAccessible(true); + InjectorGroupInfo noGroup = (InjectorGroupInfo)noGroupField.get(null); + groupMembersField.set(noGroup, new DummyList<>()); + } catch(RuntimeException | ReflectiveOperationException e) { + logger.error("Failed to patch mixin memory leak", e); + } } private Method defineClassMethod = null; diff --git a/src/main/java/org/embeddedt/modernfix/util/DummyList.java b/src/main/java/org/embeddedt/modernfix/util/DummyList.java new file mode 100644 index 00000000..221c6506 --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/util/DummyList.java @@ -0,0 +1,131 @@ +package org.embeddedt.modernfix.util; + +import org.jetbrains.annotations.NotNull; + +import java.util.*; + +/** + * List with no-op methods. + */ +public class DummyList implements List { + @Override + public int size() { + return 0; + } + + @Override + public boolean isEmpty() { + return true; + } + + @Override + public boolean contains(Object o) { + return false; + } + + @NotNull + @Override + public Iterator iterator() { + return Collections.emptyIterator(); + } + + @NotNull + @Override + public Object[] toArray() { + return new Object[0]; + } + + @NotNull + @Override + public T1[] toArray(@NotNull T1[] t1s) { + return Arrays.copyOf(t1s, 0); + } + + @Override + public boolean add(T t) { + return false; + } + + @Override + public boolean remove(Object o) { + return false; + } + + @Override + public boolean containsAll(@NotNull Collection collection) { + return false; + } + + @Override + public boolean addAll(@NotNull Collection collection) { + return false; + } + + @Override + public boolean addAll(int i, @NotNull Collection collection) { + return false; + } + + @Override + public boolean removeAll(@NotNull Collection collection) { + return false; + } + + @Override + public boolean retainAll(@NotNull Collection collection) { + return false; + } + + @Override + public void clear() { + + } + + @Override + public T get(int i) { + return null; + } + + @Override + public T set(int i, T t) { + return null; + } + + @Override + public void add(int i, T t) { + + } + + @Override + public T remove(int i) { + return null; + } + + @Override + public int indexOf(Object o) { + return -1; + } + + @Override + public int lastIndexOf(Object o) { + return -1; + } + + @NotNull + @Override + public ListIterator listIterator() { + return Collections.emptyListIterator(); + } + + @NotNull + @Override + public ListIterator listIterator(int i) { + return Collections.emptyListIterator(); + } + + @NotNull + @Override + public List subList(int i, int i1) { + return new DummyList<>(); + } +} From b20705a4c424bbc5d315898103fbdf37db7ce2f8 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sat, 8 Apr 2023 19:12:08 -0400 Subject: [PATCH 15/25] Use ImmutableMap for model location cache since it never changes --- .../modernfix/dynamicresources/ModelLocationCache.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/embeddedt/modernfix/dynamicresources/ModelLocationCache.java b/src/main/java/org/embeddedt/modernfix/dynamicresources/ModelLocationCache.java index 031fdc0c..5a1bcc8e 100644 --- a/src/main/java/org/embeddedt/modernfix/dynamicresources/ModelLocationCache.java +++ b/src/main/java/org/embeddedt/modernfix/dynamicresources/ModelLocationCache.java @@ -1,5 +1,6 @@ package org.embeddedt.modernfix.dynamicresources; +import com.google.common.collect.ImmutableMap; import com.mojang.datafixers.util.Pair; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import net.minecraft.Util; @@ -10,13 +11,13 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import java.util.ArrayList; +import java.util.Collections; import java.util.Map; import java.util.concurrent.CompletableFuture; public class ModelLocationCache { - private static final Map locationCache = new Object2ObjectOpenHashMap<>(); + private static Map locationCache = Collections.emptyMap(); public static void rebuildLocationCache() { - locationCache.clear(); ArrayList>> futures = new ArrayList<>(); for(Block block : Registry.BLOCK) { block.getStateDefinition().getPossibleStates().forEach((state) -> { @@ -25,10 +26,13 @@ public class ModelLocationCache { }, Util.backgroundExecutor())); }); } + + ImmutableMap.Builder builder = ImmutableMap.builder(); for(CompletableFuture> future : futures) { Pair pair = future.join(); - locationCache.put(pair.getFirst(), pair.getSecond()); + builder.put(pair.getFirst(), pair.getSecond()); } + locationCache = builder.build(); } public static ModelResourceLocation get(BlockState state) { From 775bc5f0274dd40d986fa95185f1f58058a9e453 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sat, 8 Apr 2023 19:13:21 -0400 Subject: [PATCH 16/25] Use ImmutableMap for resource finder --- .../modernfix/classloading/ModernFixResourceFinder.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/embeddedt/modernfix/classloading/ModernFixResourceFinder.java b/src/main/java/org/embeddedt/modernfix/classloading/ModernFixResourceFinder.java index aae72683..978f8b1a 100644 --- a/src/main/java/org/embeddedt/modernfix/classloading/ModernFixResourceFinder.java +++ b/src/main/java/org/embeddedt/modernfix/classloading/ModernFixResourceFinder.java @@ -1,9 +1,6 @@ package org.embeddedt.modernfix.classloading; -import com.google.common.collect.Interner; -import com.google.common.collect.Interners; -import com.google.common.collect.Iterators; -import com.google.common.collect.Lists; +import com.google.common.collect.*; import cpw.mods.modlauncher.api.LamdbaExceptionUtils; import net.minecraftforge.fml.loading.FMLLoader; import net.minecraftforge.fml.loading.LoadingModList; @@ -27,7 +24,7 @@ import java.util.regex.Pattern; import java.util.stream.Stream; public class ModernFixResourceFinder { - private static HashMap>> urlsForClass = null; + private static Map>> urlsForClass = null; private static final Class MINECRAFT_LOCATOR; private static Field explodedDirModsField = null; private static final Logger LOGGER = LogManager.getLogger("ModernFixResourceFinder"); @@ -81,6 +78,7 @@ public class ModernFixResourceFinder { if(list instanceof ArrayList) ((ArrayList>)list).trimToSize(); } + urlsForClass = ImmutableMap.copyOf(urlsForClass); //LOGGER.info("Finish building"); } From 1796d80d40debb6a3f090e7b3e7856ccb4587d28 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sat, 8 Apr 2023 20:01:40 -0400 Subject: [PATCH 17/25] Make ModelLocationCache more low-memory friendly --- .../dynamicresources/ModelLocationCache.java | 34 +++++++++---------- .../dynamic_resources/ModelBakeryMixin.java | 6 ---- 2 files changed, 16 insertions(+), 24 deletions(-) diff --git a/src/main/java/org/embeddedt/modernfix/dynamicresources/ModelLocationCache.java b/src/main/java/org/embeddedt/modernfix/dynamicresources/ModelLocationCache.java index 5a1bcc8e..25886e20 100644 --- a/src/main/java/org/embeddedt/modernfix/dynamicresources/ModelLocationCache.java +++ b/src/main/java/org/embeddedt/modernfix/dynamicresources/ModelLocationCache.java @@ -1,5 +1,8 @@ package org.embeddedt.modernfix.dynamicresources; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; import com.google.common.collect.ImmutableMap; import com.mojang.datafixers.util.Pair; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; @@ -14,28 +17,23 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Map; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; public class ModelLocationCache { - private static Map locationCache = Collections.emptyMap(); - public static void rebuildLocationCache() { - ArrayList>> futures = new ArrayList<>(); - for(Block block : Registry.BLOCK) { - block.getStateDefinition().getPossibleStates().forEach((state) -> { - futures.add(CompletableFuture.supplyAsync(() -> { - return Pair.of(state, BlockModelShaper.stateToModelLocation(state)); - }, Util.backgroundExecutor())); + private static final LoadingCache locationCache = CacheBuilder.newBuilder() + .maximumSize(10000) + .build(new CacheLoader() { + @Override + public ModelResourceLocation load(BlockState key) throws Exception { + return BlockModelShaper.stateToModelLocation(key); + } }); - } - - ImmutableMap.Builder builder = ImmutableMap.builder(); - for(CompletableFuture> future : futures) { - Pair pair = future.join(); - builder.put(pair.getFirst(), pair.getSecond()); - } - locationCache = builder.build(); - } public static ModelResourceLocation get(BlockState state) { - return locationCache.get(state); + try { + return locationCache.get(state); + } catch(ExecutionException e) { + throw new RuntimeException(e.getCause()); + } } } diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ModelBakeryMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ModelBakeryMixin.java index 0cb14a1a..6d993288 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ModelBakeryMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ModelBakeryMixin.java @@ -128,8 +128,6 @@ public abstract class ModelBakeryMixin { private UnbakedModel missingModel; - private static boolean firstReload = true; - /** * @author embeddedt * @reason don't load any models initially, just set up initial data structures @@ -137,10 +135,6 @@ public abstract class ModelBakeryMixin { @Overwrite protected void processLoading(ProfilerFiller arg, int maxMipLevels) { ModelLoaderRegistry.onModelLoadingStart(); - if(firstReload) { - ModelLocationCache.rebuildLocationCache(); - firstReload = false; - } try { this.missingModel = this.loadBlockModel(MISSING_MODEL_LOCATION); } catch (IOException var10) { From af731b336e37973339c33821bb146055bae3e05e Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sat, 8 Apr 2023 20:24:34 -0400 Subject: [PATCH 18/25] Clear memory reserve --- src/main/java/org/embeddedt/modernfix/ModernFixClient.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/org/embeddedt/modernfix/ModernFixClient.java b/src/main/java/org/embeddedt/modernfix/ModernFixClient.java index 29673d5d..712e7759 100644 --- a/src/main/java/org/embeddedt/modernfix/ModernFixClient.java +++ b/src/main/java/org/embeddedt/modernfix/ModernFixClient.java @@ -17,6 +17,7 @@ import net.minecraftforge.eventbus.api.EventPriority; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.ModContainer; import net.minecraftforge.fml.ModList; +import net.minecraftforge.fml.common.ObfuscationReflectionHelper; import net.minecraftforge.fml.network.NetworkEvent; import org.embeddedt.modernfix.core.ModernFixMixinPlugin; import org.embeddedt.modernfix.load.LoadEvents; @@ -38,6 +39,8 @@ public class ModernFixClient { private String brandingString = null; public ModernFixClient() { + // clear reserve as it's not needed + ObfuscationReflectionHelper.setPrivateValue(Minecraft.class, null, new byte[0], "field_71444_a"); if(ModernFixMixinPlugin.instance.isOptionEnabled("perf.faster_singleplayer_load.ClientEvents")) { MinecraftForge.EVENT_BUS.register(new LoadEvents()); } From d2e2040ce4cb668bad2df8e92851fba36ebbd655 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sat, 8 Apr 2023 20:28:48 -0400 Subject: [PATCH 19/25] Reduce allocation rate from biome zoomer --- .../core/config/ModernFixEarlyConfig.java | 1 + .../FuzzyOffsetBiomeZoomerMixin.java | 57 +++++++++++++++++++ src/main/resources/modernfix.mixins.json | 1 + 3 files changed, 59 insertions(+) create mode 100644 src/main/java/org/embeddedt/modernfix/mixin/perf/biome_zoomer/FuzzyOffsetBiomeZoomerMixin.java diff --git a/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java b/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java index 9d5625e9..ddaed12e 100644 --- a/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java +++ b/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java @@ -42,6 +42,7 @@ public class ModernFixEarlyConfig { this.addMixinRule("perf.state_definition_construct", modPresent("ferritecore")); this.addMixinRule("perf.cache_strongholds", true); this.addMixinRule("perf.cache_upgraded_structures", true); + this.addMixinRule("perf.biome_zoomer", true); this.addMixinRule("bugfix.concurrency", true); this.addMixinRule("bugfix.edge_chunk_not_saved", true); this.addMixinRule("bugfix.packet_leak", false); diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/biome_zoomer/FuzzyOffsetBiomeZoomerMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/biome_zoomer/FuzzyOffsetBiomeZoomerMixin.java new file mode 100644 index 00000000..fc72b8d3 --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/biome_zoomer/FuzzyOffsetBiomeZoomerMixin.java @@ -0,0 +1,57 @@ +package org.embeddedt.modernfix.mixin.perf.biome_zoomer; + +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.biome.BiomeManager; +import net.minecraft.world.level.biome.FuzzyOffsetBiomeZoomer; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(FuzzyOffsetBiomeZoomer.class) +public abstract class FuzzyOffsetBiomeZoomerMixin { + @Shadow protected static double getFiddledDistance(long seed, int x, int y, int z, double scaleX, double scaleY, double scaleZ) { + throw new AssertionError(); + } + + /** + * @author embeddedt + * @reason use the modern logic that doesn't allocate an array of 8 doubles every time + */ + @Overwrite + public Biome getBiome(long seed, int xIn, int yIn, int zIn, BiomeManager.NoiseBiomeSource biomeReader) { + int i = xIn - 2; + int j = yIn - 2; + int k = zIn - 2; + int l = i >> 2; + int i1 = j >> 2; + int j1 = k >> 2; + double d0 = (double)(i & 3) / 4.0D; + double d1 = (double)(j & 3) / 4.0D; + double d2 = (double)(k & 3) / 4.0D; + int k1 = 0; + double d3 = Double.POSITIVE_INFINITY; + + for(int l1 = 0; l1 < 8; ++l1) { + boolean flag = (l1 & 4) == 0; + boolean flag1 = (l1 & 2) == 0; + boolean flag2 = (l1 & 1) == 0; + int i2 = flag ? l : l + 1; + int j2 = flag1 ? i1 : i1 + 1; + int k2 = flag2 ? j1 : j1 + 1; + double d4 = flag ? d0 : d0 - 1.0D; + double d5 = flag1 ? d1 : d1 - 1.0D; + double d6 = flag2 ? d2 : d2 - 1.0D; + double d7 = getFiddledDistance(seed, i2, j2, k2, d4, d5, d6); + if (d3 > d7) { + k1 = l1; + d3 = d7; + } + } + + int l2 = (k1 & 4) == 0 ? l : l + 1; + int i3 = (k1 & 2) == 0 ? i1 : i1 + 1; + int j3 = (k1 & 1) == 0 ? j1 : j1 + 1; + return biomeReader.getNoiseBiome(l2, i3, j3); + } + +} diff --git a/src/main/resources/modernfix.mixins.json b/src/main/resources/modernfix.mixins.json index 47cd50be..ab13d662 100644 --- a/src/main/resources/modernfix.mixins.json +++ b/src/main/resources/modernfix.mixins.json @@ -61,6 +61,7 @@ "perf.cache_upgraded_structures.StructureManagerMixin", "perf.cache_strongholds.ServerLevelMixin", "perf.state_definition_construct.StateDefinitionMixin", + "perf.biome_zoomer.FuzzyOffsetBiomeZoomerMixin", "devenv.MinecraftServerMixin" ], "client": [ From 9ab6bc83b8ef5c6d1d63d2331e9613d627b61a08 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sat, 8 Apr 2023 21:12:21 -0400 Subject: [PATCH 20/25] Fix debug overlay leaking chunks from the last world --- .../org/embeddedt/modernfix/ModernFixClient.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/main/java/org/embeddedt/modernfix/ModernFixClient.java b/src/main/java/org/embeddedt/modernfix/ModernFixClient.java index 712e7759..148ac4d7 100644 --- a/src/main/java/org/embeddedt/modernfix/ModernFixClient.java +++ b/src/main/java/org/embeddedt/modernfix/ModernFixClient.java @@ -3,16 +3,20 @@ package org.embeddedt.modernfix; import com.mojang.datafixers.util.Pair; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.components.DebugScreenOverlay; import net.minecraft.client.gui.screens.ConnectScreen; import net.minecraft.client.gui.screens.TitleScreen; import net.minecraft.network.syncher.EntityDataAccessor; import net.minecraft.network.syncher.SynchedEntityData; import net.minecraft.world.entity.Entity; +import net.minecraftforge.client.event.ClientPlayerNetworkEvent; import net.minecraftforge.client.event.GuiOpenEvent; import net.minecraftforge.client.event.GuiScreenEvent; import net.minecraftforge.client.event.RenderGameOverlayEvent; +import net.minecraftforge.client.gui.ForgeIngameGui; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.TickEvent; +import net.minecraftforge.event.world.WorldEvent; import net.minecraftforge.eventbus.api.EventPriority; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.ModContainer; @@ -86,6 +90,16 @@ public class ModernFixClient { } } + @SubscribeEvent + public void onDisconnect(WorldEvent.Unload event) { + if(event.getWorld().isClientSide()) { + DebugScreenOverlay overlay = ObfuscationReflectionHelper.getPrivateValue(ForgeIngameGui.class, (ForgeIngameGui)Minecraft.getInstance().gui, "debugOverlay"); + if(overlay != null) { + Minecraft.getInstance().tell(overlay::clearChunkCache); + } + } + } + /** * Check if the IDs match and remap them if not. * @return true if ID remap was needed From a2af0cf8359c02062033a52a336ed7f8a7d7c9b5 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sat, 8 Apr 2023 22:15:32 -0400 Subject: [PATCH 21/25] Add blockstate compression optimization (off by default for mod compat) --- .../modernfix/core/ModernFixMixinPlugin.java | 41 ++++++- .../core/config/ModernFixEarlyConfig.java | 1 + .../BlockBehaviourMixin.java | 14 +++ .../BlockStateBaseMixin.java | 102 ++++++++++++++++++ .../resources/META-INF/accesstransformer.cfg | 13 ++- src/main/resources/modernfix.mixins.json | 2 + 6 files changed, 171 insertions(+), 2 deletions(-) create mode 100644 src/main/java/org/embeddedt/modernfix/mixin/perf/compress_blockstate/BlockBehaviourMixin.java create mode 100644 src/main/java/org/embeddedt/modernfix/mixin/perf/compress_blockstate/BlockStateBaseMixin.java diff --git a/src/main/java/org/embeddedt/modernfix/core/ModernFixMixinPlugin.java b/src/main/java/org/embeddedt/modernfix/core/ModernFixMixinPlugin.java index 0c22fd8d..be713fa6 100644 --- a/src/main/java/org/embeddedt/modernfix/core/ModernFixMixinPlugin.java +++ b/src/main/java/org/embeddedt/modernfix/core/ModernFixMixinPlugin.java @@ -1,7 +1,9 @@ package org.embeddedt.modernfix.core; +import com.google.common.collect.ImmutableList; import com.google.common.io.Resources; import cpw.mods.modlauncher.*; +import cpw.mods.modlauncher.api.INameMappingService; import cpw.mods.modlauncher.api.LamdbaExceptionUtils; import net.minecraftforge.fml.common.ObfuscationReflectionHelper; import net.minecraftforge.fml.loading.LoadingModList; @@ -11,6 +13,7 @@ import org.embeddedt.modernfix.classloading.ModernFixResourceFinder; import org.embeddedt.modernfix.core.config.ModernFixEarlyConfig; import org.embeddedt.modernfix.core.config.Option; import org.embeddedt.modernfix.util.DummyList; +import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.*; import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; import org.spongepowered.asm.mixin.extensibility.IMixinInfo; @@ -26,6 +29,8 @@ import java.net.URL; import java.net.URLClassLoader; import java.util.*; import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; public class ModernFixMixinPlugin implements IMixinConfigPlugin { private static final String MIXIN_PACKAGE_ROOT = "org.embeddedt.modernfix.mixin."; @@ -212,6 +217,40 @@ public class ModernFixMixinPlugin implements IMixinConfigPlugin { @Override public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { - + if(mixinClassName.equals("org.embeddedt.modernfix.mixin.perf.compress_blockstate.BlockStateBaseMixin")) { + // Delete unused fields off BlockStateBase + Set fieldsToDelete = Stream.of( + "field_235702_f_", // isAir + "field_235703_g_", // material + "field_235705_i_", // destroySpeed + "field_235706_j_", // requiresCorrectToolForDrops + "field_235707_k_", // canOcclude + "field_235708_l_", // isRedstoneConductor + "field_235709_m_", // isSuffocating + "field_235710_n_", // isViewBlocking + "field_235711_o_", // hasPostProcess + "field_235712_p_" // emissiveRendering + ).map(name -> ObfuscationReflectionHelper.remapName(INameMappingService.Domain.FIELD, name)).collect(Collectors.toSet()); + targetClass.fields.removeIf(field -> { + if(fieldsToDelete.contains(field.name)) { + logger.info("Removing " + field.name); + return true; + } + return false; + }); + for(MethodNode m : targetClass.methods) { + if(m.name.equals("")) { + ListIterator iter = m.instructions.iterator(); + while(iter.hasNext()) { + AbstractInsnNode node = iter.next(); + if(node.getOpcode() == Opcodes.PUTFIELD) { + if(fieldsToDelete.contains(((FieldInsnNode)node).name)) { + iter.remove(); + } + } + } + } + } + } } } \ No newline at end of file diff --git a/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java b/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java index ddaed12e..9bf69c7e 100644 --- a/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java +++ b/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java @@ -43,6 +43,7 @@ public class ModernFixEarlyConfig { this.addMixinRule("perf.cache_strongholds", true); this.addMixinRule("perf.cache_upgraded_structures", true); this.addMixinRule("perf.biome_zoomer", true); + this.addMixinRule("perf.compress_blockstate", false); this.addMixinRule("bugfix.concurrency", true); this.addMixinRule("bugfix.edge_chunk_not_saved", true); this.addMixinRule("bugfix.packet_leak", false); diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/compress_blockstate/BlockBehaviourMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/compress_blockstate/BlockBehaviourMixin.java new file mode 100644 index 00000000..852b8f52 --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/compress_blockstate/BlockBehaviourMixin.java @@ -0,0 +1,14 @@ +package org.embeddedt.modernfix.mixin.perf.compress_blockstate; + +import net.minecraft.world.level.block.state.BlockBehaviour; +import net.minecraft.world.level.block.state.BlockState; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; + +@Mixin(BlockBehaviour.class) +public class BlockBehaviourMixin { + @Overwrite + protected boolean isAir(BlockState state) { + return state.getBlock().properties.isAir; + } +} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/compress_blockstate/BlockStateBaseMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/compress_blockstate/BlockStateBaseMixin.java new file mode 100644 index 00000000..c3eeabd6 --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/compress_blockstate/BlockStateBaseMixin.java @@ -0,0 +1,102 @@ +package org.embeddedt.modernfix.mixin.perf.compress_blockstate; + +import com.google.common.collect.ImmutableMap; +import com.mojang.serialization.MapCodec; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockBehaviour; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateHolder; +import net.minecraft.world.level.block.state.properties.Property; +import net.minecraft.world.level.material.Material; +import org.objectweb.asm.Opcodes; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(BlockBehaviour.BlockStateBase.class) +public abstract class BlockStateBaseMixin extends StateHolder { + protected BlockStateBaseMixin(Block object, ImmutableMap, Comparable> immutableMap, MapCodec mapCodec) { + super(object, immutableMap, mapCodec); + } + + @Redirect(method = "*", at = @At( + value = "FIELD", + opcode = Opcodes.GETFIELD, + target = "Lnet/minecraft/world/level/block/state/BlockBehaviour$BlockStateBase;material:Lnet/minecraft/world/level/material/Material;" + )) + private Material getMaterial(BlockBehaviour.BlockStateBase base) { + return this.owner.properties.material; + } + + @Redirect(method = "*", at = @At( + value = "FIELD", + opcode = Opcodes.GETFIELD, + target = "Lnet/minecraft/world/level/block/state/BlockBehaviour$BlockStateBase;destroySpeed:F" + )) + private float getDestroyTime(BlockBehaviour.BlockStateBase base) { + return this.owner.properties.destroyTime; + } + + @Redirect(method = "*", at = @At( + value = "FIELD", + opcode = Opcodes.GETFIELD, + target = "Lnet/minecraft/world/level/block/state/BlockBehaviour$BlockStateBase;requiresCorrectToolForDrops:Z" + )) + private boolean getRequiresTool(BlockBehaviour.BlockStateBase base) { + return this.owner.properties.requiresCorrectToolForDrops; + } + + @Redirect(method = "*", at = @At( + value = "FIELD", + opcode = Opcodes.GETFIELD, + target = "Lnet/minecraft/world/level/block/state/BlockBehaviour$BlockStateBase;canOcclude:Z" + )) + private boolean getCanOcclude(BlockBehaviour.BlockStateBase base) { + return this.owner.properties.canOcclude; + } + + @Redirect(method = "*", at = @At( + value = "FIELD", + opcode = Opcodes.GETFIELD, + target = "Lnet/minecraft/world/level/block/state/BlockBehaviour$BlockStateBase;isRedstoneConductor:Lnet/minecraft/world/level/block/state/BlockBehaviour$StatePredicate;" + )) + private BlockBehaviour.StatePredicate getRedstoneConductor(BlockBehaviour.BlockStateBase base) { + return this.owner.properties.isRedstoneConductor; + } + + @Redirect(method = "*", at = @At( + value = "FIELD", + opcode = Opcodes.GETFIELD, + target = "Lnet/minecraft/world/level/block/state/BlockBehaviour$BlockStateBase;isSuffocating:Lnet/minecraft/world/level/block/state/BlockBehaviour$StatePredicate;" + )) + private BlockBehaviour.StatePredicate getSuffocating(BlockBehaviour.BlockStateBase base) { + return this.owner.properties.isSuffocating; + } + + @Redirect(method = "*", at = @At( + value = "FIELD", + opcode = Opcodes.GETFIELD, + target = "Lnet/minecraft/world/level/block/state/BlockBehaviour$BlockStateBase;isViewBlocking:Lnet/minecraft/world/level/block/state/BlockBehaviour$StatePredicate;" + )) + private BlockBehaviour.StatePredicate getViewBlocking(BlockBehaviour.BlockStateBase base) { + return this.owner.properties.isViewBlocking; + } + + @Redirect(method = "*", at = @At( + value = "FIELD", + opcode = Opcodes.GETFIELD, + target = "Lnet/minecraft/world/level/block/state/BlockBehaviour$BlockStateBase;hasPostProcess:Lnet/minecraft/world/level/block/state/BlockBehaviour$StatePredicate;" + )) + private BlockBehaviour.StatePredicate getPostProcess(BlockBehaviour.BlockStateBase base) { + return this.owner.properties.hasPostProcess; + } + + @Redirect(method = "*", at = @At( + value = "FIELD", + opcode = Opcodes.GETFIELD, + target = "Lnet/minecraft/world/level/block/state/BlockBehaviour$BlockStateBase;emissiveRendering:Lnet/minecraft/world/level/block/state/BlockBehaviour$StatePredicate;" + )) + private BlockBehaviour.StatePredicate getEmissiveRendering(BlockBehaviour.BlockStateBase base) { + return this.owner.properties.emissiveRendering; + } +} diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg index 7e921c8a..6c8b87f3 100644 --- a/src/main/resources/META-INF/accesstransformer.cfg +++ b/src/main/resources/META-INF/accesstransformer.cfg @@ -11,4 +11,15 @@ public net.minecraft.server.MinecraftServer field_211151_aa # nextTickTime public net.minecraft.client.Minecraft field_213277_ad # progressListener public-f net.minecraft.network.datasync.DataParameter field_187157_a # id public-f net.minecraft.network.datasync.EntityDataManager field_187234_c # itemsById -public-f net.minecraft.network.datasync.EntityDataManager field_187235_d # lock \ No newline at end of file +public-f net.minecraft.network.datasync.EntityDataManager field_187235_d # lock +public net.minecraft.block.AbstractBlock field_235684_aB_ # properties +public net.minecraft.block.AbstractBlock$Properties field_200953_a # material +public net.minecraft.block.AbstractBlock$Properties field_226895_m_ # canOcclude +public net.minecraft.block.AbstractBlock$Properties field_235813_o_ # isAir +public net.minecraft.block.AbstractBlock$Properties field_235815_q_ # isRedstoneConductor +public net.minecraft.block.AbstractBlock$Properties field_235816_r_ # isSuffocating +public net.minecraft.block.AbstractBlock$Properties field_235817_s_ # isViewBlocking +public net.minecraft.block.AbstractBlock$Properties field_235818_t_ # hasPostProcess +public net.minecraft.block.AbstractBlock$Properties field_235819_u_ # emissiveRendering +public net.minecraft.block.AbstractBlock$Properties field_235806_h_ # requiresCorrectToolForDrops +public net.minecraft.block.AbstractBlock$Properties field_200959_g # destroyTime \ No newline at end of file diff --git a/src/main/resources/modernfix.mixins.json b/src/main/resources/modernfix.mixins.json index ab13d662..36ad8afb 100644 --- a/src/main/resources/modernfix.mixins.json +++ b/src/main/resources/modernfix.mixins.json @@ -62,6 +62,8 @@ "perf.cache_strongholds.ServerLevelMixin", "perf.state_definition_construct.StateDefinitionMixin", "perf.biome_zoomer.FuzzyOffsetBiomeZoomerMixin", + "perf.compress_blockstate.BlockStateBaseMixin", + "perf.compress_blockstate.BlockBehaviourMixin", "devenv.MinecraftServerMixin" ], "client": [ From a6d924535ef81414d4ade510f6f1ca9773e5cfe6 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sun, 9 Apr 2023 12:29:47 -0400 Subject: [PATCH 22/25] Fix KubeJS resources not being scanned for textures --- .../dynamicresources/ResourcePackHandler.java | 55 +++++++++++++++++++ .../dynamic_resources/ModelBakeryMixin.java | 5 +- 2 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 src/main/java/org/embeddedt/modernfix/dynamicresources/ResourcePackHandler.java diff --git a/src/main/java/org/embeddedt/modernfix/dynamicresources/ResourcePackHandler.java b/src/main/java/org/embeddedt/modernfix/dynamicresources/ResourcePackHandler.java new file mode 100644 index 00000000..ee6c5fca --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/dynamicresources/ResourcePackHandler.java @@ -0,0 +1,55 @@ +package org.embeddedt.modernfix.dynamicresources; + +import dev.latvian.kubejs.script.data.KubeJSResourcePack; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.PackResources; +import net.minecraft.server.packs.resources.ResourceManager; +import net.minecraftforge.fml.ModList; +import org.embeddedt.modernfix.util.FileUtil; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class ResourcePackHandler { + private static final List packHandlers = new ArrayList<>(); + public static Collection getExtraResources(ResourceManager manager, String path, Predicate matchPredicate) { + final String normalizedPath = FileUtil.normalize(path); + return manager.listPacks().flatMap(pack -> packHandlers.stream().flatMap(handler -> { + if(handler.shouldHandle(pack)) { + return handler.getExtraResources(pack, normalizedPath, matchPredicate); + } else + return Stream.of(); + })).collect(Collectors.toList()); + } + + interface PackHandler { + Stream getExtraResources(PackResources pack, String path, Predicate matchPredicate); + boolean shouldHandle(PackResources pack); + } + + static class KubeJSPackHandler implements PackHandler { + + @Override + public Stream getExtraResources(PackResources pack, String path, Predicate matchPredicate) { + KubeJSResourcePack p = (KubeJSResourcePack)pack; + return p.getCachedResources().keySet().stream() + .filter(l -> l.getPath().startsWith(path)) + .filter(l -> matchPredicate.test(l.getPath())); + } + + @Override + public boolean shouldHandle(PackResources pack) { + return pack instanceof KubeJSResourcePack; + } + } + + static { + if(ModList.get().isLoaded("kubejs")) { + packHandlers.add(new KubeJSPackHandler()); + } + } +} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ModelBakeryMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ModelBakeryMixin.java index 6d993288..66aaeba5 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ModelBakeryMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ModelBakeryMixin.java @@ -35,6 +35,7 @@ import org.apache.logging.log4j.Logger; import org.embeddedt.modernfix.ModernFix; import org.embeddedt.modernfix.dynamicresources.DynamicBakedModelProvider; import org.embeddedt.modernfix.dynamicresources.ModelLocationCache; +import org.embeddedt.modernfix.dynamicresources.ResourcePackHandler; import org.spongepowered.asm.mixin.*; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -159,7 +160,9 @@ public abstract class ModelBakeryMixin { */ private void gatherModelMaterials(Set materialSet) { Stopwatch stopwatch = Stopwatch.createStarted(); - Collection allModels = this.resourceManager.listResources("models", path -> path.endsWith(".json")); + List allModels = new ArrayList<>(this.resourceManager.listResources("models", path -> path.endsWith(".json"))); + // for KubeJS, etc. + allModels.addAll(ResourcePackHandler.getExtraResources(this.resourceManager, "models", path -> path.endsWith(".json"))); List>> modelBytes = new ArrayList<>(); for(ResourceLocation fileLocation : allModels) { modelBytes.add(CompletableFuture.supplyAsync(() -> { From 8937ca020d0bd4dc3488b90effeeabc5b4aeaf8d Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sun, 9 Apr 2023 12:48:00 -0400 Subject: [PATCH 23/25] Add ModelBakeEvent alternative for dynamic models --- .../DynamicModelBakeEvent.java | 33 +++++++++++++++++++ .../dynamic_resources/ModelBakeryMixin.java | 8 +++-- 2 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 src/main/java/org/embeddedt/modernfix/dynamicresources/DynamicModelBakeEvent.java diff --git a/src/main/java/org/embeddedt/modernfix/dynamicresources/DynamicModelBakeEvent.java b/src/main/java/org/embeddedt/modernfix/dynamicresources/DynamicModelBakeEvent.java new file mode 100644 index 00000000..8a199d43 --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/dynamicresources/DynamicModelBakeEvent.java @@ -0,0 +1,33 @@ +package org.embeddedt.modernfix.dynamicresources; + +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.resources.ResourceLocation; +import net.minecraftforge.eventbus.api.Event; + +/** + * Fired when a model is baked dynamically. Intended to be used as a replacement for ModelBakeEvent + * if mods want to replace a model. + *

+ * Note that this event can fire many times for the same resource location, as models are unloaded + * if unused/under memory pressure. + */ +public class DynamicModelBakeEvent extends Event { + private final ResourceLocation location; + private BakedModel model; + public DynamicModelBakeEvent(ResourceLocation location, BakedModel model) { + this.location = location; + this.model = model; + } + + public ResourceLocation getLocation() { + return this.location; + } + + public BakedModel getModel() { + return this.model; + } + + public void setModel(BakedModel model) { + this.model = model; + } +} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ModelBakeryMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ModelBakeryMixin.java index 66aaeba5..f1a6b8f4 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ModelBakeryMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ModelBakeryMixin.java @@ -30,10 +30,12 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.StateDefinition; import net.minecraftforge.client.ForgeHooksClient; import net.minecraftforge.client.model.ModelLoaderRegistry; +import net.minecraftforge.common.MinecraftForge; import org.apache.commons.lang3.tuple.Triple; import org.apache.logging.log4j.Logger; import org.embeddedt.modernfix.ModernFix; import org.embeddedt.modernfix.dynamicresources.DynamicBakedModelProvider; +import org.embeddedt.modernfix.dynamicresources.DynamicModelBakeEvent; import org.embeddedt.modernfix.dynamicresources.ModelLocationCache; import org.embeddedt.modernfix.dynamicresources.ResourcePackHandler; import org.spongepowered.asm.mixin.*; @@ -289,8 +291,10 @@ public abstract class ModelBakeryMixin { if(ibakedmodel == null) { ibakedmodel = iunbakedmodel.bake((ModelBakery) (Object) this, textureGetter, arg2, arg); } - this.bakedCache.put(triple, ibakedmodel); - return ibakedmodel; + DynamicModelBakeEvent event = new DynamicModelBakeEvent(arg, ibakedmodel); + MinecraftForge.EVENT_BUS.post(event); + this.bakedCache.put(triple, event.getModel()); + return event.getModel(); } } } From e5cd9f57b56e845866ea051891e10a3c1330257a Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sun, 9 Apr 2023 13:52:40 -0400 Subject: [PATCH 24/25] CTM support --- build.gradle | 1 + .../DynamicModelBakeEvent.java | 20 ++++- .../dynamic_resources/ModelBakeryMixin.java | 6 +- .../ctm/CTMPackReloadListenerMixin.java | 75 +++++++++++++++++ .../ctm/TextureMetadataHandlerMixin.java | 82 +++++++++++++++++++ src/main/resources/modernfix.mixins.json | 2 + 6 files changed, 182 insertions(+), 4 deletions(-) create mode 100644 src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ctm/CTMPackReloadListenerMixin.java create mode 100644 src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ctm/TextureMetadataHandlerMixin.java diff --git a/build.gradle b/build.gradle index 31dd054f..00e55d3f 100644 --- a/build.gradle +++ b/build.gradle @@ -96,6 +96,7 @@ dependencies { modCompileOnly("curse.maven:babel-436964:3196072") modCompileOnly("curse.maven:twforest-227639:3575220") modRuntimeOnly("curse.maven:ferritecore-429235:4074330") + modCompileOnly("team.chisel.ctm:CTM:${ctm_version}") } tasks.withType(JavaCompile) { diff --git a/src/main/java/org/embeddedt/modernfix/dynamicresources/DynamicModelBakeEvent.java b/src/main/java/org/embeddedt/modernfix/dynamicresources/DynamicModelBakeEvent.java index 8a199d43..76b6c3d0 100644 --- a/src/main/java/org/embeddedt/modernfix/dynamicresources/DynamicModelBakeEvent.java +++ b/src/main/java/org/embeddedt/modernfix/dynamicresources/DynamicModelBakeEvent.java @@ -1,8 +1,12 @@ package org.embeddedt.modernfix.dynamicresources; import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.client.resources.model.ModelManager; +import net.minecraft.client.resources.model.UnbakedModel; import net.minecraft.resources.ResourceLocation; +import net.minecraftforge.client.model.ModelLoader; import net.minecraftforge.eventbus.api.Event; +import net.minecraftforge.fml.event.lifecycle.IModBusEvent; /** * Fired when a model is baked dynamically. Intended to be used as a replacement for ModelBakeEvent @@ -11,12 +15,16 @@ import net.minecraftforge.eventbus.api.Event; * Note that this event can fire many times for the same resource location, as models are unloaded * if unused/under memory pressure. */ -public class DynamicModelBakeEvent extends Event { +public class DynamicModelBakeEvent extends Event implements IModBusEvent { private final ResourceLocation location; private BakedModel model; - public DynamicModelBakeEvent(ResourceLocation location, BakedModel model) { + private final UnbakedModel unbakedModel; + private final ModelLoader modelLoader; + public DynamicModelBakeEvent(ResourceLocation location, UnbakedModel unbakedModel, BakedModel model, ModelLoader loader) { this.location = location; this.model = model; + this.unbakedModel = unbakedModel; + this.modelLoader = loader; } public ResourceLocation getLocation() { @@ -27,6 +35,14 @@ public class DynamicModelBakeEvent extends Event { return this.model; } + public UnbakedModel getUnbakedModel() { + return this.unbakedModel; + } + + public ModelLoader getModelLoader() { + return this.modelLoader; + } + public void setModel(BakedModel model) { this.model = model; } diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ModelBakeryMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ModelBakeryMixin.java index f1a6b8f4..56522a38 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ModelBakeryMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ModelBakeryMixin.java @@ -29,8 +29,10 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.StateDefinition; import net.minecraftforge.client.ForgeHooksClient; +import net.minecraftforge.client.model.ModelLoader; import net.minecraftforge.client.model.ModelLoaderRegistry; import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.fml.ModLoader; import org.apache.commons.lang3.tuple.Triple; import org.apache.logging.log4j.Logger; import org.embeddedt.modernfix.ModernFix; @@ -291,8 +293,8 @@ public abstract class ModelBakeryMixin { if(ibakedmodel == null) { ibakedmodel = iunbakedmodel.bake((ModelBakery) (Object) this, textureGetter, arg2, arg); } - DynamicModelBakeEvent event = new DynamicModelBakeEvent(arg, ibakedmodel); - MinecraftForge.EVENT_BUS.post(event); + DynamicModelBakeEvent event = new DynamicModelBakeEvent(arg, iunbakedmodel, ibakedmodel, (ModelLoader)(Object)this); + ModLoader.get().postEvent(event); this.bakedCache.put(triple, event.getModel()); return event.getModel(); } diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ctm/CTMPackReloadListenerMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ctm/CTMPackReloadListenerMixin.java new file mode 100644 index 00000000..2fcd6028 --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ctm/CTMPackReloadListenerMixin.java @@ -0,0 +1,75 @@ +package org.embeddedt.modernfix.mixin.perf.dynamic_resources.ctm; + +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import net.minecraft.client.renderer.ItemBlockRenderTypes; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.block.BlockModelShaper; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.client.resources.model.ModelResourceLocation; +import net.minecraft.client.resources.model.MultiPartBakedModel; +import net.minecraft.client.resources.model.WeightedBakedModel; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.eventbus.api.EventPriority; +import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import net.minecraftforge.registries.ForgeRegistries; +import net.minecraftforge.registries.IRegistryDelegate; +import org.embeddedt.modernfix.dynamicresources.DynamicModelBakeEvent; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import team.chisel.ctm.client.model.AbstractCTMBakedModel; +import team.chisel.ctm.client.util.CTMPackReloadListener; + +import java.util.Map; +import java.util.function.Predicate; + +@Mixin(CTMPackReloadListener.class) +public abstract class CTMPackReloadListenerMixin { + @Shadow @Final private static Map, Predicate> blockRenderChecks; + + @Shadow protected abstract Predicate getLayerCheck(BlockState state, BakedModel model); + + @Shadow protected abstract Predicate getExistingRenderCheck(Block block); + + private Map locationToState = new Object2ObjectOpenHashMap<>(); + + @Inject(method = "", at = @At("RETURN")) + private void onInit(CallbackInfo ci) { + FMLJavaModLoadingContext.get().getModEventBus().addListener(EventPriority.LOW, this::onModelBake); + } + + @Overwrite(remap = false) + private void refreshLayerHacks() { + blockRenderChecks.forEach((b, p) -> ItemBlockRenderTypes.setRenderLayer((Block) b.get(), p)); + blockRenderChecks.clear(); + if(locationToState.isEmpty()) { + for(Block block : ForgeRegistries.BLOCKS.getValues()) { + for(BlockState state : block.getStateDefinition().getPossibleStates()) { + locationToState.put(BlockModelShaper.stateToModelLocation(state), state); + } + } + } + } + + private void onModelBake(DynamicModelBakeEvent event) { + if(!(event.getModel() instanceof AbstractCTMBakedModel || event.getModel() instanceof WeightedBakedModel || event.getModel() instanceof MultiPartBakedModel)) + return; + BlockState state = locationToState.get(event.getLocation()); + if(state == null) + return; + Block block = state.getBlock(); + if(blockRenderChecks.containsKey(block.delegate)) + return; + Predicate newPredicate = this.getLayerCheck(state, event.getModel()); + if(newPredicate != null) { + blockRenderChecks.put(block.delegate, this.getExistingRenderCheck(block)); + ItemBlockRenderTypes.setRenderLayer(block, newPredicate); + } + } +} diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ctm/TextureMetadataHandlerMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ctm/TextureMetadataHandlerMixin.java new file mode 100644 index 00000000..4d52de4e --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ctm/TextureMetadataHandlerMixin.java @@ -0,0 +1,82 @@ +package org.embeddedt.modernfix.mixin.perf.dynamic_resources.ctm; + +import com.mojang.datafixers.util.Pair; +import it.unimi.dsi.fastutil.objects.Object2BooleanMap; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.client.resources.model.Material; +import net.minecraft.client.resources.model.UnbakedModel; +import net.minecraft.resources.ResourceLocation; +import net.minecraftforge.client.model.ModelLoader; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import org.embeddedt.modernfix.dynamicresources.DynamicModelBakeEvent; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import team.chisel.ctm.CTM; +import team.chisel.ctm.client.model.AbstractCTMBakedModel; +import team.chisel.ctm.client.texture.IMetadataSectionCTM; +import team.chisel.ctm.client.util.ResourceUtil; +import team.chisel.ctm.client.util.TextureMetadataHandler; + +import javax.annotation.Nonnull; +import java.io.IOException; +import java.util.*; + +@Mixin(TextureMetadataHandler.class) +public abstract class TextureMetadataHandlerMixin { + + @Shadow @Nonnull protected abstract BakedModel wrap(ResourceLocation loc, UnbakedModel model, BakedModel object, ModelLoader loader) throws IOException; + + @SubscribeEvent + public void onDynamicModelBake(DynamicModelBakeEvent event) { + UnbakedModel rootModel = event.getUnbakedModel(); + BakedModel baked = event.getModel(); + ResourceLocation rl = event.getLocation(); + if (!(baked instanceof AbstractCTMBakedModel) && !baked.isCustomRenderer()) { + Deque dependencies = new ArrayDeque<>(); + Set seenModels = new HashSet<>(); + dependencies.push(rl); + seenModels.add(rl); + boolean shouldWrap = false; + Set> errors = new HashSet<>(); + // Breadth-first loop through dependencies, exiting as soon as a CTM texture is found, and skipping duplicates/cycles + while (!shouldWrap && !dependencies.isEmpty()) { + ResourceLocation dep = dependencies.pop(); + UnbakedModel model; + try { + model = dep == rl ? rootModel : event.getModelLoader().getModel(dep); + } catch (Exception e) { + continue; + } + + Collection textures = model.getMaterials(event.getModelLoader()::getModel, errors); + Collection newDependencies = model.getDependencies(); + for (Material tex : textures) { + IMetadataSectionCTM meta = null; + // Cache all dependent texture metadata + try { + meta = ResourceUtil.getMetadata(ResourceUtil.spriteToAbsolute(tex.texture())); + } catch (IOException e) {} // Fallthrough + if (meta != null) { + // At least one texture has CTM metadata, so we should wrap this model + shouldWrap = true; + } + } + + for (ResourceLocation newDep : newDependencies) { + if (seenModels.add(newDep)) { + dependencies.push(newDep); + } + } + } + if (shouldWrap) { + try { + event.setModel(wrap(rl, rootModel, baked, event.getModelLoader())); + dependencies.clear(); + } catch (IOException e) { + CTM.logger.error("Could not wrap model " + rl + ". Aborting...", e); + } + } + } + } +} diff --git a/src/main/resources/modernfix.mixins.json b/src/main/resources/modernfix.mixins.json index 36ad8afb..0d212903 100644 --- a/src/main/resources/modernfix.mixins.json +++ b/src/main/resources/modernfix.mixins.json @@ -78,6 +78,8 @@ "perf.dynamic_resources.BlockModelShaperMixin", "perf.dynamic_resources.ItemModelShaperMixin", "perf.dynamic_resources.ModelBakeryMixin", + "perf.dynamic_resources.ctm.TextureMetadataHandlerMixin", + "perf.dynamic_resources.ctm.CTMPackReloadListenerMixin", "perf.model_optimizations.OBJLoaderMixin", "perf.model_optimizations.SelectorMixin", "perf.model_optimizations.TransformationMatrixMixin", From 882f4832dfa222760c90953263efaf510146674d Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sun, 9 Apr 2023 14:03:32 -0400 Subject: [PATCH 25/25] Allow concurrent retrieval of models from the cache --- .../dynamic_resources/ModelBakeryMixin.java | 96 ++++++++++--------- 1 file changed, 53 insertions(+), 43 deletions(-) diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ModelBakeryMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ModelBakeryMixin.java index 56522a38..e965131e 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ModelBakeryMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ModelBakeryMixin.java @@ -236,67 +236,77 @@ public abstract class ModelBakeryMixin { * @reason synchronize */ @Overwrite - public synchronized UnbakedModel getModel(ResourceLocation modelLocation) { + public UnbakedModel getModel(ResourceLocation modelLocation) { if(modelLocation.equals(MISSING_MODEL_LOCATION)) return missingModel; - if (this.unbakedCache.containsKey(modelLocation)) { - return this.unbakedCache.get(modelLocation); - } else if (this.loadingStack.contains(modelLocation)) { - throw new IllegalStateException("Circular reference while loading " + modelLocation); + UnbakedModel existing = this.unbakedCache.get(modelLocation); + if (existing != null) { + return existing; } else { - this.loadingStack.add(modelLocation); - UnbakedModel iunbakedmodel = missingModel; + synchronized(this) { + if (this.loadingStack.contains(modelLocation)) { + throw new IllegalStateException("Circular reference while loading " + modelLocation); + } else { + this.loadingStack.add(modelLocation); + UnbakedModel iunbakedmodel = missingModel; - while(!this.loadingStack.isEmpty()) { - ResourceLocation resourcelocation = this.loadingStack.iterator().next(); + while(!this.loadingStack.isEmpty()) { + ResourceLocation resourcelocation = this.loadingStack.iterator().next(); - try { - if (!this.unbakedCache.containsKey(resourcelocation)) { - if(debugDynamicModelLoading) - LOGGER.info("Loading {}", resourcelocation); - this.loadModel(resourcelocation); + try { + if (!this.unbakedCache.containsKey(resourcelocation)) { + if(debugDynamicModelLoading) + LOGGER.info("Loading {}", resourcelocation); + this.loadModel(resourcelocation); + // TODO: in theory the cache can get evicted right here and we lose the model + // very unlikely to occur though + } + } catch (ModelBakery.BlockStateDefinitionException var9) { + LOGGER.warn(var9.getMessage()); + this.unbakedCache.put(resourcelocation, iunbakedmodel); + } catch (Exception var10) { + LOGGER.warn("Unable to load model: '{}' referenced from: {}: {}", resourcelocation, modelLocation, var10); + this.unbakedCache.put(resourcelocation, iunbakedmodel); + } finally { + this.loadingStack.remove(resourcelocation); + } } - } catch (ModelBakery.BlockStateDefinitionException var9) { - LOGGER.warn(var9.getMessage()); - this.unbakedCache.put(resourcelocation, iunbakedmodel); - } catch (Exception var10) { - LOGGER.warn("Unable to load model: '{}' referenced from: {}: {}", resourcelocation, modelLocation, var10); - this.unbakedCache.put(resourcelocation, iunbakedmodel); - } finally { - this.loadingStack.remove(resourcelocation); + + return this.unbakedCache.getOrDefault(modelLocation, iunbakedmodel); } } - - return this.unbakedCache.getOrDefault(modelLocation, iunbakedmodel); } } @Overwrite - public synchronized BakedModel getBakedModel(ResourceLocation arg, ModelState arg2, Function textureGetter) { + public BakedModel getBakedModel(ResourceLocation arg, ModelState arg2, Function textureGetter) { Triple triple = Triple.of(arg, arg2.getRotation(), arg2.isUvLocked()); - if (this.bakedCache.containsKey(triple)) { - return this.bakedCache.get(triple); + BakedModel existing = this.bakedCache.get(triple); + if (existing != null) { + return existing; } else if (this.atlasSet == null) { throw new IllegalStateException("bake called too early"); } else { - if(debugDynamicModelLoading) - LOGGER.info("Baking {}", arg); - UnbakedModel iunbakedmodel = this.getModel(arg); - iunbakedmodel.getMaterials(this::getModel, new HashSet<>()); - BakedModel ibakedmodel = null; - if (iunbakedmodel instanceof BlockModel) { - BlockModel blockmodel = (BlockModel)iunbakedmodel; - if (blockmodel.getRootModel() == GENERATION_MARKER) { - ibakedmodel = ITEM_MODEL_GENERATOR.generateBlockModel(textureGetter, blockmodel).bake((ModelBakery)(Object)this, blockmodel, this.atlasSet::getSprite, arg2, arg, false); + synchronized (this) { + if(debugDynamicModelLoading) + LOGGER.info("Baking {}", arg); + UnbakedModel iunbakedmodel = this.getModel(arg); + iunbakedmodel.getMaterials(this::getModel, new HashSet<>()); + BakedModel ibakedmodel = null; + if (iunbakedmodel instanceof BlockModel) { + BlockModel blockmodel = (BlockModel)iunbakedmodel; + if (blockmodel.getRootModel() == GENERATION_MARKER) { + ibakedmodel = ITEM_MODEL_GENERATOR.generateBlockModel(textureGetter, blockmodel).bake((ModelBakery)(Object)this, blockmodel, this.atlasSet::getSprite, arg2, arg, false); + } } + if(ibakedmodel == null) { + ibakedmodel = iunbakedmodel.bake((ModelBakery) (Object) this, textureGetter, arg2, arg); + } + DynamicModelBakeEvent event = new DynamicModelBakeEvent(arg, iunbakedmodel, ibakedmodel, (ModelLoader)(Object)this); + ModLoader.get().postEvent(event); + this.bakedCache.put(triple, event.getModel()); + return event.getModel(); } - if(ibakedmodel == null) { - ibakedmodel = iunbakedmodel.bake((ModelBakery) (Object) this, textureGetter, arg2, arg); - } - DynamicModelBakeEvent event = new DynamicModelBakeEvent(arg, iunbakedmodel, ibakedmodel, (ModelLoader)(Object)this); - ModLoader.get().postEvent(event); - this.bakedCache.put(triple, event.getModel()); - return event.getModel(); } } }