diff --git a/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_resources/MixinModelManager.java b/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_resources/MixinModelManager.java index 9f02acde..1225ff6c 100644 --- a/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_resources/MixinModelManager.java +++ b/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_resources/MixinModelManager.java @@ -1,5 +1,7 @@ package org.embeddedt.modernfix.common.mixin.perf.dynamic_resources; +import net.minecraft.client.resources.model.BlockStateModelLoader; +import net.minecraft.client.resources.model.ClientItemInfoLoader; import net.minecraft.client.resources.model.ModelManager; import net.minecraft.client.resources.model.UnbakedModel; import net.minecraft.resources.Identifier; @@ -7,6 +9,7 @@ import net.minecraft.server.packs.resources.Resource; import org.embeddedt.modernfix.annotation.ClientOnlyMixin; import org.embeddedt.modernfix.dynresources.DynamicModelSystem; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.ModifyArg; @@ -27,4 +30,15 @@ public class MixinModelManager { private static Function, ? extends CompletionStage>> skipAOTUnbakedModelLoad(Function, ? extends CompletionStage>> original) { return resourceMap -> CompletableFuture.completedFuture(DynamicModelSystem.createDynamicUnbakedModelMap(resourceMap)); } + + /** + * @author embeddedt + * @reason Model resolution is not necessary, because we dynamically find models as they are referenced + */ + @Overwrite + private static ModelManager.ResolvedModels discoverModelDependencies( + Map inputModels, BlockStateModelLoader.LoadedModels loadedModels, ClientItemInfoLoader.LoadedClientInfos loadedClientInfos, net.neoforged.neoforge.client.model.standalone.StandaloneModelLoader.LoadedModels standaloneModels + ) { + return new DynamicModelSystem.DynamicResolver(inputModels, loadedModels, loadedClientInfos, standaloneModels).resolvedModels(); + } } diff --git a/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_resources/ModelDiscoveryAccessor.java b/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_resources/ModelDiscoveryAccessor.java new file mode 100644 index 00000000..34ecacee --- /dev/null +++ b/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_resources/ModelDiscoveryAccessor.java @@ -0,0 +1,15 @@ +package org.embeddedt.modernfix.common.mixin.perf.dynamic_resources; + +import it.unimi.dsi.fastutil.objects.Object2ObjectMap; +import net.minecraft.client.resources.model.ModelDiscovery; +import net.minecraft.resources.Identifier; +import org.embeddedt.modernfix.annotation.ClientOnlyMixin; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(ModelDiscovery.class) +@ClientOnlyMixin +public interface ModelDiscoveryAccessor { + @Accessor("modelWrappers") + Object2ObjectMap mfix$getModelWrappers(); +} diff --git a/src/main/java/org/embeddedt/modernfix/dynresources/DynamicModelSystem.java b/src/main/java/org/embeddedt/modernfix/dynresources/DynamicModelSystem.java index 19554b96..03bbc302 100644 --- a/src/main/java/org/embeddedt/modernfix/dynresources/DynamicModelSystem.java +++ b/src/main/java/org/embeddedt/modernfix/dynresources/DynamicModelSystem.java @@ -4,7 +4,14 @@ import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import com.google.common.collect.Maps; +import net.minecraft.client.renderer.block.model.ItemModelGenerator; +import net.minecraft.client.renderer.item.ItemModel; import net.minecraft.client.resources.model.BlockStateModelLoader; +import net.minecraft.client.resources.model.ClientItemInfoLoader; +import net.minecraft.client.resources.model.MissingBlockModel; +import net.minecraft.client.resources.model.ModelDiscovery; +import net.minecraft.client.resources.model.ModelManager; +import net.minecraft.client.resources.model.ResolvedModel; import net.minecraft.client.resources.model.UnbakedModel; import net.minecraft.resources.FileToIdConverter; import net.minecraft.resources.Identifier; @@ -12,8 +19,10 @@ import net.minecraft.server.packs.resources.Resource; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import net.neoforged.neoforge.client.model.UnbakedModelParser; +import net.neoforged.neoforge.client.model.standalone.StandaloneModelLoader; import org.embeddedt.modernfix.ModernFix; import org.embeddedt.modernfix.common.mixin.perf.dynamic_resources.IdMapperAccessor; +import org.embeddedt.modernfix.common.mixin.perf.dynamic_resources.ModelDiscoveryAccessor; import java.io.Reader; import java.util.List; @@ -70,4 +79,37 @@ public class DynamicModelSystem { return loadedModels.models().get(state); })); } + + public record DynamicResolver(Map inputModels, + BlockStateModelLoader.LoadedModels loadedModels, + ClientItemInfoLoader.LoadedClientInfos loadedClientInfos, + StandaloneModelLoader.LoadedModels standaloneModels) { + + private ResolvedModel resolveModel(Identifier id) { + var discovery = new ModelDiscovery(inputModels, MissingBlockModel.missingModel()); + discovery.addSpecialModel(ItemModelGenerator.GENERATED_ITEM_MODEL_ID, new ItemModelGenerator()); + if (!id.equals(ItemModelGenerator.GENERATED_ITEM_MODEL_ID)) { + UnbakedModel unbaked = inputModels.get(id); + if (unbaked != null) { + var wrapper = discovery.createAndQueueWrapper(id, unbaked); + ((ModelDiscoveryAccessor)discovery).mfix$getModelWrappers().put(id, wrapper); + } else { + ModernFix.LOGGER.warn("Cannot find the root model for {}", id); + } + } + var resolved = discovery.resolve(); + return resolved.getOrDefault(id, discovery.missingModel()); + } + + public ModelManager.ResolvedModels resolvedModels() { + var resolvedMissingModel = new ModelDiscovery(inputModels, MissingBlockModel.missingModel()).missingModel(); + LoadingCache resolvedModelCache = CacheBuilder.newBuilder().softValues().maximumSize(1000).build(new CacheLoader<>() { + @Override + public ResolvedModel load(Identifier key) { + return resolveModel(key); + } + }); + return new ModelManager.ResolvedModels(resolvedMissingModel, Maps.asMap(inputModels.keySet(), resolvedModelCache::getUnchecked)); + } + } } diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg index bcbffbeb..89dd0f65 100644 --- a/src/main/resources/META-INF/accesstransformer.cfg +++ b/src/main/resources/META-INF/accesstransformer.cfg @@ -54,4 +54,8 @@ public net.minecraft.world.level.levelgen.DensityFunctions$MulOrAdd$Type public net.minecraft.client.renderer.entity.EnderDragonRenderer$DragonModel entity public net.minecraft.client.KeyMapping ALL -public net.minecraft.client.resources.model.BlockStateModelLoader$LoadedBlockModelDefinition \ No newline at end of file +public net.minecraft.client.resources.model.BlockStateModelLoader$LoadedBlockModelDefinition +public net.minecraft.client.resources.model.ModelManager$ResolvedModels +public net.minecraft.client.resources.model.ModelDiscovery$ModelWrapper +public net.minecraft.client.resources.model.ModelDiscovery$ModelWrapper ModelWrapper(Lnet/minecraft/resources/Identifier;Lnet/minecraft/client/resources/model/UnbakedModel;Z)V +public net.minecraft.client.resources.model.ModelDiscovery createAndQueueWrapper(Lnet/minecraft/resources/Identifier;Lnet/minecraft/client/resources/model/UnbakedModel;)Lnet/minecraft/client/resources/model/ModelDiscovery$ModelWrapper; \ No newline at end of file