From b4ffe68adb4d85fddf2af3a7cd5fc589f0d23772 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sat, 13 May 2023 16:36:59 -0400 Subject: [PATCH 01/14] Replace Forge dynamic model bake event with modloader-independent custom solution --- .../embeddedt/modernfix/ModernFixClient.java | 14 +++++ .../api/constants/IntegrationConstants.java | 8 +++ .../ModernFixClientIntegration.java | 49 +++++++++++++++ .../modernfix/api/helpers/ModelHelpers.java | 55 +++++++++++++++++ .../modernfix/core/ModernFixMixinPlugin.java | 2 + .../platform/ModernFixPlatformHooks.java | 6 ++ .../fabric/ModernFixPlatformHooksImpl.java | 27 ++++++++ .../DynamicModelBakeEvent.java | 47 -------------- .../dynamic_resources/ModelBakeryMixin.java | 36 ++++++++--- .../ae2/RegistrationMixin.java | 61 +++++++++---------- .../ctm/CTMPackReloadListenerMixin.java | 40 ++++++------ .../ctm/TextureMetadataHandlerMixin.java | 25 ++++---- .../rs/ClientSetupMixin.java | 24 +++++--- .../ClientRegistrationHandlerMixin.java | 26 ++++---- .../forge/ModernFixPlatformHooksImpl.java | 24 ++++++++ 15 files changed, 301 insertions(+), 143 deletions(-) create mode 100644 common/src/main/java/org/embeddedt/modernfix/api/constants/IntegrationConstants.java create mode 100644 common/src/main/java/org/embeddedt/modernfix/api/entrypoint/ModernFixClientIntegration.java create mode 100644 common/src/main/java/org/embeddedt/modernfix/api/helpers/ModelHelpers.java delete mode 100644 forge/src/main/java/org/embeddedt/modernfix/forge/dynamicresources/DynamicModelBakeEvent.java diff --git a/common/src/main/java/org/embeddedt/modernfix/ModernFixClient.java b/common/src/main/java/org/embeddedt/modernfix/ModernFixClient.java index bf15ca24..f41da000 100644 --- a/common/src/main/java/org/embeddedt/modernfix/ModernFixClient.java +++ b/common/src/main/java/org/embeddedt/modernfix/ModernFixClient.java @@ -10,6 +10,8 @@ import net.minecraft.network.syncher.EntityDataAccessor; import net.minecraft.network.syncher.SynchedEntityData; import net.minecraft.server.MinecraftServer; import net.minecraft.world.entity.Entity; +import org.embeddedt.modernfix.api.constants.IntegrationConstants; +import org.embeddedt.modernfix.api.entrypoint.ModernFixClientIntegration; import org.embeddedt.modernfix.core.ModernFixMixinPlugin; import org.embeddedt.modernfix.packet.EntityIDSyncPacket; import org.embeddedt.modernfix.platform.ModernFixPlatformHooks; @@ -29,12 +31,24 @@ public class ModernFixClient { public String brandingString = null; + /** + * The list of loaded client integrations. + */ + public static List CLIENT_INTEGRATIONS = new ArrayList<>(); + public ModernFixClient() { // clear reserve as it's not needed Minecraft.reserve = new byte[0]; if(ModernFixMixinPlugin.instance.isOptionEnabled("feature.branding.F3Screen")) { brandingString = "ModernFix " + ModernFixPlatformHooks.getVersionString(); } + for(String className : ModernFixPlatformHooks.getCustomModOptions().get(IntegrationConstants.CLIENT_INTEGRATION_CLASS)) { + try { + CLIENT_INTEGRATIONS.add((ModernFixClientIntegration)Class.forName(className).getDeclaredConstructor().newInstance()); + } catch(ReflectiveOperationException | ClassCastException e) { + ModernFix.LOGGER.error("Could not instantiate integration {}", className, e); + } + } } public void resetWorldLoadStateMachine() { diff --git a/common/src/main/java/org/embeddedt/modernfix/api/constants/IntegrationConstants.java b/common/src/main/java/org/embeddedt/modernfix/api/constants/IntegrationConstants.java new file mode 100644 index 00000000..92a9a5e1 --- /dev/null +++ b/common/src/main/java/org/embeddedt/modernfix/api/constants/IntegrationConstants.java @@ -0,0 +1,8 @@ +package org.embeddedt.modernfix.api.constants; + +public class IntegrationConstants { + public static final String INTEGRATIONS_KEY = "modernfix:integration"; + + public static final String CLIENT_INTEGRATION_CLASS = "client_entrypoint"; + public static final String INTEGRATION_CLASS = "entrypoint"; +} diff --git a/common/src/main/java/org/embeddedt/modernfix/api/entrypoint/ModernFixClientIntegration.java b/common/src/main/java/org/embeddedt/modernfix/api/entrypoint/ModernFixClientIntegration.java new file mode 100644 index 00000000..f5757766 --- /dev/null +++ b/common/src/main/java/org/embeddedt/modernfix/api/entrypoint/ModernFixClientIntegration.java @@ -0,0 +1,49 @@ +package org.embeddedt.modernfix.api.entrypoint; + +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.client.resources.model.ModelBakery; +import net.minecraft.client.resources.model.ModelState; +import net.minecraft.client.resources.model.UnbakedModel; +import net.minecraft.resources.ResourceLocation; + + +/** + * Implement this interface in a mod class and add it to "modernfix:integration_v1" in your mod metadata file + * to integrate with ModernFix's features. + */ +public interface ModernFixClientIntegration { + /** + * Called when the dynamic resources status has changed during a model reload so mods know whether to run their + * normal codepath or the dynamic version. + * + * @param enabled whether dynamic resources is enabled + */ + default void onDynamicResourcesStatusChange(boolean enabled) { + } + + /** + * Called to allow mods to observe the loading of an unbaked model and either make changes to it or wrap it with their + * own instance. + * @param location the ResourceLocation of the model (this may be a ModelResourceLocation) + * @param originalModel the original model + * @param bakery the model bakery - do not touch internal fields as they probably don't behave the way you expect + * with dynamic resources on + * @return the model which should actually be loaded for this resource location + */ + default UnbakedModel onUnbakedModelLoad(ResourceLocation location, UnbakedModel originalModel, ModelBakery bakery) { + return originalModel; + } + + /** + * Called to allow mods to observe the loading of a baked model and either make changes to it or wrap it with their + * own instance. + * @param location the ResourceLocation of the model (this may be a ModelResourceLocation) + * @param originalModel the original model + * @param bakery the model bakery - do not touch internal fields as they probably don't behave the way you expect + * with dynamic resources on + * @return the model which should actually be loaded for this resource location + */ + default BakedModel onBakedModelLoad(ResourceLocation location, UnbakedModel baseModel, BakedModel originalModel, ModelState state, ModelBakery bakery) { + return originalModel; + } +} diff --git a/common/src/main/java/org/embeddedt/modernfix/api/helpers/ModelHelpers.java b/common/src/main/java/org/embeddedt/modernfix/api/helpers/ModelHelpers.java new file mode 100644 index 00000000..33535a14 --- /dev/null +++ b/common/src/main/java/org/embeddedt/modernfix/api/helpers/ModelHelpers.java @@ -0,0 +1,55 @@ +package org.embeddedt.modernfix.api.helpers; + +import com.google.common.collect.ImmutableList; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.client.resources.model.BlockModelRotation; +import net.minecraft.client.resources.model.ModelResourceLocation; +import net.minecraft.client.resources.model.ModelState; +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.StateDefinition; +import org.embeddedt.modernfix.dynamicresources.ModelBakeryHelpers; +import org.embeddedt.modernfix.util.DynamicMap; + +import java.util.Map; +import java.util.Optional; +import java.util.function.BiFunction; + +@SuppressWarnings("unused") +public final class ModelHelpers { + /** + * Allows converting a ModelResourceLocation back into the corresponding BlockState(s). Try to avoid calling this + * multiple times if possible. + * @param location the location of the model + * @return a list of all blockstates related to the model + */ + public static ImmutableList getBlockStateForLocation(ModelResourceLocation location) { + Optional blockOpt = Registry.BLOCK.getOptional(new ResourceLocation(location.getNamespace(), location.getPath())); + if(blockOpt.isPresent()) + return ModelBakeryHelpers.getBlockStatesForMRL(blockOpt.get().getStateDefinition(), location); + else + return ImmutableList.of(); + } + + /** + * Allows converting a ModelResourceLocation back into the corresponding BlockState(s). Faster version of its + * companion function if and only if you know the corresponding Block already for some reason. + * @param definition the state definition for the Block + * @param location the location of the model + * @return a list of all blockstates related to the model + */ + public static ImmutableList getBlockStateForLocation(StateDefinition definition, ModelResourceLocation location) { + return ModelBakeryHelpers.getBlockStatesForMRL(definition, location); + } + + /** + * Compatibility helper for mods to use to get a map-like view of the model bakery. + * @param modelGetter the model getter function supplied by the integration class + * @return a fake map of the top-level models + */ + public static Map createFakeTopLevelMap(BiFunction modelGetter) { + return new DynamicMap<>(location -> modelGetter.apply(location, BlockModelRotation.X0_Y0)); + } +} diff --git a/common/src/main/java/org/embeddedt/modernfix/core/ModernFixMixinPlugin.java b/common/src/main/java/org/embeddedt/modernfix/core/ModernFixMixinPlugin.java index 49b5c487..850db8f2 100644 --- a/common/src/main/java/org/embeddedt/modernfix/core/ModernFixMixinPlugin.java +++ b/common/src/main/java/org/embeddedt/modernfix/core/ModernFixMixinPlugin.java @@ -20,6 +20,8 @@ public class ModernFixMixinPlugin implements IMixinConfigPlugin { public static ModernFixMixinPlugin instance; public ModernFixMixinPlugin() { + /* invoke early to ensure it gets read on one thread */ + ModernFixPlatformHooks.getCustomModOptions(); boolean firstConfig = instance == null; if(firstConfig) { instance = this; diff --git a/common/src/main/java/org/embeddedt/modernfix/platform/ModernFixPlatformHooks.java b/common/src/main/java/org/embeddedt/modernfix/platform/ModernFixPlatformHooks.java index 39ca4d64..ee199cb2 100644 --- a/common/src/main/java/org/embeddedt/modernfix/platform/ModernFixPlatformHooks.java +++ b/common/src/main/java/org/embeddedt/modernfix/platform/ModernFixPlatformHooks.java @@ -1,5 +1,6 @@ package org.embeddedt.modernfix.platform; +import com.google.common.collect.Multimap; import com.mojang.blaze3d.platform.NativeImage; import com.mojang.brigadier.CommandDispatcher; import dev.architectury.injectables.annotations.ExpectPlatform; @@ -85,4 +86,9 @@ public class ModernFixPlatformHooks { public static void onServerCommandRegister(Consumer> handler) { throw new AssertionError(); } + + @ExpectPlatform + public static Multimap getCustomModOptions() { + throw new AssertionError(); + } } diff --git a/fabric/src/main/java/org/embeddedt/modernfix/platform/fabric/ModernFixPlatformHooksImpl.java b/fabric/src/main/java/org/embeddedt/modernfix/platform/fabric/ModernFixPlatformHooksImpl.java index cbaf273d..4a4a289b 100644 --- a/fabric/src/main/java/org/embeddedt/modernfix/platform/fabric/ModernFixPlatformHooksImpl.java +++ b/fabric/src/main/java/org/embeddedt/modernfix/platform/fabric/ModernFixPlatformHooksImpl.java @@ -1,11 +1,15 @@ package org.embeddedt.modernfix.platform.fabric; +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.Multimap; import com.mojang.blaze3d.platform.NativeImage; import com.mojang.brigadier.CommandDispatcher; import net.fabricmc.api.EnvType; import net.fabricmc.fabric.api.command.v1.CommandRegistrationCallback; import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.ModContainer; +import net.fabricmc.loader.api.metadata.CustomValue; +import net.fabricmc.loader.api.metadata.ModMetadata; import net.minecraft.client.renderer.texture.TextureAtlas; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.commands.CommandSourceStack; @@ -14,6 +18,7 @@ import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.packs.resources.Resource; import net.minecraft.server.packs.resources.ResourceManager; import org.embeddedt.modernfix.ModernFixFabric; +import org.embeddedt.modernfix.api.constants.IntegrationConstants; import org.objectweb.asm.tree.*; import java.nio.file.Path; @@ -82,4 +87,26 @@ public class ModernFixPlatformHooksImpl { public static void onServerCommandRegister(Consumer> handler) { CommandRegistrationCallback.EVENT.register((dispatcher, arg) -> handler.accept(dispatcher)); } + + private static Multimap modOptions; + public static Multimap getCustomModOptions() { + if(modOptions == null) { + modOptions = ArrayListMultimap.create(); + for (ModContainer container : FabricLoader.getInstance().getAllMods()) { + ModMetadata meta = container.getMetadata(); + if (meta.containsCustomValue(IntegrationConstants.INTEGRATIONS_KEY)) { + CustomValue integrations = meta.getCustomValue(IntegrationConstants.INTEGRATIONS_KEY); + if (integrations.getType() != CustomValue.CvType.OBJECT) { + continue; + } + for (Map.Entry entry : integrations.getAsObject()) { + if(entry.getValue().getType() != CustomValue.CvType.STRING) + continue; + modOptions.put(entry.getKey(), entry.getValue().getAsString()); + } + } + } + } + return modOptions; + } } diff --git a/forge/src/main/java/org/embeddedt/modernfix/forge/dynamicresources/DynamicModelBakeEvent.java b/forge/src/main/java/org/embeddedt/modernfix/forge/dynamicresources/DynamicModelBakeEvent.java deleted file mode 100644 index fc475ff6..00000000 --- a/forge/src/main/java/org/embeddedt/modernfix/forge/dynamicresources/DynamicModelBakeEvent.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.embeddedt.modernfix.forge.dynamicresources; - -import net.minecraft.client.resources.model.BakedModel; -import net.minecraft.client.resources.model.UnbakedModel; -import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.client.model.ModelLoader; -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; - 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() { - return this.location; - } - - public BakedModel getModel() { - 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/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/dynamic_resources/ModelBakeryMixin.java b/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/dynamic_resources/ModelBakeryMixin.java index a71b7ed7..7b75a2d8 100644 --- a/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/dynamic_resources/ModelBakeryMixin.java +++ b/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/dynamic_resources/ModelBakeryMixin.java @@ -26,26 +26,23 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.StateDefinition; import net.minecraft.world.level.block.state.properties.Property; 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.packs.DelegatingResourcePack; import net.minecraftforge.fml.packs.ModFileResourcePack; import org.apache.commons.lang3.tuple.Triple; import org.apache.logging.log4j.Logger; import org.embeddedt.modernfix.ModernFix; +import org.embeddedt.modernfix.ModernFixClient; import org.embeddedt.modernfix.annotation.ClientOnlyMixin; +import org.embeddedt.modernfix.api.entrypoint.ModernFixClientIntegration; import org.embeddedt.modernfix.duck.IExtendedModelBakery; import org.embeddedt.modernfix.dynamicresources.DynamicBakedModelProvider; -import org.embeddedt.modernfix.forge.dynamicresources.DynamicModelBakeEvent; import org.embeddedt.modernfix.dynamicresources.ModelBakeryHelpers; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mutable; 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.*; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @@ -90,6 +87,8 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery { @Shadow @Nullable public abstract BakedModel getBakedModel(ResourceLocation arg, ModelState arg2, Function textureGetter); + @Shadow @org.jetbrains.annotations.Nullable public abstract BakedModel bake(ResourceLocation location, ModelState transform); + private Cache, BakedModel> loadedBakedModels; private Cache loadedModels; @@ -217,6 +216,18 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery { return unbakedCache.get(rl); } + @ModifyVariable(method = "cacheAndQueueDependencies", at = @At("HEAD"), argsOnly = true) + private UnbakedModel fireUnbakedEvent(UnbakedModel model, ResourceLocation location) { + for(ModernFixClientIntegration integration : ModernFixClient.CLIENT_INTEGRATIONS) { + try { + model = integration.onUnbakedModelLoad(location, model, (ModelBakery)(Object)this); + } catch(RuntimeException e) { + ModernFix.LOGGER.error("Exception firing model load event for {}", location, e); + } + } + return model; + } + @Inject(method = "cacheAndQueueDependencies", at = @At("RETURN")) private void addToSmallLoadingCache(ResourceLocation location, UnbakedModel model, CallbackInfo ci) { smallLoadingCache.put(location, model); @@ -329,10 +340,15 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery { } else ibakedmodel = iunbakedmodel.bake((ModelBakery) (Object) this, textureGetter, arg2, arg); } - DynamicModelBakeEvent event = new DynamicModelBakeEvent(arg, iunbakedmodel, ibakedmodel, (ModelLoader)(Object)this); - MinecraftForge.EVENT_BUS.post(event); - this.bakedCache.put(triple, event.getModel()); - cir.setReturnValue(event.getModel()); + for(ModernFixClientIntegration integration : ModernFixClient.CLIENT_INTEGRATIONS) { + try { + ibakedmodel = integration.onBakedModelLoad(arg, iunbakedmodel, ibakedmodel, arg2, (ModelBakery)(Object)this); + } catch(RuntimeException e) { + ModernFix.LOGGER.error("Exception encountered firing bake event for {}", arg, e); + } + } + this.bakedCache.put(triple, ibakedmodel); + cir.setReturnValue(ibakedmodel); } } } diff --git a/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/dynamic_resources/ae2/RegistrationMixin.java b/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/dynamic_resources/ae2/RegistrationMixin.java index bcbfee97..bc838d13 100644 --- a/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/dynamic_resources/ae2/RegistrationMixin.java +++ b/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/dynamic_resources/ae2/RegistrationMixin.java @@ -4,21 +4,21 @@ import appeng.bootstrap.components.IModelBakeComponent; import appeng.bootstrap.components.ModelOverrideComponent; import appeng.core.Api; import appeng.core.AppEng; -import net.minecraft.client.resources.model.BakedModel; -import net.minecraft.client.resources.model.ModelBakery; +import net.minecraft.client.resources.model.*; import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.fml.common.ObfuscationReflectionHelper; import org.embeddedt.modernfix.ModernFix; +import org.embeddedt.modernfix.ModernFixClient; import org.embeddedt.modernfix.annotation.ClientOnlyMixin; import org.embeddedt.modernfix.annotation.RequiresMod; -import org.embeddedt.modernfix.forge.dynamicresources.DynamicModelBakeEvent; +import org.embeddedt.modernfix.api.entrypoint.ModernFixClientIntegration; 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.CallbackInfo; import java.lang.reflect.Field; +import java.util.Iterator; import java.util.Map; import java.util.function.BiFunction; @@ -29,34 +29,33 @@ public class RegistrationMixin { private static Field customizerField; @Inject(method = "registerClientEvents", at = @At("TAIL"), remap = false) private void doRegisterDynBake(CallbackInfo ci) { - MinecraftForge.EVENT_BUS.addListener(this::onDynamicModelBake); customizerField = ObfuscationReflectionHelper.findField(ModelOverrideComponent.class, "customizer"); - } - - private void onDynamicModelBake(DynamicModelBakeEvent event) { - if (!event.getLocation().getNamespace().equals(AppEng.MOD_ID)) { - return; - } - BakedModel missing = event.getModelLoader().getBakedTopLevelModels().get(ModelBakery.MISSING_MODEL_LOCATION); - if(event.getModel() == missing) - return; - Api.INSTANCE.definitions().getRegistry().getBootstrapComponents(IModelBakeComponent.class).forEachRemaining(c -> { - if(c instanceof ModelOverrideComponent) - handleModelOverride((ModelOverrideComponent)c, event); + ModernFixClient.CLIENT_INTEGRATIONS.add(new ModernFixClientIntegration() { + @Override + public BakedModel onBakedModelLoad(ResourceLocation location, UnbakedModel baseModel, BakedModel originalModel, ModelState state, ModelBakery bakery) { + if(location.getNamespace().equals(AppEng.MOD_ID)) { + BakedModel m = bakery.bake(ModelBakery.MISSING_MODEL_LOCATION, BlockModelRotation.X0_Y0); + if(originalModel == m) + return originalModel; + Iterator components = Api.INSTANCE.definitions().getRegistry().getBootstrapComponents(IModelBakeComponent.class); + while(components.hasNext()) { + IModelBakeComponent c = components.next(); + if(c instanceof ModelOverrideComponent) { + Map> customizer; + try { + customizer = (Map>)customizerField.get(c); + } catch(ReflectiveOperationException e) { + ModernFix.LOGGER.error("Can't replace model", e); + continue; + } + BiFunction fn = customizer.get(location.getPath()); + if(fn != null) + originalModel = fn.apply(location, originalModel); + } + } + } + return originalModel; + } }); } - - private void handleModelOverride(ModelOverrideComponent c, DynamicModelBakeEvent event) { - Map> customizer; - try { - customizer = (Map>)customizerField.get(c); - } catch(ReflectiveOperationException e) { - ModernFix.LOGGER.error("Can't replace model", e); - return; - } - BiFunction fn = customizer.get(event.getLocation().getPath()); - if(fn != null) { - event.setModel(fn.apply(event.getLocation(), event.getModel())); - } - } } diff --git a/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/dynamic_resources/ctm/CTMPackReloadListenerMixin.java b/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/dynamic_resources/ctm/CTMPackReloadListenerMixin.java index b6ef6ea2..4c8cc031 100644 --- a/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/dynamic_resources/ctm/CTMPackReloadListenerMixin.java +++ b/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/dynamic_resources/ctm/CTMPackReloadListenerMixin.java @@ -3,23 +3,19 @@ package org.embeddedt.modernfix.forge.mixin.perf.dynamic_resources.ctm; import com.google.common.collect.ImmutableList; import net.minecraft.client.renderer.ItemBlockRenderTypes; import net.minecraft.client.renderer.RenderType; -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.client.resources.model.*; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.eventbus.api.EventPriority; import net.minecraftforge.registries.ForgeRegistries; import net.minecraftforge.registries.IRegistryDelegate; import org.embeddedt.modernfix.ModernFix; +import org.embeddedt.modernfix.ModernFixClient; import org.embeddedt.modernfix.annotation.ClientOnlyMixin; import org.embeddedt.modernfix.annotation.RequiresMod; -import org.embeddedt.modernfix.duck.IExtendedModelBakery; -import org.embeddedt.modernfix.forge.dynamicresources.DynamicModelBakeEvent; +import org.embeddedt.modernfix.api.entrypoint.ModernFixClientIntegration; +import org.embeddedt.modernfix.api.helpers.ModelHelpers; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Overwrite; @@ -37,7 +33,7 @@ import java.util.function.Predicate; @Mixin(CTMPackReloadListener.class) @RequiresMod("ctm") @ClientOnlyMixin -public abstract class CTMPackReloadListenerMixin { +public abstract class CTMPackReloadListenerMixin implements ModernFixClientIntegration { /* caches the original render checks */ @Shadow @Final private static Map, Predicate> blockRenderChecks; @@ -51,7 +47,7 @@ public abstract class CTMPackReloadListenerMixin { @Inject(method = "", at = @At("RETURN")) private void onInit(CallbackInfo ci) { - MinecraftForge.EVENT_BUS.addListener(EventPriority.LOW, this::onModelBake); + ModernFixClient.CLIENT_INTEGRATIONS.add(this); } @Overwrite(remap = false) @@ -75,27 +71,31 @@ public abstract class CTMPackReloadListenerMixin { return override.test(type); } - private void onModelBake(DynamicModelBakeEvent event) { - if(!(event.getModel() instanceof AbstractCTMBakedModel || event.getModel() instanceof WeightedBakedModel || event.getModel() instanceof MultiPartBakedModel)) - return; + @Override + public BakedModel onBakedModelLoad(ResourceLocation location, UnbakedModel baseModel, BakedModel originalModel, ModelState modelState, ModelBakery bakery) { + if(!(location instanceof ModelResourceLocation)) + return originalModel; + if(!(originalModel instanceof AbstractCTMBakedModel || originalModel instanceof WeightedBakedModel || originalModel instanceof MultiPartBakedModel)) + return originalModel; /* we construct a new ResourceLocation because an MRL is coming in */ - Block block = ForgeRegistries.BLOCKS.getValue(new ResourceLocation(event.getLocation().getNamespace(), event.getLocation().getPath())); + Block block = ForgeRegistries.BLOCKS.getValue(new ResourceLocation(location.getNamespace(), location.getPath())); if(block == null || block == Blocks.AIR || renderCheckOverrides.containsKey(block.delegate)) - return; + return originalModel; /* find all states that match this MRL */ ImmutableList allStates; try { - allStates = ((IExtendedModelBakery)(Object)event.getModelLoader()).getBlockStatesForMRL(block.getStateDefinition(), (ModelResourceLocation)event.getLocation()); + allStates = ModelHelpers.getBlockStateForLocation(block.getStateDefinition(), (ModelResourceLocation)location); } catch(RuntimeException e) { - ModernFix.LOGGER.error("Couldn't get state for MRL " + event.getLocation(), e); - return; + ModernFix.LOGGER.error("Couldn't get state for MRL " + location, e); + return originalModel; } for(BlockState state : allStates) { - Predicate newPredicate = this.getLayerCheck(state, event.getModel()); + Predicate newPredicate = this.getLayerCheck(state, originalModel); if(newPredicate != null) { renderCheckOverrides.put(block.delegate, newPredicate); - return; + return originalModel; } } + return originalModel; } } diff --git a/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/dynamic_resources/ctm/TextureMetadataHandlerMixin.java b/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/dynamic_resources/ctm/TextureMetadataHandlerMixin.java index e1bc5547..c7ecb7ab 100644 --- a/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/dynamic_resources/ctm/TextureMetadataHandlerMixin.java +++ b/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/dynamic_resources/ctm/TextureMetadataHandlerMixin.java @@ -1,15 +1,13 @@ package org.embeddedt.modernfix.forge.mixin.perf.dynamic_resources.ctm; import com.mojang.datafixers.util.Pair; -import net.minecraft.client.resources.model.BakedModel; -import net.minecraft.client.resources.model.Material; -import net.minecraft.client.resources.model.UnbakedModel; +import net.minecraft.client.resources.model.*; import net.minecraft.resources.ResourceLocation; import net.minecraftforge.client.model.ModelLoader; -import net.minecraftforge.common.MinecraftForge; +import org.embeddedt.modernfix.ModernFixClient; import org.embeddedt.modernfix.annotation.ClientOnlyMixin; import org.embeddedt.modernfix.annotation.RequiresMod; -import org.embeddedt.modernfix.forge.dynamicresources.DynamicModelBakeEvent; +import org.embeddedt.modernfix.api.entrypoint.ModernFixClientIntegration; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; @@ -29,13 +27,13 @@ import java.util.*; @Mixin(TextureMetadataHandler.class) @RequiresMod("ctm") @ClientOnlyMixin -public abstract class TextureMetadataHandlerMixin { +public abstract class TextureMetadataHandlerMixin implements ModernFixClientIntegration { @Shadow @Nonnull protected abstract BakedModel wrap(ResourceLocation loc, UnbakedModel model, BakedModel object, ModelLoader loader) throws IOException; @Inject(method = "", at = @At("RETURN")) private void subscribeDynamic(CallbackInfo ci) { - MinecraftForge.EVENT_BUS.addListener(this::onDynamicModelBake); + ModernFixClient.CLIENT_INTEGRATIONS.add(this); } @Redirect(method = "onModelBake", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/resources/model/BakedModel;isCustomRenderer()Z")) @@ -43,10 +41,8 @@ public abstract class TextureMetadataHandlerMixin { return model == null || model.isCustomRenderer(); } - public void onDynamicModelBake(DynamicModelBakeEvent event) { - UnbakedModel rootModel = event.getUnbakedModel(); - BakedModel baked = event.getModel(); - ResourceLocation rl = event.getLocation(); + @Override + public BakedModel onBakedModelLoad(ResourceLocation rl, UnbakedModel rootModel, BakedModel baked, ModelState state, ModelBakery bakery) { if (!(baked instanceof AbstractCTMBakedModel) && !baked.isCustomRenderer()) { Deque dependencies = new ArrayDeque<>(); Set seenModels = new HashSet<>(); @@ -59,12 +55,12 @@ public abstract class TextureMetadataHandlerMixin { ResourceLocation dep = dependencies.pop(); UnbakedModel model; try { - model = dep == rl ? rootModel : event.getModelLoader().getModel(dep); + model = dep == rl ? rootModel : bakery.getModel(dep); } catch (Exception e) { continue; } - Collection textures = model.getMaterials(event.getModelLoader()::getModel, errors); + Collection textures = model.getMaterials(bakery::getModel, errors); Collection newDependencies = model.getDependencies(); for (Material tex : textures) { IMetadataSectionCTM meta = null; @@ -86,12 +82,13 @@ public abstract class TextureMetadataHandlerMixin { } if (shouldWrap) { try { - event.setModel(wrap(rl, rootModel, baked, event.getModelLoader())); + baked = wrap(rl, rootModel, baked, (ModelLoader)bakery); dependencies.clear(); } catch (IOException e) { CTM.logger.error("Could not wrap model " + rl + ". Aborting...", e); } } } + return baked; } } diff --git a/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/dynamic_resources/rs/ClientSetupMixin.java b/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/dynamic_resources/rs/ClientSetupMixin.java index 4369870e..26cf83b0 100644 --- a/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/dynamic_resources/rs/ClientSetupMixin.java +++ b/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/dynamic_resources/rs/ClientSetupMixin.java @@ -2,12 +2,12 @@ package org.embeddedt.modernfix.forge.mixin.perf.dynamic_resources.rs; import com.refinedmods.refinedstorage.render.BakedModelOverrideRegistry; import com.refinedmods.refinedstorage.setup.ClientSetup; -import net.minecraft.client.resources.model.ModelResourceLocation; +import net.minecraft.client.resources.model.*; import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.common.MinecraftForge; +import org.embeddedt.modernfix.ModernFixClient; import org.embeddedt.modernfix.annotation.ClientOnlyMixin; import org.embeddedt.modernfix.annotation.RequiresMod; -import org.embeddedt.modernfix.forge.dynamicresources.DynamicModelBakeEvent; +import org.embeddedt.modernfix.api.entrypoint.ModernFixClientIntegration; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -15,6 +15,7 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + @Mixin(ClientSetup.class) @RequiresMod("refinedstorage") @ClientOnlyMixin @@ -23,12 +24,15 @@ public class ClientSetupMixin { @Inject(method = "", at = @At("RETURN")) private void addDynamicListener(CallbackInfo ci) { - MinecraftForge.EVENT_BUS.addListener(this::onDynamicModelBake); - } - - private void onDynamicModelBake(DynamicModelBakeEvent event) { - BakedModelOverrideRegistry.BakedModelOverrideFactory factory = bakedModelOverrideRegistry.get(event.getLocation() instanceof ModelResourceLocation ? new ResourceLocation(event.getLocation().getNamespace(), event.getLocation().getPath()) : event.getLocation()); - if(factory != null) - event.setModel(factory.create(event.getModel(), event.getModelLoader().getBakedTopLevelModels())); + ModernFixClient.CLIENT_INTEGRATIONS.add(new ModernFixClientIntegration() { + @Override + public BakedModel onBakedModelLoad(ResourceLocation location, UnbakedModel baseModel, BakedModel originalModel, ModelState state, ModelBakery bakery) { + BakedModelOverrideRegistry.BakedModelOverrideFactory factory = bakedModelOverrideRegistry.get(location instanceof ModelResourceLocation ? new ResourceLocation(location.getNamespace(), location.getPath()) : location); + if(factory != null) + return factory.create(originalModel, bakery.getBakedTopLevelModels()); + else + return originalModel; + } + }); } } diff --git a/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/dynamic_resources/supermartijncore/ClientRegistrationHandlerMixin.java b/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/dynamic_resources/supermartijncore/ClientRegistrationHandlerMixin.java index 682484f1..e4cc3781 100644 --- a/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/dynamic_resources/supermartijncore/ClientRegistrationHandlerMixin.java +++ b/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/dynamic_resources/supermartijncore/ClientRegistrationHandlerMixin.java @@ -4,12 +4,14 @@ import com.supermartijn642.core.registry.ClientRegistrationHandler; import com.supermartijn642.core.util.Pair; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.client.resources.model.ModelBakery; +import net.minecraft.client.resources.model.ModelState; +import net.minecraft.client.resources.model.UnbakedModel; import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.eventbus.api.SubscribeEvent; +import org.embeddedt.modernfix.ModernFixClient; import org.embeddedt.modernfix.annotation.ClientOnlyMixin; import org.embeddedt.modernfix.annotation.RequiresMod; -import org.embeddedt.modernfix.forge.dynamicresources.DynamicModelBakeEvent; +import org.embeddedt.modernfix.api.entrypoint.ModernFixClientIntegration; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -48,13 +50,15 @@ public class ClientRegistrationHandlerMixin { @Inject(method = "", at = @At("RETURN")) private void registerDynBake(String modid, CallbackInfo ci) { - MinecraftForge.EVENT_BUS.addListener(this::onDynamicModelBake); - } - - @SubscribeEvent - public void onDynamicModelBake(DynamicModelBakeEvent event) { - Function replacer = modelOverwritesByLocation.get(event.getLocation()); - if(replacer != null) - event.setModel(replacer.apply(event.getModel())); + ModernFixClient.CLIENT_INTEGRATIONS.add(new ModernFixClientIntegration() { + @Override + public BakedModel onBakedModelLoad(ResourceLocation location, UnbakedModel baseModel, BakedModel originalModel, ModelState state, ModelBakery bakery) { + Function replacer = modelOverwritesByLocation.get(location); + if(replacer != null) + return replacer.apply(originalModel); + else + return originalModel; + } + }); } } diff --git a/forge/src/main/java/org/embeddedt/modernfix/platform/forge/ModernFixPlatformHooksImpl.java b/forge/src/main/java/org/embeddedt/modernfix/platform/forge/ModernFixPlatformHooksImpl.java index f8eb19e6..af1208bb 100644 --- a/forge/src/main/java/org/embeddedt/modernfix/platform/forge/ModernFixPlatformHooksImpl.java +++ b/forge/src/main/java/org/embeddedt/modernfix/platform/forge/ModernFixPlatformHooksImpl.java @@ -1,5 +1,7 @@ package org.embeddedt.modernfix.platform.forge; +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.Multimap; import com.google.common.io.Resources; import com.mojang.blaze3d.platform.NativeImage; import com.mojang.brigadier.CommandDispatcher; @@ -23,8 +25,10 @@ import net.minecraftforge.fml.loading.FMLLoader; import net.minecraftforge.fml.loading.FMLPaths; import net.minecraftforge.fml.loading.LoadingModList; import net.minecraftforge.fml.loading.moddiscovery.ExplodedDirectoryLocator; +import net.minecraftforge.fml.loading.moddiscovery.ModInfo; import net.minecraftforge.fml.network.PacketDistributor; import net.minecraftforge.fml.server.ServerLifecycleHooks; +import org.embeddedt.modernfix.api.constants.IntegrationConstants; import org.embeddedt.modernfix.forge.classloading.FastAccessTransformerList; import org.embeddedt.modernfix.forge.classloading.ModernFixResourceFinder; import org.embeddedt.modernfix.core.ModernFixMixinPlugin; @@ -255,4 +259,24 @@ public class ModernFixPlatformHooksImpl { handler.accept(event.getDispatcher()); }); } + + private static Multimap modOptions; + public static Multimap getCustomModOptions() { + if(modOptions == null) { + modOptions = ArrayListMultimap.create(); + for (ModInfo meta : LoadingModList.get().getMods()) { + meta.getConfigElement(IntegrationConstants.INTEGRATIONS_KEY).ifPresent(optionsObj -> { + if(optionsObj instanceof Map) { + Map options = (Map)optionsObj; + options.forEach((key, value) -> { + if(key instanceof String && value instanceof String) { + modOptions.put((String)key, (String)value); + } + }); + } + }); + } + } + return modOptions; + } } From a7e64f29476020e020707195368841f959d38cac Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sun, 14 May 2023 19:23:36 -0400 Subject: [PATCH 02/14] Fix performance issue when loading large NBT maps Array map was not being changed to hash map until AFTER the insertions, which is bad --- .../org/embeddedt/modernfix/util/CanonizingStringMap.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/common/src/main/java/org/embeddedt/modernfix/util/CanonizingStringMap.java b/common/src/main/java/org/embeddedt/modernfix/util/CanonizingStringMap.java index e5bb2f2d..05bd219b 100644 --- a/common/src/main/java/org/embeddedt/modernfix/util/CanonizingStringMap.java +++ b/common/src/main/java/org/embeddedt/modernfix/util/CanonizingStringMap.java @@ -77,11 +77,15 @@ public class CanonizingStringMap implements Map { public void putAll(@NotNull Map map) { if(map.size() == 0) return; + // grow early if we know there are enough non-overlapping keys + if((map.size() - backingMap.size()) > GROWTH_THRESHOLD && !(backingMap instanceof Object2ObjectOpenHashMap)) { + backingMap = new Object2ObjectOpenHashMap<>(backingMap); + } map.forEach((String key, T val) -> { key = KEY_INTERNER.intern(key); backingMap.put(key, val); }); - // if it's too big to be an array, grow it + // if it's still an array, and now too big, grow it if(backingMap.size() > GROWTH_THRESHOLD && !(backingMap instanceof Object2ObjectOpenHashMap)) { backingMap = new Object2ObjectOpenHashMap<>(backingMap); } From 962b843199286d8e429572f54d0212fde71c2bf5 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sat, 20 May 2023 12:35:33 -0400 Subject: [PATCH 03/14] Avoid exposing mods to exceptions when baking models --- .../dynamicresources/DynamicBakedModelProvider.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/common/src/main/java/org/embeddedt/modernfix/dynamicresources/DynamicBakedModelProvider.java b/common/src/main/java/org/embeddedt/modernfix/dynamicresources/DynamicBakedModelProvider.java index d11971b3..5803fb77 100644 --- a/common/src/main/java/org/embeddedt/modernfix/dynamicresources/DynamicBakedModelProvider.java +++ b/common/src/main/java/org/embeddedt/modernfix/dynamicresources/DynamicBakedModelProvider.java @@ -13,6 +13,7 @@ import net.minecraft.core.Direction; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.block.state.BlockState; import org.apache.commons.lang3.tuple.Triple; +import org.embeddedt.modernfix.ModernFix; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -106,7 +107,12 @@ public class DynamicBakedModelProvider implements Map Date: Sat, 20 May 2023 16:35:41 -0400 Subject: [PATCH 04/14] Only preserve window position if a non-default width/height was given Fixes #103 (in next release) --- .../WindowMixin.java | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/bugfix/preserve_early_window_pos/WindowMixin.java b/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/bugfix/preserve_early_window_pos/WindowMixin.java index a543b777..85702c55 100644 --- a/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/bugfix/preserve_early_window_pos/WindowMixin.java +++ b/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/bugfix/preserve_early_window_pos/WindowMixin.java @@ -1,8 +1,7 @@ package org.embeddedt.modernfix.forge.mixin.bugfix.preserve_early_window_pos; -import com.mojang.blaze3d.platform.Monitor; -import com.mojang.blaze3d.platform.ScreenManager; -import com.mojang.blaze3d.platform.Window; +import com.mojang.blaze3d.platform.*; +import net.minecraft.client.Minecraft; import net.minecraftforge.fml.common.ObfuscationReflectionHelper; import net.minecraftforge.fml.loading.progress.EarlyProgressVisualization; import org.embeddedt.modernfix.annotation.ClientOnlyMixin; @@ -35,19 +34,26 @@ public class WindowMixin { } private Object getEarlyProgressVisualizer() { + Minecraft client = Minecraft.getInstance(); if(VISUALIZER == null || this.fullscreen) return null; Object o = ObfuscationReflectionHelper.getPrivateValue(EarlyProgressVisualization.class, EarlyProgressVisualization.INSTANCE, "visualization"); return VISUALIZER.isAssignableFrom(o.getClass()) ? o : null; } + private static boolean defaultDisplayData(DisplayData arg3) { + return arg3.width == 854 && arg3.height == 480 && !arg3.isFullscreen; + } + /** * Return a null monitor if not in fullscreen and the visualizer is present, so that the code grabs the * original X/Y position of the window. */ @Redirect(method = "", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/platform/ScreenManager;getMonitor(J)Lcom/mojang/blaze3d/platform/Monitor;")) - private Monitor getMonitor(ScreenManager manager, long id) { - return getEarlyProgressVisualizer() != null ? null : manager.getMonitor(id); + private Monitor getMonitor(ScreenManager manager, long id, WindowEventHandler arg, ScreenManager arg2, DisplayData arg3) { + if(defaultDisplayData(arg3) && getEarlyProgressVisualizer() != null) + return null; + return manager.getMonitor(id); } /** @@ -55,9 +61,9 @@ public class WindowMixin { */ @SuppressWarnings("unchecked") @Redirect(method = "", at = @At(value = "INVOKE", target = "Lnet/minecraftforge/fml/loading/progress/EarlyProgressVisualization;handOffWindow(Ljava/util/function/IntSupplier;Ljava/util/function/IntSupplier;Ljava/util/function/Supplier;Ljava/util/function/LongSupplier;)J"), require = 0) - private long performHandoff(EarlyProgressVisualization instance, IntSupplier width, IntSupplier height, Supplier title, LongSupplier monitor) { + private long performHandoff(EarlyProgressVisualization instance, IntSupplier width, IntSupplier height, Supplier title, LongSupplier monitor, WindowEventHandler arg, ScreenManager arg2, DisplayData arg3) { Object visualizer = getEarlyProgressVisualizer(); - if(visualizer != null) { + if(visualizer != null && defaultDisplayData(arg3)) { long windowId = ObfuscationReflectionHelper.getPrivateValue((Class)visualizer.getClass(), visualizer, "window"); int[] w = new int[1]; int[] h = new int[1]; From bb6d498d58d0ca966a0f108f37e0bce3f4390029 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sun, 21 May 2023 14:10:50 -0400 Subject: [PATCH 05/14] Disable faster_texture_loading and faster_texture_stitching when Opticrash is present Fixes #91 --- .../embeddedt/modernfix/core/config/ModernFixEarlyConfig.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/common/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java b/common/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java index a7688484..2cbd9276 100644 --- a/common/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java +++ b/common/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java @@ -188,8 +188,9 @@ public class ModernFixEarlyConfig { disableIfModPresent("mixin.bugfix.paper_chunk_patches", "c2me"); disableIfModPresent("mixin.perf.reuse_datapacks", "tac"); disableIfModPresent("mixin.launch.class_search_cache", "optifine"); + disableIfModPresent("mixin.perf.faster_texture_stitching", "optifine"); disableIfModPresent("mixin.perf.datapack_reload_exceptions", "cyanide"); - disableIfModPresent("mixin.perf.faster_texture_loading", "stitch"); + disableIfModPresent("mixin.perf.faster_texture_loading", "stitch", "optifine"); } private void disableIfModPresent(String configName, String... ids) { From 98da673cbef392d952c08e9a2980f1bd593813bf Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sun, 21 May 2023 17:04:22 -0400 Subject: [PATCH 06/14] Tweak point at which dummy models are cleared on Fabric --- .../perf/dynamic_resources/ModelBakeryMixin.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakeryMixin.java b/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakeryMixin.java index 82b7ae6e..8b3a6757 100644 --- a/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakeryMixin.java +++ b/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakeryMixin.java @@ -244,6 +244,7 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery { "entity/chest", "item", "items", + "part", "pipe", "ropebridge" }; @@ -266,6 +267,14 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery { return materialsSet; } + @Inject(method = "", at = @At(value = "INVOKE_STRING", target = "Lnet/minecraft/util/profiling/ProfilerFiller;popPush(Ljava/lang/String;)V", args = "ldc=textures")) + private void clearDummyModels(CallbackInfo ci) { + // discard unwrapped models + Predicate> isVanillaModel = entry -> entry.getValue() instanceof BlockModel || entry.getValue() instanceof MultiVariant || entry.getValue() instanceof MultiPart; + this.unbakedCache.entrySet().removeIf(isVanillaModel); + this.topLevelModels.entrySet().removeIf(isVanillaModel); + } + @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(); @@ -287,10 +296,6 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery { return super.put(key, value); } }; - // discard unwrapped models - Predicate> isVanillaModel = entry -> entry.getValue() instanceof BlockModel || entry.getValue() instanceof MultiVariant || entry.getValue() instanceof MultiPart; - this.unbakedCache.entrySet().removeIf(isVanillaModel); - this.topLevelModels.entrySet().removeIf(isVanillaModel); // bake indigo models Stopwatch watch = Stopwatch.createStarted(); this.topLevelModels.forEach((key, value) -> { From a22308fb89a380d925778bb45ca3f148b6740cfa Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sun, 21 May 2023 17:08:45 -0400 Subject: [PATCH 07/14] Depend on full Fabric API at runtime --- fabric/build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/fabric/build.gradle b/fabric/build.gradle index a68aea14..64ccca13 100644 --- a/fabric/build.gradle +++ b/fabric/build.gradle @@ -36,6 +36,7 @@ dependencies { modIncludeImplementation(fabricApi.module("fabric-models-v0", rootProject.fabric_api_version)) { exclude group: 'net.fabricmc', module: 'fabric-loader' } modImplementation(fabricApi.module("fabric-resource-loader-v0", rootProject.fabric_api_version)) { exclude group: 'net.fabricmc', module: 'fabric-loader' } modCompileOnly("com.terraformersmc:modmenu:${rootProject.modmenu_version}") { transitive false } + modRuntimeOnly("net.fabricmc.fabric-api:fabric-api:${rootProject.fabric_api_version}") { exclude group: 'net.fabricmc', module: 'fabric-loader' } // Remove the next line if you don't want to depend on the API // modApi "me.shedaniel:architectury-fabric:${rootProject.architectury_version}" From 0a035b6e0dc5317b16cd9012ff87d12c01d89f89 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sun, 21 May 2023 17:11:51 -0400 Subject: [PATCH 08/14] Back client integration list with COW arraylist --- .../src/main/java/org/embeddedt/modernfix/ModernFixClient.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/common/src/main/java/org/embeddedt/modernfix/ModernFixClient.java b/common/src/main/java/org/embeddedt/modernfix/ModernFixClient.java index f41da000..be5fd14a 100644 --- a/common/src/main/java/org/embeddedt/modernfix/ModernFixClient.java +++ b/common/src/main/java/org/embeddedt/modernfix/ModernFixClient.java @@ -20,6 +20,7 @@ import org.embeddedt.modernfix.world.IntegratedWatchdog; import java.lang.management.ManagementFactory; import java.lang.reflect.Field; import java.util.*; +import java.util.concurrent.CopyOnWriteArrayList; public class ModernFixClient { public static long worldLoadStartTime; @@ -34,7 +35,7 @@ public class ModernFixClient { /** * The list of loaded client integrations. */ - public static List CLIENT_INTEGRATIONS = new ArrayList<>(); + public static List CLIENT_INTEGRATIONS = new CopyOnWriteArrayList<>(); public ModernFixClient() { // clear reserve as it's not needed From fc65975252e66d6cbaabd890a3640a98f617d4d8 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sun, 21 May 2023 20:08:17 -0400 Subject: [PATCH 09/14] Fix AE2 mod id --- .../mixin/perf/dynamic_resources/ae2/RegistrationMixin.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/dynamic_resources/ae2/RegistrationMixin.java b/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/dynamic_resources/ae2/RegistrationMixin.java index f2e53627..45b1c686 100644 --- a/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/dynamic_resources/ae2/RegistrationMixin.java +++ b/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/dynamic_resources/ae2/RegistrationMixin.java @@ -21,13 +21,13 @@ import java.util.Map; import java.util.function.Function; @Mixin(InitAutoRotatingModel.class) -@RequiresMod("appliedenergistics2") +@RequiresMod("ae2") @ClientOnlyMixin public class RegistrationMixin { @Shadow @Final private static Map> CUSTOMIZERS; @Inject(method = "init", at = @At("TAIL"), remap = false) - private void doRegisterDynBake(CallbackInfo ci) { + private static void doRegisterDynBake(CallbackInfo ci) { ModernFixClient.CLIENT_INTEGRATIONS.add(new ModernFixClientIntegration() { @Override public BakedModel onBakedModelLoad(ResourceLocation location, UnbakedModel baseModel, BakedModel originalModel, ModelState state, ModelBakery bakery) { From f48ed1212b049e3fedb4f09991163d48b68ade80 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sun, 21 May 2023 20:17:38 -0400 Subject: [PATCH 10/14] Move AE2 dynamic resources compat to common module --- common/build.gradle | 3 +++ .../mixin/perf/dynamic_resources/ae2/RegistrationMixin.java | 2 +- forge/build.gradle | 1 - gradle.properties | 1 + 4 files changed, 5 insertions(+), 2 deletions(-) rename {forge/src/main/java/org/embeddedt/modernfix/forge => common/src/main/java/org/embeddedt/modernfix/common}/mixin/perf/dynamic_resources/ae2/RegistrationMixin.java (96%) diff --git a/common/build.gradle b/common/build.gradle index f047ba1d..ce3ad020 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -23,6 +23,9 @@ dependencies { modCompileOnly("me.shedaniel:RoughlyEnoughItems-fabric:${rei_version}") { transitive = false } + modCompileOnly("appeng:appliedenergistics2-fabric:${appeng_version}") { + transitive = false + } // compile against the JEI API but do not include it at runtime modCompileOnly("mezz.jei:jei-${minecraft_version}-common:${jei_version}") // Remove the next line if you don't want to depend on the API diff --git a/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/dynamic_resources/ae2/RegistrationMixin.java b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_resources/ae2/RegistrationMixin.java similarity index 96% rename from forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/dynamic_resources/ae2/RegistrationMixin.java rename to common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_resources/ae2/RegistrationMixin.java index 45b1c686..d6bc85b6 100644 --- a/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/dynamic_resources/ae2/RegistrationMixin.java +++ b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_resources/ae2/RegistrationMixin.java @@ -1,4 +1,4 @@ -package org.embeddedt.modernfix.forge.mixin.perf.dynamic_resources.ae2; +package org.embeddedt.modernfix.common.mixin.perf.dynamic_resources.ae2; import appeng.core.AppEng; import appeng.init.client.InitAutoRotatingModel; diff --git a/forge/build.gradle b/forge/build.gradle index 287be48b..93defe66 100644 --- a/forge/build.gradle +++ b/forge/build.gradle @@ -45,7 +45,6 @@ dependencies { modCompileOnly("team.chisel.ctm:CTM:${ctm_version}") modCompileOnly("curse.maven:supermartijncore-454372:4455384") - modCompileOnly("appeng:appliedenergistics2-forge:11.7.3") modCompileOnly("vazkii.patchouli:Patchouli:1.18.2-71.1") common(project(path: ":common", configuration: "namedElements")) { transitive false } diff --git a/gradle.properties b/gradle.properties index 95bd8e12..44cfec12 100644 --- a/gradle.properties +++ b/gradle.properties @@ -18,3 +18,4 @@ fabric_loader_version=0.14.18 fabric_api_version=0.76.0+1.18.2 modmenu_version=3.2.5 +appeng_version=11.7.2 \ No newline at end of file From cfd542623c89ed28db207062fe056f2dc011ae51 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sun, 21 May 2023 20:24:28 -0400 Subject: [PATCH 11/14] Fire model integrations on Fabric --- .../dynamic_resources/ModelBakeryMixin.java | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakeryMixin.java b/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakeryMixin.java index 8b3a6757..77e05a43 100644 --- a/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakeryMixin.java +++ b/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakeryMixin.java @@ -32,17 +32,16 @@ import net.minecraft.world.level.block.state.StateDefinition; import org.apache.commons.lang3.tuple.Triple; import org.apache.logging.log4j.Logger; import org.embeddedt.modernfix.ModernFix; +import org.embeddedt.modernfix.ModernFixClient; import org.embeddedt.modernfix.annotation.ClientOnlyMixin; +import org.embeddedt.modernfix.api.entrypoint.ModernFixClientIntegration; import org.embeddedt.modernfix.duck.IExtendedModelBakery; import org.embeddedt.modernfix.dynamicresources.DynamicBakedModelProvider; import org.embeddedt.modernfix.dynamicresources.ModelBakeryHelpers; import org.embeddedt.modernfix.util.LayeredForwardingMap; import org.jetbrains.annotations.Nullable; 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.ModifyArg; -import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.*; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @@ -333,6 +332,18 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery { return unbakedCache.get(rl); } + @ModifyVariable(method = "cacheAndQueueDependencies", at = @At("HEAD"), argsOnly = true) + private UnbakedModel fireUnbakedEvent(UnbakedModel model, ResourceLocation location) { + for(ModernFixClientIntegration integration : ModernFixClient.CLIENT_INTEGRATIONS) { + try { + model = integration.onUnbakedModelLoad(location, model, (ModelBakery)(Object)this); + } catch(RuntimeException e) { + ModernFix.LOGGER.error("Exception firing model load event for {}", location, e); + } + } + return model; + } + /** * @author embeddedt * @reason synchronize @@ -457,7 +468,13 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery { ModernFix.LOGGER.error("Model {} returned null baked model", arg); ibakedmodel = bakedMissingModel; } - // TODO event + for(ModernFixClientIntegration integration : ModernFixClient.CLIENT_INTEGRATIONS) { + try { + ibakedmodel = integration.onBakedModelLoad(arg, iunbakedmodel, ibakedmodel, arg2, (ModelBakery)(Object)this); + } catch(RuntimeException e) { + ModernFix.LOGGER.error("Exception encountered firing bake event for {}", arg, e); + } + } this.bakedCache.put(triple, ibakedmodel); cir.setReturnValue(ibakedmodel); } From 91c2d50d9728b68a5cfc4c9385542d638d056d05 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Sun, 21 May 2023 22:14:17 -0400 Subject: [PATCH 12/14] Add more texture paths --- .../mixin/perf/dynamic_resources/ModelBakeryMixin.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakeryMixin.java b/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakeryMixin.java index 77e05a43..a8551700 100644 --- a/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakeryMixin.java +++ b/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakeryMixin.java @@ -243,9 +243,12 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery { "entity/chest", "item", "items", + "model", + "models", "part", "pipe", - "ropebridge" + "ropebridge", + "solid_block" }; for(String folder : extraFolders) { Collection textureLocations = this.resourceManager.listResources("textures/" + folder, p -> p.endsWith(".png")); From 80617c24f1cd6c7280cb50966f26a703410fa190 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Mon, 22 May 2023 13:25:14 -0400 Subject: [PATCH 13/14] Work around KeyMapping names being retrieved off-thread --- .../mixin/perf/blast_search_trees/MinecraftMixin.java | 6 ++++++ common/src/main/resources/modernfix.accesswidener | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/blast_search_trees/MinecraftMixin.java b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/blast_search_trees/MinecraftMixin.java index d28c2fc0..73f6a358 100644 --- a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/blast_search_trees/MinecraftMixin.java +++ b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/blast_search_trees/MinecraftMixin.java @@ -1,5 +1,6 @@ package org.embeddedt.modernfix.common.mixin.perf.blast_search_trees; +import net.minecraft.client.KeyMapping; import net.minecraft.client.Minecraft; import net.minecraft.client.searchtree.SearchRegistry; import org.embeddedt.modernfix.ModernFix; @@ -27,6 +28,11 @@ public class MinecraftMixin { this.searchRegistry.register(SearchRegistry.CREATIVE_NAMES, provider.getSearchTree(false)); this.searchRegistry.register(SearchRegistry.CREATIVE_TAGS, provider.getSearchTree(true)); this.searchRegistry.register(SearchRegistry.RECIPE_COLLECTIONS, new DummySearchTree<>()); + // grab components for all key mappings in order to prevent them from being loaded off-thread later + // this populates the LazyLoadedValues + for(KeyMapping mapping : KeyMapping.ALL.values()) { + mapping.getTranslatedKeyMessage(); + } ci.cancel(); } } diff --git a/common/src/main/resources/modernfix.accesswidener b/common/src/main/resources/modernfix.accesswidener index 459f6b00..6f44fc25 100644 --- a/common/src/main/resources/modernfix.accesswidener +++ b/common/src/main/resources/modernfix.accesswidener @@ -28,4 +28,5 @@ accessible class net/minecraft/server/level/ChunkMap$DistanceManager accessible class net/minecraft/world/level/chunk/PalettedContainer$Data accessible field net/minecraft/server/MinecraftServer resources Lnet/minecraft/server/MinecraftServer$ReloadableResources; accessible class net/minecraft/server/MinecraftServer$ReloadableResources -accessible method net/minecraft/client/gui/screens/Screen addRenderableWidget (Lnet/minecraft/client/gui/components/events/GuiEventListener;)Lnet/minecraft/client/gui/components/events/GuiEventListener; \ No newline at end of file +accessible method net/minecraft/client/gui/screens/Screen addRenderableWidget (Lnet/minecraft/client/gui/components/events/GuiEventListener;)Lnet/minecraft/client/gui/components/events/GuiEventListener; +accessible field net/minecraft/client/KeyMapping ALL Ljava/util/Map; \ No newline at end of file From 675e3bb08b6289c3d5bab936a1f1b36a7fff9cc8 Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Mon, 22 May 2023 13:49:08 -0400 Subject: [PATCH 14/14] Fix startup crash introduced in last commit --- .../common/mixin/perf/blast_search_trees/MinecraftMixin.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/blast_search_trees/MinecraftMixin.java b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/blast_search_trees/MinecraftMixin.java index 73f6a358..cf5d0044 100644 --- a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/blast_search_trees/MinecraftMixin.java +++ b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/blast_search_trees/MinecraftMixin.java @@ -7,6 +7,8 @@ import org.embeddedt.modernfix.ModernFix; import org.embeddedt.modernfix.annotation.ClientOnlyMixin; import org.embeddedt.modernfix.searchtree.DummySearchTree; import org.embeddedt.modernfix.searchtree.SearchTreeProviderRegistry; +import org.lwjgl.glfw.GLFW; +import org.lwjgl.glfw.GLFWErrorCallback; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -30,9 +32,12 @@ public class MinecraftMixin { this.searchRegistry.register(SearchRegistry.RECIPE_COLLECTIONS, new DummySearchTree<>()); // grab components for all key mappings in order to prevent them from being loaded off-thread later // this populates the LazyLoadedValues + // we also need to suppress GLFW errors to prevent crashes if a key is missing + GLFWErrorCallback oldCb = GLFW.glfwSetErrorCallback(null); for(KeyMapping mapping : KeyMapping.ALL.values()) { mapping.getTranslatedKeyMessage(); } + GLFW.glfwSetErrorCallback(oldCb); ci.cancel(); } }