diff --git a/src/main/java/org/embeddedt/modernfix/ModernFix.java b/src/main/java/org/embeddedt/modernfix/ModernFix.java index 2af32f35..6ea713c6 100644 --- a/src/main/java/org/embeddedt/modernfix/ModernFix.java +++ b/src/main/java/org/embeddedt/modernfix/ModernFix.java @@ -17,7 +17,7 @@ import org.apache.logging.log4j.Logger; import org.embeddedt.modernfix.core.config.ModernFixConfig; import org.embeddedt.modernfix.entity.EntityDataIDSyncHandler; import org.embeddedt.modernfix.packet.PacketHandler; - +import org.embeddedt.modernfix.registry.ObjectHolderClearer; import java.lang.management.ManagementFactory; import java.util.concurrent.CountDownLatch; @@ -88,6 +88,7 @@ public class ModernFix { ModLoader.get().addWarning(new ModLoadingWarning(ModLoadingContext.get().getActiveContainer().getModInfo(), ModLoadingStage.COMMON_SETUP, "modernfix.no_lazydfu")); }); } + ObjectHolderClearer.clearThrowables(); } @SubscribeEvent diff --git a/src/main/java/org/embeddedt/modernfix/duck/IExtendedModelBakery.java b/src/main/java/org/embeddedt/modernfix/duck/IExtendedModelBakery.java index 34ce3862..49435254 100644 --- a/src/main/java/org/embeddedt/modernfix/duck/IExtendedModelBakery.java +++ b/src/main/java/org/embeddedt/modernfix/duck/IExtendedModelBakery.java @@ -1,8 +1,11 @@ package org.embeddedt.modernfix.duck; - -import net.minecraft.client.renderer.texture.AtlasSet; +import com.google.common.collect.ImmutableList; +import net.minecraft.client.resources.model.ModelResourceLocation; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition; public interface IExtendedModelBakery { - AtlasSet getUnfinishedAtlasSet(); + ImmutableList getBlockStatesForMRL(StateDefinition stateDefinition, ModelResourceLocation location); } diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ModelBakeryMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ModelBakeryMixin.java index 6f3ffe75..3bf84525 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ModelBakeryMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ModelBakeryMixin.java @@ -38,6 +38,7 @@ import net.minecraftforge.registries.ForgeRegistries; import net.minecraftforge.registries.ForgeRegistryEntry; import org.apache.commons.lang3.tuple.Triple; import org.embeddedt.modernfix.ModernFix; +import org.embeddedt.modernfix.duck.IExtendedModelBakery; import org.embeddedt.modernfix.dynamicresources.DynamicBakedModelProvider; import org.embeddedt.modernfix.dynamicresources.DynamicModelBakeEvent; import org.embeddedt.modernfix.dynamicresources.ModelLocationCache; @@ -64,7 +65,7 @@ import java.util.stream.Stream; /* high priority so that our injectors are added before other mods' */ @Mixin(value = ModelBakery.class, priority = 600) -public abstract class ModelBakeryMixin { +public abstract class ModelBakeryMixin implements IExtendedModelBakery { private static final boolean debugDynamicModelLoading = Boolean.getBoolean("modernfix.debugDynamicModelLoading"); @@ -436,6 +437,11 @@ public abstract class ModelBakeryMixin { return ImmutableList.copyOf(finalList); } + @Override + public ImmutableList getBlockStatesForMRL(StateDefinition stateDefinition, ModelResourceLocation location) { + return loadOnlyRelevantBlockState(stateDefinition, location); + } + @Inject(method = "bake(Lnet/minecraft/resources/ResourceLocation;Lnet/minecraft/client/resources/model/ModelState;Ljava/util/function/Function;)Lnet/minecraft/client/resources/model/BakedModel;", at = @At("HEAD"), cancellable = true, remap = false) public void getOrLoadBakedModelDynamic(ResourceLocation arg, ModelState arg2, Function textureGetter, CallbackInfoReturnable cir) { Triple triple = Triple.of(arg, arg2.getRotation(), arg2.isUvLocked()); diff --git a/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ctm/CTMPackReloadListenerMixin.java b/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ctm/CTMPackReloadListenerMixin.java index 9799f23b..63c7404b 100644 --- a/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ctm/CTMPackReloadListenerMixin.java +++ b/src/main/java/org/embeddedt/modernfix/mixin/perf/dynamic_resources/ctm/CTMPackReloadListenerMixin.java @@ -1,5 +1,6 @@ package org.embeddedt.modernfix.mixin.perf.dynamic_resources.ctm; +import com.google.common.collect.ImmutableList; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import net.minecraft.client.renderer.ItemBlockRenderTypes; import net.minecraft.client.renderer.RenderType; @@ -8,13 +9,17 @@ 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.resources.ResourceLocation; import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.state.BlockState; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.eventbus.api.EventPriority; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; import net.minecraftforge.registries.ForgeRegistries; import net.minecraftforge.registries.IRegistryDelegate; +import org.embeddedt.modernfix.ModernFix; +import org.embeddedt.modernfix.duck.IExtendedModelBakery; import org.embeddedt.modernfix.dynamicresources.DynamicModelBakeEvent; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; @@ -37,8 +42,6 @@ public abstract class CTMPackReloadListenerMixin { @Shadow protected abstract Predicate getExistingRenderCheck(Block block); - private Map locationToState = new Object2ObjectOpenHashMap<>(); - @Inject(method = "", at = @At("RETURN")) private void onInit(CallbackInfo ci) { MinecraftForge.EVENT_BUS.addListener(EventPriority.LOW, this::onModelBake); @@ -48,28 +51,30 @@ public abstract class CTMPackReloadListenerMixin { private void refreshLayerHacks() { blockRenderChecks.forEach((b, p) -> ItemBlockRenderTypes.setRenderLayer((Block) b.get(), p)); blockRenderChecks.clear(); - if(locationToState.isEmpty()) { - for(Block block : ForgeRegistries.BLOCKS.getValues()) { - for(BlockState state : block.getStateDefinition().getPossibleStates()) { - locationToState.put(BlockModelShaper.stateToModelLocation(state), state); - } - } - } } private void onModelBake(DynamicModelBakeEvent event) { if(!(event.getModel() instanceof AbstractCTMBakedModel || event.getModel() instanceof WeightedBakedModel || event.getModel() instanceof MultiPartBakedModel)) return; - BlockState state = locationToState.get(event.getLocation()); - if(state == null) + /* we construct a new ResourceLocation because an MRL is coming in */ + Block block = ForgeRegistries.BLOCKS.getValue(new ResourceLocation(event.getLocation().getNamespace(), event.getLocation().getPath())); + if(block == null || block == Blocks.AIR || blockRenderChecks.containsKey(block.delegate)) return; - Block block = state.getBlock(); - if(blockRenderChecks.containsKey(block.delegate)) + /* find all states that match this MRL */ + ImmutableList allStates; + try { + allStates = ((IExtendedModelBakery)(Object)event.getModelLoader()).getBlockStatesForMRL(block.getStateDefinition(), (ModelResourceLocation)event.getLocation()); + } catch(RuntimeException e) { + ModernFix.LOGGER.error("Couldn't get state for MRL " + event.getLocation(), e); return; - Predicate newPredicate = this.getLayerCheck(state, event.getModel()); - if(newPredicate != null) { - blockRenderChecks.put(block.delegate, this.getExistingRenderCheck(block)); - ItemBlockRenderTypes.setRenderLayer(block, newPredicate); + } + for(BlockState state : allStates) { + Predicate newPredicate = this.getLayerCheck(state, event.getModel()); + if(newPredicate != null) { + blockRenderChecks.put(block.delegate, this.getExistingRenderCheck(block)); + ItemBlockRenderTypes.setRenderLayer(block, newPredicate); + return; + } } } } diff --git a/src/main/java/org/embeddedt/modernfix/registry/ObjectHolderClearer.java b/src/main/java/org/embeddedt/modernfix/registry/ObjectHolderClearer.java new file mode 100644 index 00000000..6ca0f948 --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/registry/ObjectHolderClearer.java @@ -0,0 +1,47 @@ +package org.embeddedt.modernfix.registry; + +import net.minecraft.resources.ResourceLocation; +import net.minecraftforge.fml.common.ObfuscationReflectionHelper; +import net.minecraftforge.registries.ObjectHolderRegistry; +import org.embeddedt.modernfix.ModernFix; + +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.List; +import java.util.Set; +import java.util.function.Consumer; +import java.util.function.Predicate; + +public class ObjectHolderClearer { + /** + * Many of the built-in Forge holders needlessly hold on to an exception. + */ + public static void clearThrowables() { + Set>> holders = ObfuscationReflectionHelper.getPrivateValue(ObjectHolderRegistry.class, null, "objectHolders"); + if(holders != null) { + int numCleared = 0; + HashMap, Field> throwableField = new HashMap<>(); + Throwable singletonThrowable = new Throwable("[This stacktrace was cleared to save memory]"); + try { + for(Consumer> holder : holders) { + Field target = throwableField.computeIfAbsent(holder.getClass(), clz -> { + Field[] clzFields = clz.getDeclaredFields(); + for(Field f : clzFields) { + if(Throwable.class.isAssignableFrom(f.getType())) { + f.setAccessible(true); + return f; + } + } + return null; + }); + if(target != null) { + target.set(holder, singletonThrowable); + numCleared++; + } + } + } catch(RuntimeException | ReflectiveOperationException | NoClassDefFoundError ignored) { + } + ModernFix.LOGGER.debug("Cleared " + numCleared + " object holder stacktrace references"); + } + } +}