diff --git a/build.gradle b/build.gradle index 462c88ed..3adce5c8 100644 --- a/build.gradle +++ b/build.gradle @@ -41,6 +41,17 @@ allprojects { includeGroup "curse.maven" } } + exclusiveContent { + forRepository { + maven { + name = "Modrinth" + url = "https://api.modrinth.com/maven" + } + } + filter { + includeGroup "maven.modrinth" + } + } maven { name = 'ParchmentMC' url = 'https://maven.parchmentmc.org' 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 18c2b0eb..0639d6c1 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 @@ -1,7 +1,6 @@ package org.embeddedt.modernfix.fabric.mixin.perf.dynamic_resources; import net.fabricmc.loader.api.FabricLoader; -import net.minecraft.client.renderer.block.model.BlockModel; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.resources.model.*; import net.minecraft.core.registries.BuiltInRegistries; @@ -16,14 +15,16 @@ 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.CallbackInfoReturnable; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; +import java.util.Objects; import java.util.Optional; import java.util.function.Function; -@Mixin(ModelBakery.ModelBakerImpl.class) +@Mixin(value = ModelBakery.ModelBakerImpl.class, priority = 600) public abstract class ModelBakerImplMixin { private static final boolean debugDynamicModelLoading = Boolean.getBoolean("modernfix.debugDynamicModelLoading"); @Shadow @Final private ModelBakery field_40571; @@ -49,41 +50,85 @@ public abstract class ModelBakerImplMixin { } } + private void createBakedMissingModelIfNeeded(IExtendedModelBakery extendedBakery, UnbakedModel iunbakedmodel, ModelState arg2, ResourceLocation arg) { + if(extendedBakery.getBakedMissingModel() == null) { + extendedBakery.setBakedMissingModel(iunbakedmodel.bake((ModelBaker)this, this.modelTextureGetter, arg2, arg)); + ((DynamicBakedModelProvider)this.field_40571.getBakedTopLevelModels()).setMissingModel(extendedBakery.getBakedMissingModel()); + } + } - @Inject(method = "bake", at = @At("HEAD"), cancellable = true) - public void getOrLoadBakedModelDynamic(ResourceLocation arg, ModelState arg2, CallbackInfoReturnable cir) { + private boolean wasMissingModel = false; + + @Inject(method = "getModel", at = @At("HEAD"), cancellable = true) + private void obtainModel(ResourceLocation arg, CallbackInfoReturnable cir) { + 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); + } + } + } 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(); + } else + cir.setReturnValue(this.field_40571.getModel(arg)); + if(cir.getReturnValue() == extendedBakery.mfix$getUnbakedMissingModel()) { + if(arg != ModelBakery.MISSING_MODEL_LOCATION && debugDynamicModelLoading) + ModernFix.LOGGER.warn("Model {} not present", arg); + wasMissingModel = true; + } + 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;")) + private BakedModel unifyMissingBakedModel(BakedModel model) { + if(wasMissingModel) { + // use a shared baked missing model + IExtendedModelBakery extendedBakery = (IExtendedModelBakery)this.field_40571; + BakedModel missing; + synchronized (this.field_40571) { + if(extendedBakery.getBakedMissingModel() == null) { + extendedBakery.setBakedMissingModel(model); + missing = model; + } else { + missing = extendedBakery.getBakedMissingModel(); + } + } + return missing; + } + return model; + } + + + + /** + * @author embeddedt + * @reason emulate old function, to allow injectors to work + */ + /* + @Overwrite + public BakedModel bake(ResourceLocation arg, ModelState arg2) { ModelBakery.BakedCacheKey key = new ModelBakery.BakedCacheKey(arg, arg2.getRotation(), arg2.isUvLocked()); BakedModel existing = this.field_40571.bakedCache.get(key); if (existing != null) { - cir.setReturnValue(existing); + return existing; } else { synchronized (this.field_40571) { if(debugDynamicModelLoading) ModernFix.LOGGER.info("Baking {}", arg); - UnbakedModel iunbakedmodel; - 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 = 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); - } - iunbakedmodel = this.field_40571.topLevelModels.getOrDefault(arg, extendedBakery.mfix$getUnbakedMissingModel()); - // avoid leaks - this.field_40571.topLevelModels.clear(); - } else - iunbakedmodel = this.getModel(arg); - if(iunbakedmodel == extendedBakery.mfix$getUnbakedMissingModel() && arg != ModelBakery.MISSING_MODEL_LOCATION && debugDynamicModelLoading) - ModernFix.LOGGER.warn("Model {} not present", arg); + UnbakedModel iunbakedmodel = this.getModel(arg); // TODO: make sure parent resolution doesn't re-run many times iunbakedmodel.resolveParents(this::getModel); BakedModel ibakedmodel = null; @@ -94,19 +139,21 @@ public abstract class ModelBakerImplMixin { } } if(ibakedmodel == null) { + // leave the original assignment in the same spot so wrapping injectors work + // this means two bakes might happen for missing models, but not much we can do + ibakedmodel = iunbakedmodel.bake((ModelBaker)this, this.modelTextureGetter, arg2, arg); + IExtendedModelBakery extendedBakery = (IExtendedModelBakery)this.field_40571; if(iunbakedmodel == extendedBakery.mfix$getUnbakedMissingModel()) { // use a shared baked missing model - if(extendedBakery.getBakedMissingModel() == null) { - extendedBakery.setBakedMissingModel(iunbakedmodel.bake((ModelBaker)this, this.modelTextureGetter, arg2, arg)); - ((DynamicBakedModelProvider)this.field_40571.getBakedTopLevelModels()).setMissingModel(extendedBakery.getBakedMissingModel()); - } + createBakedMissingModelIfNeeded(extendedBakery, iunbakedmodel, arg2, arg); ibakedmodel = extendedBakery.getBakedMissingModel(); - } else - ibakedmodel = iunbakedmodel.bake((ModelBaker)this, this.modelTextureGetter, arg2, arg); + } } this.field_40571.bakedCache.put(key, ibakedmodel); - cir.setReturnValue(ibakedmodel); + return ibakedmodel; } } } + + */ } 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 520fcb93..55781818 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 @@ -31,17 +31,14 @@ import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.TimeUnit; import java.util.function.BiConsumer; import java.util.function.BiFunction; -/* high priority so that our injectors are added before other mods' */ -@Mixin(value = ModelBakery.class, priority = 600) +/* low priority so that our injectors are added after other mods' */ +@Mixin(value = ModelBakery.class, priority = 1100) @ClientOnlyMixin public abstract class ModelBakeryMixin implements IExtendedModelBakery { @@ -172,10 +169,14 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery { private BiFunction textureGetter; - @Inject(method = "bakeModels", at = @At("HEAD"), cancellable = true) - private void skipBake(BiFunction getter, CallbackInfo ci) { + @Inject(method = "bakeModels", at = @At("HEAD")) + private void captureGetter(BiFunction getter, CallbackInfo ci) { textureGetter = getter; - ci.cancel(); + } + + @Redirect(method = "bakeModels", at = @At(value = "INVOKE", target = "Ljava/util/Map;keySet()Ljava/util/Set;")) + private Set skipBake(Map instance) { + return Collections.emptySet(); } /** diff --git a/gradle.properties b/gradle.properties index f9e843a4..ad721fbc 100644 --- a/gradle.properties +++ b/gradle.properties @@ -15,3 +15,5 @@ rhino_version=1902.2.2-build.268 fabric_loader_version=0.14.18 fabric_api_version=0.80.0+1.19.4 + +continuity_version=3.0.0-beta.2+1.19.3 \ No newline at end of file