diff --git a/common/build.gradle b/common/build.gradle index 1476a95f..dfc0f177 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -25,6 +25,9 @@ dependencies { modCompileOnly("me.shedaniel:RoughlyEnoughItems-fabric:${rei_version}") { transitive = false } + + modCompileOnly("curse.maven:diagonal-fences-458048:${diagonal_fences_version}") + // compile against the JEI API but do not include it at runtime modCompileOnly("mezz.jei:jei-${jei_minecraft_version}-common:${jei_version}") modCompileOnly("mezz.jei:jei-${jei_minecraft_version}-gui:${jei_version}") diff --git a/common/src/main/java/org/embeddedt/modernfix/ModernFix.java b/common/src/main/java/org/embeddedt/modernfix/ModernFix.java index b571b718..dba7fba9 100644 --- a/common/src/main/java/org/embeddedt/modernfix/ModernFix.java +++ b/common/src/main/java/org/embeddedt/modernfix/ModernFix.java @@ -1,5 +1,6 @@ package org.embeddedt.modernfix; +import net.minecraft.SharedConstants; import net.minecraft.Util; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ChunkMap; @@ -11,6 +12,7 @@ import org.embeddedt.modernfix.core.ModernFixMixinPlugin; import org.embeddedt.modernfix.platform.ModernFixPlatformHooks; import org.embeddedt.modernfix.resources.ReloadExecutor; import org.embeddedt.modernfix.util.ClassInfoManager; +import org.embeddedt.modernfix.world.IntegratedWatchdog; import java.lang.management.ManagementFactory; import java.util.concurrent.ExecutorService; @@ -23,6 +25,8 @@ public class ModernFix { public static final String MODID = "modernfix"; + public static String NAME = "ModernFix"; + public static ModernFix INSTANCE; // Used to skip computing the blockstate caches twice @@ -45,7 +49,22 @@ public class ModernFix { public ModernFix() { INSTANCE = this; + if(ModernFixMixinPlugin.instance.isOptionEnabled("feature.snapshot_easter_egg.NameChange") && !SharedConstants.getCurrentVersion().isStable()) + NAME = "PreemptiveFix"; ModernFixPlatformHooks.onServerCommandRegister(ModernFixCommands::register); + if(ModernFixMixinPlugin.instance.isOptionEnabled("feature.spam_thread_dump.ThreadDumper")) { + Thread t = new Thread() { + public void run() { + while(true) { + LOGGER.error("------ DEBUG THREAD DUMP (occurs every 60 seconds) ------"); + LOGGER.error(IntegratedWatchdog.obtainThreadDump()); + try { Thread.sleep(60000); } catch(InterruptedException e) {} + } + } + }; + t.setDaemon(true); + t.start(); + } } public void onServerStarted() { diff --git a/common/src/main/java/org/embeddedt/modernfix/ModernFixClient.java b/common/src/main/java/org/embeddedt/modernfix/ModernFixClient.java index 7a020414..7fa3f7c3 100644 --- a/common/src/main/java/org/embeddedt/modernfix/ModernFixClient.java +++ b/common/src/main/java/org/embeddedt/modernfix/ModernFixClient.java @@ -11,6 +11,8 @@ import net.minecraft.network.syncher.SynchedEntityData; import net.minecraft.server.MinecraftServer; import net.minecraft.util.MemoryReserve; 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; @@ -22,6 +24,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; @@ -33,14 +36,26 @@ public class ModernFixClient { public String brandingString = null; + /** + * The list of loaded client integrations. + */ + public static List CLIENT_INTEGRATIONS = new CopyOnWriteArrayList<>(); + public ModernFixClient() { // clear reserve as it's not needed MemoryReserve.release(); if(ModernFixMixinPlugin.instance.isOptionEnabled("feature.branding.F3Screen")) { - brandingString = "ModernFix " + ModernFixPlatformHooks.getVersionString(); + brandingString = ModernFix.NAME + " " + ModernFixPlatformHooks.getVersionString(); } SearchTreeProviderRegistry.register(JEIBackedSearchTree.PROVIDER); SearchTreeProviderRegistry.register(REIBackedSearchTree.PROVIDER); + 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..aa3b78bc --- /dev/null +++ b/common/src/main/java/org/embeddedt/modernfix/api/entrypoint/ModernFixClientIntegration.java @@ -0,0 +1,62 @@ +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 use of an unbaked model at bake time 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 onUnbakedModelPreBake(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..293fe410 --- /dev/null +++ b/common/src/main/java/org/embeddedt/modernfix/api/helpers/ModelHelpers.java @@ -0,0 +1,74 @@ +package org.embeddedt.modernfix.api.helpers; + +import com.google.common.collect.ImmutableList; +import net.minecraft.client.resources.model.*; +import net.minecraft.core.registries.BuiltInRegistries; +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.duck.IExtendedModelBakery; +import org.embeddedt.modernfix.dynamicresources.ModelBakeryHelpers; +import org.embeddedt.modernfix.util.DynamicMap; +import org.jetbrains.annotations.Nullable; + +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 = BuiltInRegistries.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)); + } + + /** + * Provides a ModelBaker for mods to use. + * @param bakery the ModelBakery supplied to your integration + * @return an appropriate ModelBaker + */ + public static ModelBaker adaptBakery(ModelBakery bakery) { + return new ModelBaker() { + @Override + public UnbakedModel getModel(ResourceLocation resourceLocation) { + return bakery.getModel(resourceLocation); + } + + @Nullable + @Override + public BakedModel bake(ResourceLocation resourceLocation, ModelState modelState) { + return ((IExtendedModelBakery)bakery).bakeDefault(resourceLocation, modelState); + } + }; + } +} diff --git a/common/src/main/java/org/embeddedt/modernfix/common/mixin/bugfix/edge_chunk_not_saved/ChunkManagerMixin.java b/common/src/main/java/org/embeddedt/modernfix/common/mixin/bugfix/edge_chunk_not_saved/ChunkManagerMixin.java deleted file mode 100644 index 1b635a8f..00000000 --- a/common/src/main/java/org/embeddedt/modernfix/common/mixin/bugfix/edge_chunk_not_saved/ChunkManagerMixin.java +++ /dev/null @@ -1,33 +0,0 @@ -package org.embeddedt.modernfix.common.mixin.bugfix.edge_chunk_not_saved; - -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.ProtoChunk; -import net.minecraft.world.level.chunk.ImposterProtoChunk; -import net.minecraft.world.level.chunk.ChunkAccess; -import net.minecraft.server.level.ChunkHolder; -import net.minecraft.server.level.ChunkMap; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.ModifyArg; -import org.spongepowered.asm.mixin.injection.Redirect; - -import java.util.function.Predicate; - -/* https://github.com/SuperCoder7979/chunksavingfix-fabric/blob/main/src/main/java/supercoder79/chunksavingfix/mixin/MixinThreadedAnvilChunkStorage.java */ -@Mixin(ChunkMap.class) -public class ChunkManagerMixin { - // TODO: hits both at the moment- check and re-evaluate - @ModifyArg(method = "saveAllChunks(Z)V", at = @At(value = "INVOKE", target = "Ljava/util/stream/Stream;filter(Ljava/util/function/Predicate;)Ljava/util/stream/Stream;", ordinal = 0), require = 0) - private Predicate alwaysAccessibleFlush(Predicate chunkHolder) { - return c -> true; - } - @ModifyArg(method = "saveAllChunks(Z)V", at = @At(value = "INVOKE", target = "Ljava/util/stream/Stream;filter(Ljava/util/function/Predicate;)Ljava/util/stream/Stream;", ordinal = 1), require = 0) - private Predicate allowProtoChunkFlush(Predicate chunk) { - return c -> c instanceof ProtoChunk || c instanceof ImposterProtoChunk || c instanceof LevelChunk; - } - - @Redirect(method = "saveChunkIfNeeded", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ChunkHolder;wasAccessibleSinceLastSave()Z"), require = 0) - private boolean alwaysAccessible(ChunkHolder chunkHolder) { - return true; - } -} diff --git a/common/src/main/java/org/embeddedt/modernfix/common/mixin/bugfix/packet_leak/ClientPlayNetHandlerMixin.java b/common/src/main/java/org/embeddedt/modernfix/common/mixin/bugfix/packet_leak/ClientPlayNetHandlerMixin.java deleted file mode 100644 index cfc92448..00000000 --- a/common/src/main/java/org/embeddedt/modernfix/common/mixin/bugfix/packet_leak/ClientPlayNetHandlerMixin.java +++ /dev/null @@ -1,23 +0,0 @@ -package org.embeddedt.modernfix.common.mixin.bugfix.packet_leak; - -import net.minecraft.client.multiplayer.ClientPacketListener; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.network.protocol.game.ClientboundCustomPayloadPacket; -import org.embeddedt.modernfix.annotation.ClientOnlyMixin; -import org.embeddedt.modernfix.duck.IClientNetHandler; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -@Mixin(ClientPacketListener.class) -@ClientOnlyMixin -public class ClientPlayNetHandlerMixin { - /** - * @author embeddedt - * @reason allow the other function to track use of the buffer - */ - @Redirect(method = "handleCustomPayload", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/protocol/game/ClientboundCustomPayloadPacket;getData()Lnet/minecraft/network/FriendlyByteBuf;")) - private FriendlyByteBuf saveCopyForRelease(ClientboundCustomPayloadPacket instance) { - return ((IClientNetHandler)instance).getCopiedCustomBuffer(); - } -} 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 a21e1255..3e9e5edf 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 net.minecraft.world.item.ItemStack; @@ -8,6 +9,8 @@ import org.embeddedt.modernfix.annotation.ClientOnlyMixin; import org.embeddedt.modernfix.platform.ModernFixPlatformHooks; 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; @@ -36,6 +39,14 @@ public abstract class MinecraftMixin { this.searchRegistry.register(SearchRegistry.CREATIVE_TAGS, tagSupplier); this.searchRegistry.register(SearchRegistry.RECIPE_COLLECTIONS, list -> new DummySearchTree<>()); ModernFixPlatformHooks.registerCreativeSearchTrees(this.searchRegistry, nameSupplier, tagSupplier, this::populateSearchTree); + // 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(); } } diff --git a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_resources/BlockModelShaperMixin.java b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_resources/BlockModelShaperMixin.java index 5aa70d22..6f33dd5f 100644 --- a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_resources/BlockModelShaperMixin.java +++ b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_resources/BlockModelShaperMixin.java @@ -3,6 +3,7 @@ package org.embeddedt.modernfix.common.mixin.perf.dynamic_resources; 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.world.level.block.state.BlockState; import org.embeddedt.modernfix.annotation.ClientOnlyMixin; import org.embeddedt.modernfix.dynamicresources.ModelLocationCache; @@ -29,9 +30,14 @@ public class BlockModelShaperMixin { this.modelByStateCache = new DynamicOverridableMap<>(state -> modelManager.getModel(ModelLocationCache.get(state))); } + /** + * @author embeddedt + * @reason get the model from the dynamic model provider + */ @Overwrite public BakedModel getBlockModel(BlockState state) { - BakedModel model = modelManager.getModel(ModelLocationCache.get(state)); + ModelResourceLocation mrl = ModelLocationCache.get(state); + BakedModel model = mrl == null ? null : modelManager.getModel(mrl); if (model == null) { model = modelManager.getMissingModel(); } diff --git a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_resources/diagonalfences/MultipartAppenderMixin.java b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_resources/diagonalfences/MultipartAppenderMixin.java new file mode 100644 index 00000000..5be40715 --- /dev/null +++ b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_resources/diagonalfences/MultipartAppenderMixin.java @@ -0,0 +1,48 @@ +package org.embeddedt.modernfix.common.mixin.perf.dynamic_resources.diagonalfences; + +import fuzs.diagonalfences.api.world.level.block.DiagonalBlock; +import fuzs.diagonalfences.client.model.MultipartAppender; +import net.minecraft.client.renderer.block.model.multipart.MultiPart; +import net.minecraft.client.resources.model.ModelBakery; +import net.minecraft.client.resources.model.UnbakedModel; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.FenceBlock; +import org.embeddedt.modernfix.ModernFixClient; +import org.embeddedt.modernfix.annotation.RequiresMod; +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; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(MultipartAppender.class) +@RequiresMod("diagonalfences") +public abstract class MultipartAppenderMixin { + @Shadow(remap = false) + public static void appendDiagonalSelectors(ModelBakery modelBakery, MultiPart multiPart) { + throw new AssertionError(); + } + + private static boolean handlerInjected = false; + + @Inject(method = "onPrepareModelBaking", at = @At("RETURN")) + private static void setupHelper(CallbackInfo ci) { + if(handlerInjected) + return; + handlerInjected = true; + ModernFixClient.CLIENT_INTEGRATIONS.add(new ModernFixClientIntegration() { + @Override + public UnbakedModel onUnbakedModelLoad(ResourceLocation location, UnbakedModel originalModel, ModelBakery bakery) { + if(originalModel instanceof MultiPart multipart) { + Block block = multipart.definition.getOwner(); + if(block instanceof FenceBlock && block instanceof DiagonalBlock diagonalBlock && diagonalBlock.hasProperties()) { + appendDiagonalSelectors(bakery, multipart); + } + } + return originalModel; + } + }); + } +} diff --git a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/faster_item_rendering/ItemRendererMixin.java b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/faster_item_rendering/ItemRendererMixin.java index 43c58aca..2326798b 100644 --- a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/faster_item_rendering/ItemRendererMixin.java +++ b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/faster_item_rendering/ItemRendererMixin.java @@ -2,55 +2,33 @@ package org.embeddedt.modernfix.common.mixin.perf.faster_item_rendering; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; -import net.minecraft.client.color.item.ItemColors; import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.block.model.BakedQuad; import net.minecraft.client.renderer.block.model.ItemTransform; import net.minecraft.client.renderer.entity.ItemRenderer; import net.minecraft.client.resources.model.BakedModel; import net.minecraft.client.resources.model.SimpleBakedModel; -import net.minecraft.core.Direction; -import net.minecraft.util.RandomSource; import net.minecraft.world.item.ItemDisplayContext; import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.ItemStack; import org.embeddedt.modernfix.render.FastItemRenderType; import org.embeddedt.modernfix.render.RenderState; -import org.spongepowered.asm.mixin.Final; +import org.embeddedt.modernfix.render.SimpleItemModelView; 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.ModifyVariable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import java.util.List; - -@Mixin(ItemRenderer.class) +@Mixin(value = ItemRenderer.class, priority = 600) public abstract class ItemRendererMixin { - @Shadow @Final private ItemColors itemColors; - - private final RandomSource dummyRandom = RandomSource.createNewThreadLocalInstance(); - - private static final float[] COLOR_MULTIPLIER = new float[]{1.0F, 1.0F, 1.0F, 1.0F}; - private ItemDisplayContext transformType; + private final SimpleItemModelView modelView = new SimpleItemModelView(); @Inject(method = "render", at = @At("HEAD")) private void markRenderingType(ItemStack itemStack, ItemDisplayContext transformType, boolean leftHand, PoseStack matrixStack, MultiBufferSource buffer, int combinedLight, int combinedOverlay, BakedModel model, CallbackInfo ci) { this.transformType = transformType; } - private static final Direction[] ITEM_DIRECTIONS = new Direction[] { Direction.SOUTH }; - private static final Direction[] BLOCK_DIRECTIONS = new Direction[] { Direction.UP, Direction.EAST, Direction.NORTH }; - - private boolean isCorrectDirectionForType(FastItemRenderType type, Direction direction) { - if(type == FastItemRenderType.SIMPLE_ITEM) - return direction == Direction.SOUTH; - else { - return direction == Direction.UP || direction == Direction.EAST || direction == Direction.NORTH; - } - } - /** * If a model * - is a vanilla item model (SimpleBakedModel), @@ -59,8 +37,8 @@ public abstract class ItemRendererMixin { * we do not need to go through the process of rendering every quad. Just render the south ones (the ones facing the * camera). */ - @Inject(method = "renderModelLists", at = @At("HEAD"), cancellable = true) - private void fasterItemRender(BakedModel model, ItemStack stack, int combinedLight, int combinedOverlay, PoseStack matrixStack, VertexConsumer buffer, CallbackInfo ci) { + @ModifyVariable(method = "renderModelLists", at = @At("HEAD"), index = 1, argsOnly = true) + private BakedModel useSimpleWrappedItemModel(BakedModel model, BakedModel arg, ItemStack stack, int combinedLight, int combinedOverlay, PoseStack matrixStack, VertexConsumer buffer) { if(!RenderState.IS_RENDERING_LEVEL && !stack.isEmpty() && model.getClass() == SimpleBakedModel.class && transformType == ItemDisplayContext.GUI) { FastItemRenderType type; ItemTransform transform = model.getTransforms().gui; @@ -69,26 +47,12 @@ public abstract class ItemRendererMixin { else if(stack.getItem() instanceof BlockItem && isBlockTransforms(transform)) type = FastItemRenderType.SIMPLE_BLOCK; else - return; - ci.cancel(); - PoseStack.Pose pose = matrixStack.last(); - int[] combinedLights = new int[] {combinedLight, combinedLight, combinedLight, combinedLight}; - Direction[] directions = type == FastItemRenderType.SIMPLE_ITEM ? ITEM_DIRECTIONS : BLOCK_DIRECTIONS; - for(Direction direction : directions) { - List culledFaces = model.getQuads(null, direction, dummyRandom); - /* check size to avoid instantiating iterator when the list is empty */ - if(culledFaces.size() > 0) { - for(BakedQuad quad : culledFaces) { - render2dItemFace(quad, stack, buffer, pose, combinedLights, combinedOverlay); - } - } - } - List unculledFaces = model.getQuads(null, null, dummyRandom); - for(BakedQuad quad : unculledFaces) { - if(isCorrectDirectionForType(type, quad.getDirection())) - render2dItemFace(quad, stack, buffer, pose, combinedLights, combinedOverlay); - } - } + return model; + modelView.setItem(model); + modelView.setType(type); + return modelView; + } else + return model; } private boolean isBlockTransforms(ItemTransform transform) { @@ -96,16 +60,4 @@ public abstract class ItemRendererMixin { && transform.rotation.y() == 225f && transform.rotation.z() == 0f; } - - private void render2dItemFace(BakedQuad quad, ItemStack stack, VertexConsumer buffer, PoseStack.Pose pose, int[] combinedLights, int combinedOverlay) { - int i = -1; - if (quad.isTinted()) { - i = this.itemColors.getColor(stack, quad.getTintIndex()); - } - - float f = (float)(i >> 16 & 255) / 255.0F; - float f1 = (float)(i >> 8 & 255) / 255.0F; - float f2 = (float)(i & 255) / 255.0F; - buffer.putBulkData(pose, quad, COLOR_MULTIPLIER, f, f1, f2, combinedLights, combinedOverlay, true); - } } diff --git a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/nbt_memory_usage/CompoundTag1Mixin.java b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/nbt_memory_usage/CompoundTag1Mixin.java new file mode 100644 index 00000000..8034f856 --- /dev/null +++ b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/nbt_memory_usage/CompoundTag1Mixin.java @@ -0,0 +1,20 @@ +package org.embeddedt.modernfix.common.mixin.perf.nbt_memory_usage; + +import net.minecraft.nbt.Tag; +import org.embeddedt.modernfix.util.CanonizingStringMap; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyVariable; + +import java.util.Map; + +@Mixin(targets = "net/minecraft/nbt/CompoundTag$1") +public class CompoundTag1Mixin { + @ModifyVariable(method = "load(Ljava/io/DataInput;ILnet/minecraft/nbt/NbtAccounter;)Lnet/minecraft/nbt/CompoundTag;", at = @At(value = "INVOKE_ASSIGN", target = "Lcom/google/common/collect/Maps;newHashMap()Ljava/util/HashMap;", remap = false)) + private Map modifyMap(Map map) { + CanonizingStringMap newMap = new CanonizingStringMap<>(); + if(map != null) + newMap.putAll(map); + return newMap; + } +} \ No newline at end of file diff --git a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/nbt_memory_usage/CompoundTagMixin.java b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/nbt_memory_usage/CompoundTagMixin.java index 3e87a8c0..274af319 100644 --- a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/nbt_memory_usage/CompoundTagMixin.java +++ b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/nbt_memory_usage/CompoundTagMixin.java @@ -6,27 +6,25 @@ import org.embeddedt.modernfix.util.CanonizingStringMap; 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.ModifyArg; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import java.util.Map; @Mixin(CompoundTag.class) public class CompoundTagMixin { - @Shadow @Final @Mutable + @Shadow @Final private Map tags; /** - * Ensure that the backing map is always a CanonizingStringMap. + * Ensure that the default backing map is a CanonizingStringMap. */ - @Redirect(method = "(Ljava/util/Map;)V", at = @At(value = "FIELD", target = "Lnet/minecraft/nbt/CompoundTag;tags:Ljava/util/Map;", ordinal = 0)) - private void replaceTagMap(CompoundTag tag, Map incomingMap) { - if(incomingMap instanceof CanonizingStringMap) - this.tags = incomingMap; - else { - this.tags = new CanonizingStringMap<>(); - this.tags.putAll(incomingMap); - } + @ModifyArg(method = "()V", at = @At(value = "INVOKE", target = "Lnet/minecraft/nbt/CompoundTag;(Ljava/util/Map;)V"), index = 0) + private static Map useCanonizingStringMap(Map incoming) { + CanonizingStringMap newMap = new CanonizingStringMap<>(); + if(incoming != null) + newMap.putAll(incoming); + return newMap; } /** diff --git a/common/src/main/java/org/embeddedt/modernfix/common/mixin/safety/LivingEntityRendererMixin.java b/common/src/main/java/org/embeddedt/modernfix/common/mixin/safety/LivingEntityRendererMixin.java new file mode 100644 index 00000000..8e165b7b --- /dev/null +++ b/common/src/main/java/org/embeddedt/modernfix/common/mixin/safety/LivingEntityRendererMixin.java @@ -0,0 +1,28 @@ +package org.embeddedt.modernfix.common.mixin.safety; + +import net.minecraft.client.renderer.entity.LivingEntityRenderer; +import net.minecraft.client.renderer.entity.layers.RenderLayer; +import org.embeddedt.modernfix.annotation.ClientOnlyMixin; +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.callback.CallbackInfo; + +import java.util.Collections; +import java.util.List; + +@Mixin(LivingEntityRenderer.class) +@ClientOnlyMixin +public class LivingEntityRendererMixin { + @Shadow @Final @Mutable + protected List> layers; + + @Inject(method = "", at = @At("RETURN")) + private void synchronizeLayerList(CallbackInfo ci) { + /* allows buggy mods to call addLayer concurrently, order is not deterministic but can't fix that */ + this.layers = Collections.synchronizedList(layers); + } +} 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/core/config/ModernFixEarlyConfig.java b/common/src/main/java/org/embeddedt/modernfix/core/config/ModernFixEarlyConfig.java index 1d072c10..d7b505c2 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 @@ -59,6 +59,8 @@ public class ModernFixEarlyConfig { private final Set mixinOptions = new ObjectOpenHashSet<>(); private final Map mixinsMissingMods = new Object2ObjectOpenHashMap<>(); + public static boolean isFabric = false; + public Map getPermanentlyDisabledMixins() { return mixinsMissingMods; } @@ -71,6 +73,8 @@ public class ModernFixEarlyConfig { if(stream == null) continue; try(Reader reader = new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8))) { + if(configFile.contains("fabric")) + isFabric = true; JsonObject configObject = (JsonObject)new JsonParser().parse(reader); JsonArray mixinList = configObject.getAsJsonArray("mixins"); String packageName = configObject.get("package").getAsString().replace('.', '/'); @@ -143,6 +147,8 @@ public class ModernFixEarlyConfig { .put("mixin.perf.dynamic_entity_renderers", false) .put("mixin.feature.integrated_server_watchdog", true) .put("mixin.perf.faster_item_rendering", false) + .put("mixin.feature.spam_thread_dump", false) + .put("mixin.feature.snapshot_easter_egg", true) .put("mixin.devenv", isDevEnv) .put("mixin.perf.remove_spawn_chunks", isDevEnv) .build(); @@ -177,14 +183,21 @@ public class ModernFixEarlyConfig { disableIfModPresent("mixin.perf.thread_priorities", "smoothboot"); disableIfModPresent("mixin.perf.boost_worker_count", "smoothboot"); disableIfModPresent("mixin.perf.async_jei", "modernui"); - disableIfModPresent("mixin.perf.compress_biome_container", "chocolate", "betterendforge"); + disableIfModPresent("mixin.perf.compress_biome_container", "chocolate", "betterendforge" ,"skyblockbuilder"); disableIfModPresent("mixin.bugfix.mc218112", "performant"); disableIfModPresent("mixin.bugfix.remove_block_chunkloading", "performant"); disableIfModPresent("mixin.bugfix.paper_chunk_patches", "c2me"); + disableIfModPresent("mixin.perf.nbt_memory_usage", "c2me"); + // DimThread makes changes to the server chunk manager (understandably), C2ME probably does the same + disableIfModPresent("mixin.bugfix.chunk_deadlock", "c2me", "dimthread"); 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", "changed"); + if(isFabric) { + disableIfModPresent("mixin.bugfix.packet_leak", "memoryleakfix"); + } } private void disableIfModPresent(String configName, String... ids) { diff --git a/common/src/main/java/org/embeddedt/modernfix/duck/IClientNetHandler.java b/common/src/main/java/org/embeddedt/modernfix/duck/IClientNetHandler.java deleted file mode 100644 index 71b1a0a6..00000000 --- a/common/src/main/java/org/embeddedt/modernfix/duck/IClientNetHandler.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.embeddedt.modernfix.duck; - -import net.minecraft.network.FriendlyByteBuf; - -public interface IClientNetHandler { - FriendlyByteBuf getCopiedCustomBuffer(); -} diff --git a/common/src/main/java/org/embeddedt/modernfix/duck/IExtendedModelBakery.java b/common/src/main/java/org/embeddedt/modernfix/duck/IExtendedModelBakery.java index 50a325be..4cabb89b 100644 --- a/common/src/main/java/org/embeddedt/modernfix/duck/IExtendedModelBakery.java +++ b/common/src/main/java/org/embeddedt/modernfix/duck/IExtendedModelBakery.java @@ -3,6 +3,7 @@ package org.embeddedt.modernfix.duck; import com.google.common.collect.ImmutableList; import net.minecraft.client.resources.model.BakedModel; import net.minecraft.client.resources.model.ModelResourceLocation; +import net.minecraft.client.resources.model.ModelState; import net.minecraft.client.resources.model.UnbakedModel; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.block.Block; @@ -11,7 +12,7 @@ import net.minecraft.world.level.block.state.StateDefinition; public interface IExtendedModelBakery { ImmutableList getBlockStatesForMRL(StateDefinition stateDefinition, ModelResourceLocation location); - BakedModel bakeDefault(ResourceLocation modelLocation); + BakedModel bakeDefault(ResourceLocation modelLocation, ModelState state); BakedModel getBakedMissingModel(); void setBakedMissingModel(BakedModel m); UnbakedModel mfix$getUnbakedMissingModel(); 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 75db839f..85dc7d72 100644 --- a/common/src/main/java/org/embeddedt/modernfix/dynamicresources/DynamicBakedModelProvider.java +++ b/common/src/main/java/org/embeddedt/modernfix/dynamicresources/DynamicBakedModelProvider.java @@ -15,6 +15,7 @@ import net.minecraft.util.RandomSource; import net.minecraft.world.level.block.state.BlockState; import org.apache.commons.lang3.tuple.Triple; import org.embeddedt.modernfix.duck.IExtendedModelBakery; +import org.embeddedt.modernfix.ModernFix; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -109,7 +110,12 @@ public class DynamicBakedModelProvider implements Map getCustomModOptions() { + throw new AssertionError(); + } + @ExpectPlatform public static void registerCreativeSearchTrees(SearchRegistry registry, SearchRegistry.TreeBuilderSupplier nameSupplier, SearchRegistry.TreeBuilderSupplier tagSupplier, BiConsumer, List> populator) { throw new AssertionError(); diff --git a/common/src/main/java/org/embeddedt/modernfix/render/SimpleItemModelView.java b/common/src/main/java/org/embeddedt/modernfix/render/SimpleItemModelView.java new file mode 100644 index 00000000..b1a27b0f --- /dev/null +++ b/common/src/main/java/org/embeddedt/modernfix/render/SimpleItemModelView.java @@ -0,0 +1,94 @@ +package org.embeddedt.modernfix.render; + +import com.google.common.collect.ImmutableList; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.renderer.block.model.ItemOverrides; +import net.minecraft.client.renderer.block.model.ItemTransforms; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.resources.model.BakedModel; +import net.minecraft.core.Direction; +import net.minecraft.util.RandomSource; +import net.minecraft.world.level.block.state.BlockState; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +/** + * Wrapper class that presents a fake view of item models (only showing the simple front-facing quads), rather + * than every quad. + */ +public class SimpleItemModelView implements BakedModel { + private BakedModel wrappedItem; + private FastItemRenderType type; + + public void setItem(BakedModel model) { + this.wrappedItem = model; + } + + public void setType(FastItemRenderType type) { + this.type = type; + } + + private boolean isCorrectDirectionForType(Direction direction) { + if(type == FastItemRenderType.SIMPLE_ITEM) + return direction == Direction.SOUTH; + else { + return direction == Direction.UP || direction == Direction.EAST || direction == Direction.NORTH; + } + } + + private final List nullQuadList = new ObjectArrayList<>(); + + @Override + public List getQuads(@Nullable BlockState state, @Nullable Direction side, RandomSource rand) { + if(side != null) { + return isCorrectDirectionForType(side) ? wrappedItem.getQuads(state, side, rand) : ImmutableList.of(); + } else { + nullQuadList.clear(); + List realList = wrappedItem.getQuads(state, null, rand); + for(int i = 0; i < realList.size(); i++) { + BakedQuad quad = realList.get(i); + if(isCorrectDirectionForType(quad.getDirection())) { + nullQuadList.add(quad); + } + } + return nullQuadList; + } + } + + @Override + public boolean useAmbientOcclusion() { + return wrappedItem.useAmbientOcclusion(); + } + + @Override + public boolean isGui3d() { + return wrappedItem.isGui3d(); + } + + @Override + public boolean usesBlockLight() { + return wrappedItem.usesBlockLight(); + } + + @Override + public boolean isCustomRenderer() { + return wrappedItem.isCustomRenderer(); + } + + @Override + public TextureAtlasSprite getParticleIcon() { + return wrappedItem.getParticleIcon(); + } + + @Override + public ItemTransforms getTransforms() { + return wrappedItem.getTransforms(); + } + + @Override + public ItemOverrides getOverrides() { + return wrappedItem.getOverrides(); + } +} diff --git a/common/src/main/java/org/embeddedt/modernfix/resources/PackResourcesCacheEngine.java b/common/src/main/java/org/embeddedt/modernfix/resources/PackResourcesCacheEngine.java index 25cf6267..6bf1ec8f 100644 --- a/common/src/main/java/org/embeddedt/modernfix/resources/PackResourcesCacheEngine.java +++ b/common/src/main/java/org/embeddedt/modernfix/resources/PackResourcesCacheEngine.java @@ -8,6 +8,7 @@ import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.PackType; import org.embeddedt.modernfix.ModernFix; +import org.embeddedt.modernfix.platform.ModernFixPlatformHooks; import org.embeddedt.modernfix.util.PackTypeHelper; import java.io.IOException; @@ -163,6 +164,8 @@ public class PackResourcesCacheEngine { } public static void invalidate() { + if(!ModernFixPlatformHooks.isDevEnv()) + return; synchronized (cachingPacks) { cachingPacks.keySet().forEach(pack -> { if(pack != null) diff --git a/common/src/main/java/org/embeddedt/modernfix/searchtree/JEIBackedSearchTree.java b/common/src/main/java/org/embeddedt/modernfix/searchtree/JEIBackedSearchTree.java index e237733a..8b3e41c9 100644 --- a/common/src/main/java/org/embeddedt/modernfix/searchtree/JEIBackedSearchTree.java +++ b/common/src/main/java/org/embeddedt/modernfix/searchtree/JEIBackedSearchTree.java @@ -98,7 +98,7 @@ public class JEIBackedSearchTree extends DummySearchTree { @Override public boolean canUse() { - return ModernFixPlatformHooks.modPresent("jei") && getIngredientListUncached != null && filterField != null; + return ModernFixPlatformHooks.modPresent("jei") && !ModernFixPlatformHooks.modPresent("emi") && getIngredientListUncached != null && filterField != null; } @Override diff --git a/common/src/main/java/org/embeddedt/modernfix/searchtree/REIBackedSearchTree.java b/common/src/main/java/org/embeddedt/modernfix/searchtree/REIBackedSearchTree.java index f48bb6ac..15debcd0 100644 --- a/common/src/main/java/org/embeddedt/modernfix/searchtree/REIBackedSearchTree.java +++ b/common/src/main/java/org/embeddedt/modernfix/searchtree/REIBackedSearchTree.java @@ -1,22 +1,28 @@ package org.embeddedt.modernfix.searchtree; +import com.google.common.base.Predicates; import me.shedaniel.rei.api.client.registry.entry.EntryRegistry; import me.shedaniel.rei.api.common.entry.EntryStack; import me.shedaniel.rei.api.common.entry.type.VanillaEntryTypes; import me.shedaniel.rei.impl.client.search.AsyncSearchManager; +import me.shedaniel.rei.impl.common.entry.type.EntryRegistryImpl; +import me.shedaniel.rei.impl.common.util.HashedEntryStackWrapper; import net.minecraft.client.searchtree.RefreshableSearchTree; import net.minecraft.world.item.ItemStack; import org.embeddedt.modernfix.ModernFix; import org.embeddedt.modernfix.platform.ModernFixPlatformHooks; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.function.Supplier; +import java.util.function.UnaryOperator; public class REIBackedSearchTree extends DummySearchTree { - private final AsyncSearchManager searchManager = new AsyncSearchManager(EntryRegistry.getInstance()::getPreFilteredList, () -> { - return stack -> true; - }, EntryStack::normalize); + private final AsyncSearchManager searchManager = createSearchManager(); private final boolean filteringByTag; private String lastSearchText = ""; @@ -39,14 +45,23 @@ public class REIBackedSearchTree extends DummySearchTree { if(!pSearchText.equals(lastSearchText)) { listCache.clear(); this.searchManager.updateFilter(pSearchText); - List> stacks; + List stacks; try { stacks = this.searchManager.getNow(); } catch(RuntimeException e) { ModernFix.LOGGER.error("Couldn't search for '" + pSearchText + "'", e); stacks = Collections.emptyList(); } - for(EntryStack stack : stacks) { + for(Object o : stacks) { + EntryStack stack; + if(o instanceof EntryStack) + stack = (EntryStack)o; + else if(o instanceof HashedEntryStackWrapper) { + stack = ((HashedEntryStackWrapper)o).unwrap(); + } else { + ModernFix.LOGGER.error("Don't know how to handle {}", o.getClass().getName()); + continue; + } if(stack.getType() == VanillaEntryTypes.ITEM) { listCache.add(stack.cheatsAs().getValue()); } @@ -56,6 +71,50 @@ public class REIBackedSearchTree extends DummySearchTree { return listCache; } + @SuppressWarnings({"unchecked", "rawtypes"}) + private static AsyncSearchManager createSearchManager() { + Method m, normalizeMethod; + try { + try { + m = EntryRegistryImpl.class.getDeclaredMethod("getPreFilteredComplexList"); + m.setAccessible(true); + normalizeMethod = HashedEntryStackWrapper.class.getDeclaredMethod("normalize"); + normalizeMethod.setAccessible(true); + } catch(NoSuchMethodException e) { + m = EntryRegistryImpl.class.getDeclaredMethod("getPreFilteredList"); + m.setAccessible(true); + normalizeMethod = EntryStack.class.getDeclaredMethod("normalize"); + normalizeMethod.setAccessible(true); + } + final MethodHandle getListMethod = MethodHandles.publicLookup().unreflect(m); + final MethodHandle normalize = MethodHandles.publicLookup().unreflect(normalizeMethod); + final EntryRegistryImpl registry = (EntryRegistryImpl)EntryRegistry.getInstance(); + Supplier stackListSupplier = () -> { + try { + return (List)getListMethod.invokeExact(registry); + } catch(Throwable e) { + if(e instanceof RuntimeException) + throw (RuntimeException)e; + throw new RuntimeException(e); + } + }; + UnaryOperator normalizeOperator = o -> { + try { + return normalize.invoke(o); + } catch(Throwable e) { + if(e instanceof RuntimeException) + throw (RuntimeException)e; + throw new RuntimeException(e); + } + }; + return new AsyncSearchManager(stackListSupplier, () -> { + return Predicates.alwaysTrue(); + }, normalizeOperator); + } catch(ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } + public static final SearchTreeProviderRegistry.Provider PROVIDER = new SearchTreeProviderRegistry.Provider() { @Override public RefreshableSearchTree getSearchTree(boolean tag) { diff --git a/common/src/main/java/org/embeddedt/modernfix/structure/CachingStructureManager.java b/common/src/main/java/org/embeddedt/modernfix/structure/CachingStructureManager.java index 6bf07666..08debc7c 100644 --- a/common/src/main/java/org/embeddedt/modernfix/structure/CachingStructureManager.java +++ b/common/src/main/java/org/embeddedt/modernfix/structure/CachingStructureManager.java @@ -63,7 +63,8 @@ public class CachingStructureManager { currentTag.putInt("DataVersion", 500); } int currentDataVersion = currentTag.getInt("DataVersion"); - if(currentDataVersion < SharedConstants.getCurrentVersion().getDataVersion().getVersion()) { + int requiredMinimumDataVersion = SharedConstants.getCurrentVersion().getDataVersion().getVersion(); + if(currentDataVersion < requiredMinimumDataVersion) { /* Needs upgrade, try looking up from cache */ MessageDigest hasher = digestThreadLocal.get(); hasher.reset(); @@ -71,13 +72,13 @@ public class CachingStructureManager { CompoundTag cachedUpgraded = getCachedUpgraded(location, truncateHash(hash)); if(cachedUpgraded == null) cachedUpgraded = getCachedUpgraded(location, hash); /* pick up old cache */ - if(cachedUpgraded != null && cachedUpgraded.getInt("DataVersion") == SharedConstants.getCurrentVersion().getDataVersion().getVersion()) { + if(cachedUpgraded != null && cachedUpgraded.getInt("DataVersion") == requiredMinimumDataVersion) { ModernFix.LOGGER.debug("Using cached upgraded version of {}", location); currentTag = cachedUpgraded; } else { synchronized (laggyStructureMods) { if(laggyStructureMods.add(location.getNamespace())) { - ModernFix.LOGGER.warn("Mod {} is shipping outdated structure files, which can cause worldgen lag; please report this to them.", location.getNamespace()); + ModernFix.LOGGER.warn("The namespace {} contains an outdated structure file, which can cause worldgen lag. Please view debug.log for the full filename, determine which mod provides the structure, and report to the mod/datapack author, including the debug log.", location.getNamespace()); } } ModernFix.LOGGER.debug("Structure {} is being run through DFU (hash {}), this will cause launch time delays", location, hash); 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 05bd219b..1202500b 100644 --- a/common/src/main/java/org/embeddedt/modernfix/util/CanonizingStringMap.java +++ b/common/src/main/java/org/embeddedt/modernfix/util/CanonizingStringMap.java @@ -141,6 +141,7 @@ public class CanonizingStringMap implements Map { } public static CanonizingStringMap deepCopy(CanonizingStringMap inputMap, Function deepCopier) { + Objects.requireNonNull(deepCopier); Object2ObjectMap copiedBackingMap; int size = inputMap.backingMap.size(); if(size > GROWTH_THRESHOLD) { @@ -148,7 +149,8 @@ public class CanonizingStringMap implements Map { } else copiedBackingMap = new Object2ObjectArrayMap<>(size); inputMap.backingMap.object2ObjectEntrySet().forEach(entry -> { - copiedBackingMap.put(entry.getKey(), deepCopier.apply(entry.getValue())); + if(entry.getKey() != null && entry.getValue() != null) + copiedBackingMap.put(entry.getKey(), deepCopier.apply(entry.getValue())); }); return new CanonizingStringMap<>(copiedBackingMap); } diff --git a/common/src/main/java/org/embeddedt/modernfix/world/IntegratedWatchdog.java b/common/src/main/java/org/embeddedt/modernfix/world/IntegratedWatchdog.java index 32a5707a..ae7c987e 100644 --- a/common/src/main/java/org/embeddedt/modernfix/world/IntegratedWatchdog.java +++ b/common/src/main/java/org/embeddedt/modernfix/world/IntegratedWatchdog.java @@ -25,6 +25,27 @@ public class IntegratedWatchdog extends Thread { this.setName("ModernFix integrated server watchdog"); } + public static String obtainThreadDump() { + ThreadMXBean threadmxbean = ManagementFactory.getThreadMXBean(); + ThreadInfo[] athreadinfo = threadmxbean.dumpAllThreads(true, true); + StringBuilder sb = new StringBuilder(); + sb.append("Thread Dump:\n"); + for(ThreadInfo threadinfo : athreadinfo) { + sb.append(threadinfo); + StackTraceElement[] elements = threadinfo.getStackTrace(); + if(elements.length > 8) { + sb.append("extended trace:\n"); + for(int i = 8; i < elements.length; i++) { + sb.append("\tat "); + sb.append(elements[i]); + sb.append('\n'); + } + } + sb.append('\n'); + } + return sb.toString(); + } + public void run() { while(true) { MinecraftServer server = this.server.get(); @@ -35,24 +56,7 @@ public class IntegratedWatchdog extends Thread { long delta = curTime - nextTick; if(delta > MAX_TICK_DELTA) { LOGGER.error("A single server tick has taken {}, more than {} milliseconds", delta, MAX_TICK_DELTA); - ThreadMXBean threadmxbean = ManagementFactory.getThreadMXBean(); - ThreadInfo[] athreadinfo = threadmxbean.dumpAllThreads(true, true); - StringBuilder sb = new StringBuilder(); - sb.append("Thread Dump:\n"); - for(ThreadInfo threadinfo : athreadinfo) { - sb.append(threadinfo); - StackTraceElement[] elements = threadinfo.getStackTrace(); - if(elements.length > 8) { - sb.append("extended trace:\n"); - for(int i = 8; i < elements.length; i++) { - sb.append("\tat "); - sb.append(elements[i]); - sb.append('\n'); - } - } - sb.append('\n'); - } - LOGGER.error(sb.toString()); + LOGGER.error(obtainThreadDump()); nextTick = 0; curTime = 0; } diff --git a/common/src/main/resources/modernfix.accesswidener b/common/src/main/resources/modernfix.accesswidener index 344227a9..e422ca5e 100644 --- a/common/src/main/resources/modernfix.accesswidener +++ b/common/src/main/resources/modernfix.accesswidener @@ -35,3 +35,5 @@ 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; +accessible field net/minecraft/client/KeyMapping ALL Ljava/util/Map; +accessible field net/minecraft/client/renderer/block/model/multipart/MultiPart definition Lnet/minecraft/world/level/block/state/StateDefinition; diff --git a/fabric/build.gradle b/fabric/build.gradle index 0a7f2f6c..3317c721 100644 --- a/fabric/build.gradle +++ b/fabric/build.gradle @@ -37,6 +37,7 @@ dependencies { modImplementation(fabricApi.module("fabric-resource-loader-v0", rootProject.fabric_api_version)) { exclude group: 'net.fabricmc', module: 'fabric-loader' } modImplementation(fabricApi.module("fabric-data-generation-api-v1", 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}" diff --git a/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakerImplMixin.java b/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakerImplMixin.java index f6441b48..c7cc45fb 100644 --- a/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakerImplMixin.java +++ b/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/perf/dynamic_resources/ModelBakerImplMixin.java @@ -8,6 +8,8 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import org.embeddedt.modernfix.ModernFix; +import org.embeddedt.modernfix.ModernFixClient; +import org.embeddedt.modernfix.api.entrypoint.ModernFixClientIntegration; import org.embeddedt.modernfix.duck.IExtendedModelBakery; import org.embeddedt.modernfix.dynamicresources.DynamicBakedModelProvider; import org.spongepowered.asm.mixin.Final; @@ -58,39 +60,63 @@ public abstract class ModelBakerImplMixin { } private boolean wasMissingModel = false; + private ResourceLocation capturedLocation; + private UnbakedModel capturedModel; + private ModelState capturedState; + + @Inject(method = "bake", at = @At("HEAD")) + private void captureState(ResourceLocation rl, ModelState state, CallbackInfoReturnable cir) { + capturedState = state; + } @Inject(method = "getModel", at = @At("HEAD"), cancellable = true) private void obtainModel(ResourceLocation arg, CallbackInfoReturnable cir) { + capturedLocation = arg; if(debugDynamicModelLoading) ModernFix.LOGGER.info("Baking {}", arg); IExtendedModelBakery extendedBakery = (IExtendedModelBakery)this.field_40571; if(arg instanceof ModelResourceLocation && arg != ModelBakery.MISSING_MODEL_LOCATION) { - /* to emulate vanilla model loading, treat as top-level */ - Optional blockOpt = Objects.equals(((ModelResourceLocation)arg).getVariant(), "inventory") ? Optional.empty() : BuiltInRegistries.BLOCK.getOptional(new ResourceLocation(arg.getNamespace(), arg.getPath())); - if(blockOpt.isPresent()) { - /* load via lambda for mods that expect blockstate to get loaded */ - for(BlockState state : extendedBakery.getBlockStatesForMRL(blockOpt.get().getStateDefinition(), (ModelResourceLocation)arg)) { - try { - blockStateLoaderHandle.invokeExact(this.field_40571, state); - } catch(Throwable e) { - ModernFix.LOGGER.error("Error loading model", e); + // synchronized because we use topLevelModels + synchronized (this.field_40571) { + /* to emulate vanilla model loading, treat as top-level */ + Optional blockOpt = Objects.equals(((ModelResourceLocation)arg).getVariant(), "inventory") ? Optional.empty() : BuiltInRegistries.BLOCK.getOptional(new ResourceLocation(arg.getNamespace(), arg.getPath())); + if(blockOpt.isPresent()) { + /* load via lambda for mods that expect blockstate to get loaded */ + for(BlockState state : extendedBakery.getBlockStatesForMRL(blockOpt.get().getStateDefinition(), (ModelResourceLocation)arg)) { + try { + blockStateLoaderHandle.invokeExact(this.field_40571, state); + } catch(Throwable e) { + ModernFix.LOGGER.error("Error loading model", e); + } } + } else { + this.field_40571.loadTopLevel((ModelResourceLocation)arg); } - } else { - this.field_40571.loadTopLevel((ModelResourceLocation)arg); + cir.setReturnValue(this.field_40571.topLevelModels.getOrDefault(arg, extendedBakery.mfix$getUnbakedMissingModel())); + // avoid leaks + this.field_40571.topLevelModels.clear(); } - cir.setReturnValue(this.field_40571.topLevelModels.getOrDefault(arg, extendedBakery.mfix$getUnbakedMissingModel())); - // avoid leaks - this.field_40571.topLevelModels.clear(); } else cir.setReturnValue(this.field_40571.getModel(arg)); + UnbakedModel toReplace = cir.getReturnValue(); + if(!wasMissingModel) { + for(ModernFixClientIntegration integration : ModernFixClient.CLIENT_INTEGRATIONS) { + try { + toReplace = integration.onUnbakedModelPreBake(arg, toReplace, (ModelBakery)(Object)this); + } catch(RuntimeException e) { + ModernFix.LOGGER.error("Exception firing model pre-bake event for {}", arg, e); + } + } + } + cir.setReturnValue(toReplace); + cir.getReturnValue().resolveParents(this.field_40571::getModel); + capturedModel = cir.getReturnValue(); if(cir.getReturnValue() == extendedBakery.mfix$getUnbakedMissingModel()) { if(arg != ModelBakery.MISSING_MODEL_LOCATION && debugDynamicModelLoading) ModernFix.LOGGER.warn("Model {} not present", arg); wasMissingModel = true; } else wasMissingModel = false; /* sometimes this runs more than once e.g. for recursive model baking */ - cir.getReturnValue().resolveParents(this.field_40571::getModel); } @ModifyVariable(method = "bake", at = @At(value = "INVOKE_ASSIGN", target = "Lnet/minecraft/client/resources/model/UnbakedModel;bake(Lnet/minecraft/client/resources/model/ModelBaker;Ljava/util/function/Function;Lnet/minecraft/client/resources/model/ModelState;Lnet/minecraft/resources/ResourceLocation;)Lnet/minecraft/client/resources/model/BakedModel;")) @@ -109,6 +135,9 @@ public abstract class ModelBakerImplMixin { } return missing; } + for(ModernFixClientIntegration integration : ModernFixClient.CLIENT_INTEGRATIONS) { + model = integration.onBakedModelLoad(capturedLocation, capturedModel, model, capturedState, this.field_40571); + } return model; } 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 7c56d153..36ef4dda 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 @@ -14,7 +14,9 @@ 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 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; @@ -28,6 +30,7 @@ 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; @@ -107,11 +110,6 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery { this.bakedTopLevelModels = new DynamicBakedModelProvider((ModelBakery)(Object)this, bakedCache); } - @Inject(method = "", at = @At("RETURN")) - private void stopIgnore(CallbackInfo ci) { - this.ignoreModelLoad = false; - } - private void onModelRemoved(RemovalNotification notification) { if(!debugDynamicModelLoading) return; @@ -171,6 +169,7 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery { @Inject(method = "bakeModels", at = @At("HEAD")) private void captureGetter(BiFunction getter, CallbackInfo ci) { + this.ignoreModelLoad = false; textureGetter = getter; } @@ -189,6 +188,17 @@ 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 @@ -256,14 +266,14 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery { } @Override - public BakedModel bakeDefault(ResourceLocation modelLocation) { + public BakedModel bakeDefault(ResourceLocation modelLocation, ModelState state) { ModelBakery.BakedCacheKey key = new ModelBakery.BakedCacheKey(modelLocation, BlockModelRotation.X0_Y0.getRotation(), BlockModelRotation.X0_Y0.isUvLocked()); BakedModel m = loadedBakedModels.getIfPresent(key); if(m != null) return m; ModelBakery self = (ModelBakery) (Object) this; ModelBaker theBaker = self.new ModelBakerImpl(textureGetter, modelLocation); - m = theBaker.bake(modelLocation, BlockModelRotation.X0_Y0); + m = theBaker.bake(modelLocation, state); if(m != null) loadedBakedModels.put(key, m); return m; diff --git a/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/safety/DynamicTextureMixin.java b/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/safety/DynamicTextureMixin.java new file mode 100644 index 00000000..5cc7f1ac --- /dev/null +++ b/fabric/src/main/java/org/embeddedt/modernfix/fabric/mixin/safety/DynamicTextureMixin.java @@ -0,0 +1,30 @@ +package org.embeddedt.modernfix.fabric.mixin.safety; + +import com.mojang.blaze3d.platform.NativeImage; +import net.minecraft.client.renderer.texture.DynamicTexture; +import org.embeddedt.modernfix.ModernFix; +import org.jetbrains.annotations.Nullable; +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; + +@Mixin(DynamicTexture.class) +public class DynamicTextureMixin { + @Shadow @Nullable private NativeImage pixels; + + private Exception closeTrace; + + @Inject(method = "method_22793", at = @At(value = "FIELD", target = "Lnet/minecraft/client/renderer/texture/DynamicTexture;pixels:Lcom/mojang/blaze3d/platform/NativeImage;", ordinal = 0)) + private void checkNullPixels(CallbackInfo ci) { + if(pixels == null) { + ModernFix.LOGGER.error("Attempted to upload null texture! This is not allowed, closed here", closeTrace); + } + } + + @Inject(method = "close", at = @At("HEAD")) + private void storeCloseTrace(CallbackInfo ci) { + closeTrace = new Exception(); + } +} 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 f10a53a9..e7c88873 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,20 +1,26 @@ package org.embeddedt.modernfix.platform.fabric; +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.Multimap; import com.mojang.brigadier.CommandDispatcher; import net.fabricmc.api.EnvType; import net.fabricmc.fabric.api.command.v2.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.searchtree.SearchRegistry; import net.minecraft.commands.CommandSourceStack; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.item.ItemStack; import org.embeddedt.modernfix.ModernFixFabric; +import org.embeddedt.modernfix.api.constants.IntegrationConstants; import org.objectweb.asm.tree.*; import java.nio.file.Path; import java.util.List; +import java.util.Map; import java.util.function.BiConsumer; import java.util.function.Consumer; @@ -72,6 +78,28 @@ public class ModernFixPlatformHooksImpl { CommandRegistrationCallback.EVENT.register((dispatcher, arg, env) -> 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; + } + public static void registerCreativeSearchTrees(SearchRegistry registry, SearchRegistry.TreeBuilderSupplier nameSupplier, SearchRegistry.TreeBuilderSupplier tagSupplier, BiConsumer, List> populator) { /* no-op on Fabric */ } diff --git a/fabric/src/main/resources/fabric.mod.json b/fabric/src/main/resources/fabric.mod.json index 598db739..f1518b24 100644 --- a/fabric/src/main/resources/fabric.mod.json +++ b/fabric/src/main/resources/fabric.mod.json @@ -34,7 +34,7 @@ "fabric-screen-api-v1": "*", "fabric-command-api-v2": "*", "fabric-models-v0": "*", - "minecraft": ">=1.16.5" + "minecraft": ">=1.16.2" }, "breaks": { "dashloader": "*" diff --git a/forge/build.gradle b/forge/build.gradle index 8a60e93f..650783d7 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:4455391") - modCompileOnly("appeng:appliedenergistics2-forge:12.9.4") modCompileOnly("vazkii.patchouli:Patchouli:1.19.2-77") common(project(path: ":common", configuration: "namedElements")) { transitive false } 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 3b67e62f..00000000 --- a/forge/src/main/java/org/embeddedt/modernfix/forge/dynamicresources/DynamicModelBakeEvent.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.embeddedt.modernfix.forge.dynamicresources; - -import net.minecraft.client.resources.model.*; -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; - private final UnbakedModel unbakedModel; - private final ModelBaker modelLoader; - private final ModelBakery modelBakery; - public DynamicModelBakeEvent(ResourceLocation location, UnbakedModel unbakedModel, BakedModel model, ModelBaker loader, ModelBakery bakery) { - this.location = location; - this.model = model; - this.unbakedModel = unbakedModel; - this.modelLoader = loader; - this.modelBakery = bakery; - } - - public ResourceLocation getLocation() { - return this.location; - } - - public BakedModel getModel() { - return this.model; - } - - public UnbakedModel getUnbakedModel() { - return this.unbakedModel; - } - - public ModelBaker getModelLoader() { - return this.modelLoader; - } - - public ModelBakery getModelBakery() { - return this.modelBakery; - } - - public void setModel(BakedModel model) { - this.model = model; - } -} diff --git a/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/dynamic_resources/ModelBakerImplMixin.java b/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/dynamic_resources/ModelBakerImplMixin.java index 23e1a669..7402eb9b 100644 --- a/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/dynamic_resources/ModelBakerImplMixin.java +++ b/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/dynamic_resources/ModelBakerImplMixin.java @@ -4,11 +4,11 @@ import net.minecraft.client.renderer.block.model.BlockModel; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.resources.model.*; import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.common.MinecraftForge; import org.embeddedt.modernfix.ModernFix; +import org.embeddedt.modernfix.ModernFixClient; +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.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -48,6 +48,15 @@ public abstract class ModelBakerImplMixin { ibakedmodel = ModelBakery.ITEM_MODEL_GENERATOR.generateBlockModel(textureGetter, blockmodel).bake((ModelBaker)this, blockmodel, textureGetter, arg2, arg, false); } } + if(iunbakedmodel != extendedBakery.mfix$getUnbakedMissingModel()) { + for(ModernFixClientIntegration integration : ModernFixClient.CLIENT_INTEGRATIONS) { + try { + iunbakedmodel = integration.onUnbakedModelPreBake(arg, iunbakedmodel, (ModelBakery)(Object)this); + } catch(RuntimeException e) { + ModernFix.LOGGER.error("Exception encountered firing bake event for {}", arg, e); + } + } + } if(ibakedmodel == null) { if(iunbakedmodel == extendedBakery.mfix$getUnbakedMissingModel()) { // use a shared baked missing model @@ -59,10 +68,11 @@ public abstract class ModelBakerImplMixin { } else ibakedmodel = iunbakedmodel.bake((ModelBaker)this, textureGetter, arg2, arg); } - DynamicModelBakeEvent event = new DynamicModelBakeEvent(arg, iunbakedmodel, ibakedmodel, (ModelBaker)this, this.field_40571); - MinecraftForge.EVENT_BUS.post(event); - this.field_40571.bakedCache.put(key, event.getModel()); - cir.setReturnValue(event.getModel()); + for(ModernFixClientIntegration integration : ModernFixClient.CLIENT_INTEGRATIONS) { + ibakedmodel = integration.onBakedModelLoad(arg, iunbakedmodel, ibakedmodel, arg2, this.field_40571); + } + this.field_40571.bakedCache.put(key, ibakedmodel); + cir.setReturnValue(ibakedmodel); } } } 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 0c87eda0..da1a4d9f 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 @@ -14,6 +14,8 @@ 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 org.embeddedt.modernfix.ModernFix; +import org.embeddedt.modernfix.ModernFixClient; +import org.embeddedt.modernfix.api.entrypoint.ModernFixClientIntegration; import org.embeddedt.modernfix.dynamicresources.DynamicBakedModelProvider; import org.embeddedt.modernfix.duck.IExtendedModelBakery; import org.embeddedt.modernfix.annotation.ClientOnlyMixin; @@ -26,6 +28,7 @@ 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.ModifyVariable; import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @@ -157,6 +160,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); @@ -229,10 +244,10 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery { } @Override - public BakedModel bakeDefault(ResourceLocation modelLocation) { + public BakedModel bakeDefault(ResourceLocation modelLocation, ModelState state) { ModelBakery self = (ModelBakery) (Object) this; ModelBaker theBaker = self.new ModelBakerImpl(textureGetter, modelLocation); - return theBaker.bake(modelLocation, BlockModelRotation.X0_Y0); + return theBaker.bake(modelLocation, state); } @Override 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 deleted file mode 100644 index 7218e3ca..00000000 --- a/forge/src/main/java/org/embeddedt/modernfix/forge/mixin/perf/dynamic_resources/ae2/RegistrationMixin.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.embeddedt.modernfix.forge.mixin.perf.dynamic_resources.ae2; - -import appeng.core.AppEng; -import appeng.init.client.InitAutoRotatingModel; -import net.minecraft.client.resources.model.BakedModel; -import net.minecraft.client.resources.model.ModelBakery; -import net.minecraftforge.common.MinecraftForge; -import org.embeddedt.modernfix.annotation.ClientOnlyMixin; -import org.embeddedt.modernfix.annotation.RequiresMod; -import org.spongepowered.asm.mixin.Final; -import org.embeddedt.modernfix.forge.dynamicresources.DynamicModelBakeEvent; -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 java.util.Map; -import java.util.function.Function; - -@Mixin(InitAutoRotatingModel.class) -@RequiresMod("appliedenergistics2") -@ClientOnlyMixin -public class RegistrationMixin { - @Shadow @Final private static Map> CUSTOMIZERS; - @Inject(method = "init", at = @At("TAIL"), remap = false) - private static void doRegisterDynBake(CallbackInfo ci) { - MinecraftForge.EVENT_BUS.addListener(RegistrationMixin::onDynamicModelBake); - } - - private static void onDynamicModelBake(DynamicModelBakeEvent event) { - if (!event.getLocation().getNamespace().equals(AppEng.MOD_ID)) { - return; - } - BakedModel missing = event.getModelBakery().getBakedTopLevelModels().get(ModelBakery.MISSING_MODEL_LOCATION); - if(event.getModel() == missing) - return; - Function customizerFn = CUSTOMIZERS.get(event.getLocation().getPath()); - if(customizerFn != null) - event.setModel(customizerFn.apply(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 44fa59fc..02928406 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,24 +3,20 @@ 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.core.Holder; 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.client.ChunkRenderTypeSet; -import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.eventbus.api.EventPriority; import net.minecraftforge.registries.ForgeRegistries; 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; @@ -38,7 +34,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; @@ -52,7 +48,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) @@ -77,28 +73,32 @@ 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())); Holder.Reference delegate = block != null ? ForgeRegistries.BLOCKS.getDelegateOrThrow(block) : null; if(block == null || block == Blocks.AIR || renderCheckOverrides.containsKey(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(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 29ccffe0..bb88b4ca 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.ModelBaker; -import net.minecraft.client.resources.model.UnbakedModel; +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.embeddedt.modernfix.api.helpers.ModelHelpers; 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, ModelBaker 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,7 +55,7 @@ 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; } @@ -87,12 +83,13 @@ public abstract class TextureMetadataHandlerMixin { } if (shouldWrap) { try { - event.setModel(wrap(rl, rootModel, baked, event.getModelLoader())); + baked = wrap(rl, rootModel, baked, ModelHelpers.adaptBakery(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 f00211eb..f7674d06 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,20 +15,24 @@ 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 public class ClientSetupMixin { @Shadow @Final private static BakedModelOverrideRegistry BAKED_MODEL_OVERRIDE_REGISTRY; - @Inject(method = "onClientSetup", at = @At("RETURN"), remap = false) - private static void addDynamicListener(CallbackInfo ci) { - MinecraftForge.EVENT_BUS.addListener(ClientSetupMixin::onDynamicModelBake); - } - - private static void onDynamicModelBake(DynamicModelBakeEvent event) { - BakedModelOverrideRegistry.BakedModelOverrideFactory factory = BAKED_MODEL_OVERRIDE_REGISTRY.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.getModelBakery().getBakedTopLevelModels())); + @Inject(method = "", at = @At("RETURN")) + private void addDynamicListener(CallbackInfo ci) { + ModernFixClient.CLIENT_INTEGRATIONS.add(new ModernFixClientIntegration() { + @Override + public BakedModel onBakedModelLoad(ResourceLocation location, UnbakedModel baseModel, BakedModel originalModel, ModelState state, ModelBakery bakery) { + BakedModelOverrideRegistry.BakedModelOverrideFactory factory = BAKED_MODEL_OVERRIDE_REGISTRY.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 487c42aa..183cb7d5 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.mojang.brigadier.CommandDispatcher; import net.minecraft.client.searchtree.SearchRegistry; import net.minecraft.commands.CommandSourceStack; @@ -15,9 +17,10 @@ import net.minecraftforge.fml.ModLoader; 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.network.PacketDistributor; import net.minecraftforge.server.ServerLifecycleHooks; +import org.embeddedt.modernfix.api.constants.IntegrationConstants; import org.embeddedt.modernfix.core.ModernFixMixinPlugin; import org.embeddedt.modernfix.forge.classloading.FastAccessTransformerList; import org.embeddedt.modernfix.forge.packet.PacketHandler; @@ -55,7 +58,7 @@ public class ModernFixPlatformHooksImpl { } public static boolean isDevEnv() { - return !FMLLoader.isProduction() && FMLLoader.getLoadingModList().getModFileById("modernfix").getFile().getProvider() instanceof ExplodedDirectoryLocator; + return !FMLLoader.isProduction(); } public static MinecraftServer getCurrentServer() { @@ -100,11 +103,31 @@ public class ModernFixPlatformHooksImpl { }); } + 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; + } + public static void registerCreativeSearchTrees(SearchRegistry registry, SearchRegistry.TreeBuilderSupplier nameSupplier, SearchRegistry.TreeBuilderSupplier tagSupplier, BiConsumer, List> populator) { - for(SearchRegistry.Key nameKey : CreativeModeTabSearchRegistry.getNameSearchKeys().values()) { + for (SearchRegistry.Key nameKey : CreativeModeTabSearchRegistry.getNameSearchKeys().values()) { registry.register(nameKey, nameSupplier); } - for(SearchRegistry.Key tagKey : CreativeModeTabSearchRegistry.getTagSearchKeys().values()) { + for (SearchRegistry.Key tagKey : CreativeModeTabSearchRegistry.getTagSearchKeys().values()) { registry.register(tagKey, tagSupplier); } Map> tagSearchKeys = CreativeModeTabSearchRegistry.getTagSearchKeys(); diff --git a/gradle.properties b/gradle.properties index 53c0b4fa..d183f66a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -19,3 +19,4 @@ fabric_api_version=0.81.2+1.20 continuity_version=3.0.0-beta.2+1.19.3 modmenu_version=7.0.0-beta.2 +diagonal_fences_version=4545943