|
1 | 1 | package org.embeddedt.modernfix.forge.mixin.perf.dynamic_resources; |
2 | 2 |
|
3 | | -import net.minecraft.client.renderer.block.model.BlockModel; |
| 3 | +import com.llamalad7.mixinextras.injector.ModifyExpressionValue; |
4 | 4 | import net.minecraft.client.renderer.texture.TextureAtlasSprite; |
5 | 5 | import net.minecraft.client.resources.model.*; |
| 6 | +import net.minecraft.core.registries.BuiltInRegistries; |
6 | 7 | import net.minecraft.resources.ResourceLocation; |
| 8 | +import net.minecraft.world.level.block.Block; |
| 9 | +import net.minecraft.world.level.block.state.BlockState; |
| 10 | +import net.minecraftforge.fml.util.ObfuscationReflectionHelper; |
7 | 11 | import org.embeddedt.modernfix.ModernFix; |
8 | 12 | import org.embeddedt.modernfix.ModernFixClient; |
9 | 13 | import org.embeddedt.modernfix.api.entrypoint.ModernFixClientIntegration; |
|
17 | 21 | import org.spongepowered.asm.mixin.injection.Inject; |
18 | 22 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; |
19 | 23 |
|
| 24 | +import java.lang.invoke.MethodHandle; |
| 25 | +import java.lang.invoke.MethodHandles; |
| 26 | +import java.util.Objects; |
| 27 | +import java.util.Optional; |
20 | 28 | import java.util.function.Function; |
21 | 29 |
|
22 | | -@Mixin(ModelBakery.ModelBakerImpl.class) |
| 30 | +@Mixin(value = ModelBakery.ModelBakerImpl.class, priority = 600) |
23 | 31 | public abstract class ModelBakerImplMixin implements IModelBakerImpl { |
24 | 32 | private static final boolean debugDynamicModelLoading = Boolean.getBoolean("modernfix.debugDynamicModelLoading"); |
25 | 33 | @Shadow @Final private ModelBakery field_40571; |
26 | 34 |
|
27 | | - @Shadow public abstract UnbakedModel getModel(ResourceLocation arg); |
28 | | - |
29 | 35 | private boolean mfix$ignoreCache = false; |
30 | 36 |
|
| 37 | + @Shadow @Final private Function<Material, TextureAtlasSprite> modelTextureGetter; |
| 38 | + |
| 39 | + private static final MethodHandle blockStateLoaderHandle; |
| 40 | + static { |
| 41 | + try { |
| 42 | + blockStateLoaderHandle = MethodHandles.lookup().unreflect( |
| 43 | + ObfuscationReflectionHelper.findMethod(ModelBakery.class, "m_119263_", BlockState.class) |
| 44 | + ); |
| 45 | + } catch(ReflectiveOperationException e) { |
| 46 | + throw new RuntimeException(e); |
| 47 | + } |
| 48 | + } |
| 49 | + |
31 | 50 | @Override |
32 | 51 | public void mfix$ignoreCache() { |
33 | 52 | mfix$ignoreCache = true; |
34 | 53 | } |
35 | 54 |
|
36 | | - @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) |
37 | | - public void getOrLoadBakedModelDynamic(ResourceLocation arg, ModelState arg2, Function<Material, TextureAtlasSprite> textureGetter, CallbackInfoReturnable<BakedModel> cir) { |
38 | | - ModelBakery.BakedCacheKey key = new ModelBakery.BakedCacheKey(arg, arg2.getRotation(), arg2.isUvLocked()); |
39 | | - BakedModel existing = mfix$ignoreCache ? null : this.field_40571.bakedCache.get(key); |
40 | | - if (existing != null) { |
41 | | - cir.setReturnValue(existing); |
42 | | - } else { |
43 | | - synchronized (this) { |
44 | | - if(debugDynamicModelLoading) |
45 | | - ModernFix.LOGGER.info("Baking {}", arg); |
46 | | - UnbakedModel iunbakedmodel = this.getModel(arg); |
47 | | - IExtendedModelBakery extendedBakery = (IExtendedModelBakery)this.field_40571; |
48 | | - if(iunbakedmodel == extendedBakery.mfix$getUnbakedMissingModel() && debugDynamicModelLoading) |
49 | | - ModernFix.LOGGER.warn("Model {} not present", arg); |
50 | | - // TODO: make sure parent resolution doesn't re-run many times |
51 | | - iunbakedmodel.resolveParents(this::getModel); |
52 | | - BakedModel ibakedmodel = null; |
53 | | - if (iunbakedmodel instanceof BlockModel) { |
54 | | - BlockModel blockmodel = (BlockModel)iunbakedmodel; |
55 | | - if (blockmodel.getRootModel() == ModelBakery.GENERATION_MARKER) { |
56 | | - ibakedmodel = ModelBakery.ITEM_MODEL_GENERATOR.generateBlockModel(textureGetter, blockmodel).bake((ModelBaker)this, blockmodel, textureGetter, arg2, arg, false); |
57 | | - } |
58 | | - } |
59 | | - if(iunbakedmodel != extendedBakery.mfix$getUnbakedMissingModel()) { |
60 | | - for(ModernFixClientIntegration integration : ModernFixClient.CLIENT_INTEGRATIONS) { |
| 55 | + private ResourceLocation capturedLocation; |
| 56 | + private UnbakedModel capturedModel; |
| 57 | + private ModelState capturedState; |
| 58 | + |
| 59 | + @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"), remap = false) |
| 60 | + private void captureState(ResourceLocation arg, ModelState state, Function<Material, TextureAtlasSprite> sprites, CallbackInfoReturnable<BakedModel> cir) { |
| 61 | + capturedState = state; |
| 62 | + } |
| 63 | + |
| 64 | + @Inject(method = "getModel", at = @At("HEAD"), cancellable = true) |
| 65 | + private void obtainModel(ResourceLocation arg, CallbackInfoReturnable<UnbakedModel> cir) { |
| 66 | + capturedLocation = arg; |
| 67 | + if(debugDynamicModelLoading) |
| 68 | + ModernFix.LOGGER.info("Baking {}", arg); |
| 69 | + IExtendedModelBakery extendedBakery = (IExtendedModelBakery)this.field_40571; |
| 70 | + if(arg instanceof ModelResourceLocation && arg != ModelBakery.MISSING_MODEL_LOCATION) { |
| 71 | + // synchronized because we use topLevelModels |
| 72 | + synchronized (this.field_40571) { |
| 73 | + /* to emulate vanilla model loading, treat as top-level */ |
| 74 | + Optional<Block> blockOpt = Objects.equals(((ModelResourceLocation)arg).getVariant(), "inventory") ? Optional.empty() : BuiltInRegistries.BLOCK.getOptional(new ResourceLocation(arg.getNamespace(), arg.getPath())); |
| 75 | + if(blockOpt.isPresent()) { |
| 76 | + /* load via lambda for mods that expect blockstate to get loaded */ |
| 77 | + for(BlockState state : extendedBakery.getBlockStatesForMRL(blockOpt.get().getStateDefinition(), (ModelResourceLocation)arg)) { |
61 | 78 | try { |
62 | | - iunbakedmodel = integration.onUnbakedModelPreBake(arg, iunbakedmodel, this.field_40571); |
63 | | - } catch(RuntimeException e) { |
64 | | - ModernFix.LOGGER.error("Exception encountered firing bake event for {}", arg, e); |
| 79 | + blockStateLoaderHandle.invokeExact(this.field_40571, state); |
| 80 | + } catch(Throwable e) { |
| 81 | + ModernFix.LOGGER.error("Error loading model", e); |
65 | 82 | } |
66 | 83 | } |
| 84 | + } else { |
| 85 | + this.field_40571.loadTopLevel((ModelResourceLocation)arg); |
67 | 86 | } |
68 | | - if(ibakedmodel == null) { |
69 | | - if(iunbakedmodel == extendedBakery.mfix$getUnbakedMissingModel()) { |
70 | | - // use a shared baked missing model |
71 | | - if(extendedBakery.getBakedMissingModel() == null) { |
72 | | - extendedBakery.setBakedMissingModel(iunbakedmodel.bake((ModelBaker)this, textureGetter, arg2, arg)); |
73 | | - ((DynamicBakedModelProvider)this.field_40571.getBakedTopLevelModels()).setMissingModel(extendedBakery.getBakedMissingModel()); |
74 | | - } |
75 | | - ibakedmodel = extendedBakery.getBakedMissingModel(); |
76 | | - } else |
77 | | - ibakedmodel = iunbakedmodel.bake((ModelBaker)this, textureGetter, arg2, arg); |
78 | | - } |
79 | | - for(ModernFixClientIntegration integration : ModernFixClient.CLIENT_INTEGRATIONS) { |
80 | | - ibakedmodel = integration.onBakedModelLoad(arg, iunbakedmodel, ibakedmodel, arg2, this.field_40571); |
| 87 | + cir.setReturnValue(this.field_40571.topLevelModels.getOrDefault(arg, extendedBakery.mfix$getUnbakedMissingModel())); |
| 88 | + // avoid leaks |
| 89 | + this.field_40571.topLevelModels.clear(); |
| 90 | + } |
| 91 | + } else |
| 92 | + cir.setReturnValue(this.field_40571.getModel(arg)); |
| 93 | + UnbakedModel toReplace = cir.getReturnValue(); |
| 94 | + if(true) { |
| 95 | + for(ModernFixClientIntegration integration : ModernFixClient.CLIENT_INTEGRATIONS) { |
| 96 | + try { |
| 97 | + toReplace = integration.onUnbakedModelPreBake(arg, toReplace, this.field_40571); |
| 98 | + } catch(RuntimeException e) { |
| 99 | + ModernFix.LOGGER.error("Exception firing model pre-bake event for {}", arg, e); |
81 | 100 | } |
82 | | - this.field_40571.bakedCache.put(key, ibakedmodel); |
83 | | - cir.setReturnValue(ibakedmodel); |
84 | 101 | } |
85 | 102 | } |
| 103 | + cir.setReturnValue(toReplace); |
| 104 | + cir.getReturnValue().resolveParents(this.field_40571::getModel); |
| 105 | + capturedModel = cir.getReturnValue(); |
| 106 | + if(cir.getReturnValue() == extendedBakery.mfix$getUnbakedMissingModel()) { |
| 107 | + if(arg != ModelBakery.MISSING_MODEL_LOCATION && debugDynamicModelLoading) |
| 108 | + ModernFix.LOGGER.warn("Model {} not present", arg); |
| 109 | + } |
| 110 | + } |
| 111 | + |
| 112 | + @ModifyExpressionValue(method = "bake(Lnet/minecraft/resources/ResourceLocation;Lnet/minecraft/client/resources/model/ModelState;Ljava/util/function/Function;)Lnet/minecraft/client/resources/model/BakedModel;", at = @At(value = "INVOKE", target = "Ljava/util/Map;get(Ljava/lang/Object;)Ljava/lang/Object;", ordinal = 0)) |
| 113 | + private Object ignoreCacheIfRequested(Object o) { |
| 114 | + return mfix$ignoreCache ? null : o; |
| 115 | + } |
| 116 | + |
| 117 | + @ModifyExpressionValue(method = "bake(Lnet/minecraft/resources/ResourceLocation;Lnet/minecraft/client/resources/model/ModelState;Ljava/util/function/Function;)Lnet/minecraft/client/resources/model/BakedModel;", at = @At(value = "INVOKE", 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;")) |
| 118 | + private BakedModel unifyMissingBakedModel(BakedModel model) { |
| 119 | + for(ModernFixClientIntegration integration : ModernFixClient.CLIENT_INTEGRATIONS) { |
| 120 | + model = integration.onBakedModelLoad(capturedLocation, capturedModel, model, capturedState, this.field_40571); |
| 121 | + } |
| 122 | + return model; |
86 | 123 | } |
87 | 124 | } |
0 commit comments