diff --git a/build.gradle b/build.gradle index 9ba81565..3b9cdb2b 100644 --- a/build.gradle +++ b/build.gradle @@ -74,6 +74,7 @@ compileJava { classes += ['net/minecraft/class_5944': 'net/minecraft/class_5944'] method 'net/minecraft/class_5944', '(Lnet/minecraft/class_5912;Lnet/minecraft/util/Identifier;Lnet/minecraft/client/render/VertexFormat;)V', '', '' method 'net/minecraft/client/gui/screen/Screen', '(Lnet/minecraft/class_332;IIF)V', 'renderWithTooltip', 'method_47413' + classes += ['net/minecraft/client/render/model/Baker': 'net/minecraft/class_7775'] } } diff --git a/src/main/java/me/modmuss50/optifabric/compat/fabricmodelloadingapi/ModelLoadingMixinPlugin.java b/src/main/java/me/modmuss50/optifabric/compat/fabricmodelloadingapi/ModelLoadingMixinPlugin.java new file mode 100644 index 00000000..2f013987 --- /dev/null +++ b/src/main/java/me/modmuss50/optifabric/compat/fabricmodelloadingapi/ModelLoadingMixinPlugin.java @@ -0,0 +1,93 @@ +package me.modmuss50.optifabric.compat.fabricmodelloadingapi; + +import me.modmuss50.optifabric.compat.InterceptingMixinPlugin; +import me.modmuss50.optifabric.util.MixinUtils; +import me.modmuss50.optifabric.util.RemappingUtils; +import net.fabricmc.tinyremapper.IMappingProvider.Member; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.*; +import org.spongepowered.asm.mixin.extensibility.IMixinInfo; +import org.spongepowered.asm.mixin.transformer.ClassInfo; + +public class ModelLoadingMixinPlugin extends InterceptingMixinPlugin { + @Override + public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { + // not doing this will cause Mixin to have a stroke while trying to find where to put the fabric injectors + ClassInfo info = ClassInfo.forName(targetClassName); + MixinUtils.completeClassInfo(info, targetClass.methods); + String bakeDesc = "(Lnet/minecraft/class_2960;Lnet/minecraft/class_3665;)Lnet/minecraft/class_1087;";//(Identifier, ModelBakeSettings)BakedModel + String bake = RemappingUtils.getMethodName("class_7775", "method_45873", bakeDesc);//BakerImpl, bake + bakeDesc = RemappingUtils.mapMethodDescriptor(bakeDesc); + if ("ModelLoaderBakerImplMixin".equals(mixinInfo.getName())) { + for (MethodNode method : targetClass.methods) { + if (bake.equals(method.name) && bakeDesc.equals(method.desc)) { + //This is the @ModifyVariable + //target = "Lnet/minecraft/client/render/model/ModelLoader$BakerImpl;getOrLoadModel(Lnet/minecraft/util/Identifier;)Lnet/minecraft/client/render/model/UnbakedModel;" + Member mfMixinTarget = RemappingUtils.mapMethod("class_1088$class_7778", "method_45872", "(Lnet/minecraft/class_2960;)Lnet/minecraft/class_1100;"); + LabelNode fakeStart = new LabelNode(); + LabelNode skip = new LabelNode(); + InsnList extraFirst = new InsnList(); + + /* + The following line doesn't work because why would it work (it does in OriginMixinPlugin) + so I have to resort to using postApply and remove this trash code + */ +// extra.add(new JumpInsnNode(Opcodes.GOTO, skip)); + extraFirst.add(fakeStart); + extraFirst.add(new InsnNode(Opcodes.ACONST_NULL)); + extraFirst.add(new InsnNode(Opcodes.ACONST_NULL)); + extraFirst.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, mfMixinTarget.owner, mfMixinTarget.name, mfMixinTarget.desc)); + extraFirst.add(new VarInsnNode(Opcodes.ASTORE, 3)); + extraFirst.add(skip); + + method.localVariables.add(new LocalVariableNode("fakeUnbakedModel", "L" + RemappingUtils.getClassName("class_1087") + ";", null, fakeStart, skip, 3)); + method.instructions.insertBefore(method.instructions.getFirst(), extraFirst); + method.maxLocals += 1; + + //This part takes care of the two @Redirect + //target = "Lnet/minecraft/client/render/model/UnbakedModel;bake(Lnet/minecraft/client/render/model/Baker;Ljava/util/function/Function;Lnet/minecraft/client/render/model/ModelBakeSettings;Lnet/minecraft/util/Identifier;)Lnet/minecraft/client/render/model/BakedModel;" + Member redirectMixinTarget1 = RemappingUtils.mapMethod("class_1100", "method_4753", "(Lnet/minecraft/class_7775;Ljava/util/function/Function;Lnet/minecraft/class_3665;Lnet/minecraft/class_2960;)Lnet/minecraft/class_1087;"); + //target = "Lnet/minecraft/client/render/model/json/JsonUnbakedModel;bake(Lnet/minecraft/client/render/model/Baker;Lnet/minecraft/client/render/model/json/JsonUnbakedModel;Ljava/util/function/Function;Lnet/minecraft/client/render/model/ModelBakeSettings;Lnet/minecraft/util/Identifier;Z)Lnet/minecraft/client/render/model/BakedModel;" + Member redirectMixinTarget2 = RemappingUtils.mapMethod("class_793", "method_3446", "(Lnet/minecraft/class_7775;Lnet/minecraft/class_793;Ljava/util/function/Function;Lnet/minecraft/class_3665;Lnet/minecraft/class_2960;Z)Lnet/minecraft/class_1087;"); + LabelNode skipLast = new LabelNode(); + InsnList extraLast = new InsnList(); + // this works because funny (and because no local variable is involved) + extraLast.add(new JumpInsnNode(Opcodes.GOTO, skipLast)); + extraLast.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE, redirectMixinTarget1.owner, redirectMixinTarget1.name, redirectMixinTarget1.desc)); + extraLast.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE, redirectMixinTarget2.owner, redirectMixinTarget2.name, redirectMixinTarget2.desc)); + extraLast.add(skipLast); + method.instructions.insertBefore(method.instructions.getLast(), extraLast); + break; + } + } + } + + super.preApply(targetClassName, targetClass, mixinClassName, mixinInfo); + } + + @Override + public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { + String bakeDesc = "(Lnet/minecraft/class_2960;Lnet/minecraft/class_3665;)Lnet/minecraft/class_1087;"; + String bake = RemappingUtils.getMethodName("class_7775", "method_45873", bakeDesc); + bakeDesc = RemappingUtils.mapMethodDescriptor(bakeDesc); + + if ("ModelLoaderBakerImplMixin".equals(mixinInfo.getName())) { + out: for (MethodNode method : targetClass.methods) { + if (bake.equals(method.name) && bakeDesc.equals(method.desc)) { + LocalVariableNode fakeUnbakedModel = method.localVariables.get(3); + method.localVariables.remove(fakeUnbakedModel); + method.maxLocals -= 1; + // remove trash + for (AbstractInsnNode insn : method.instructions) { + method.instructions.remove(insn); + System.out.println(insn); + if (fakeUnbakedModel.end.equals(insn)) { + break out; + } + } + } + } + } + super.postApply(targetClassName, targetClass, mixinClassName, mixinInfo); + } +} diff --git a/src/main/java/me/modmuss50/optifabric/compat/fabricmodelloadingapi/mixin/ModelLoaderBakerImplMixin.java b/src/main/java/me/modmuss50/optifabric/compat/fabricmodelloadingapi/mixin/ModelLoaderBakerImplMixin.java new file mode 100644 index 00000000..b0cdad6e --- /dev/null +++ b/src/main/java/me/modmuss50/optifabric/compat/fabricmodelloadingapi/mixin/ModelLoaderBakerImplMixin.java @@ -0,0 +1,48 @@ +package me.modmuss50.optifabric.compat.fabricmodelloadingapi.mixin; + +import me.modmuss50.optifabric.compat.InterceptingMixin; +import me.modmuss50.optifabric.compat.Shim; +import net.minecraft.class_7775; +import net.minecraft.client.render.model.BakedModel; +import net.minecraft.client.render.model.ModelBakeSettings; +import net.minecraft.client.render.model.UnbakedModel; +import net.minecraft.client.render.model.json.JsonUnbakedModel; +import net.minecraft.client.texture.Sprite; +import net.minecraft.client.util.SpriteIdentifier; +import net.minecraft.util.Identifier; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyVariable; +import org.spongepowered.asm.mixin.injection.Redirect; + +import java.util.function.Function; + +@Mixin(targets = "net/minecraft/class_1088$class_7778") +@InterceptingMixin("net/fabricmc/fabric/mixin/client/model/loading/ModelLoaderBakerImplMixin") +abstract class ModelLoaderBakerImplMixin { + @Shim private native UnbakedModel invokeModifyBeforeBake(UnbakedModel model, Identifier id, ModelBakeSettings settings); + + @ModifyVariable(method = "bake", remap = false, + at = @At(value = "INVOKE_ASSIGN", target = "Lnet/minecraft/class_1088$class_7778;method_45872(Lnet/minecraft/util/Identifier;)Lnet/minecraft/client/render/model/UnbakedModel;", remap = true)) + private UnbakedModel invokeModifyBeforeBake(UnbakedModel model, Identifier id, ModelBakeSettings settings, Function sprites) { + return invokeModifyBeforeBake(model, id, settings); + } + + @Shim + private native BakedModel invokeModifyAfterBake(UnbakedModel unbakedModel, class_7775 baker, Function textureGetter, ModelBakeSettings settings, Identifier id); + + @Redirect(method = "bake", remap = false, + at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/model/UnbakedModel;method_4753(Lnet/minecraft/client/render/model/Baker;Ljava/util/function/Function;Lnet/minecraft/client/render/model/ModelBakeSettings;Lnet/minecraft/util/Identifier;)Lnet/minecraft/client/render/model/BakedModel;", remap = true)) + private BakedModel optifabric_invokeModifyAfterBake(UnbakedModel unbakedModel, class_7775 baker, Function textureGetter, ModelBakeSettings settings, Identifier id) { + return invokeModifyAfterBake(unbakedModel, baker, textureGetter, settings, id); + } + + + @Shim private native BakedModel invokeModifyAfterBake(JsonUnbakedModel unbakedModel, class_7775 baker, JsonUnbakedModel parent, Function textureGetter, ModelBakeSettings settings, Identifier id, boolean hasDepth); + + @Redirect(method = "bake", remap = false, + at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/model/json/JsonUnbakedModel;method_3446(Lnet/minecraft/client/render/model/Baker;Lnet/minecraft/client/render/model/json/JsonUnbakedModel;Ljava/util/function/Function;Lnet/minecraft/client/render/model/ModelBakeSettings;Lnet/minecraft/util/Identifier;Z)Lnet/minecraft/client/render/model/BakedModel;", remap = true)) + private BakedModel optifabric_invokeModifyAfterBake(JsonUnbakedModel unbakedModel, class_7775 baker, JsonUnbakedModel parent, Function textureGetter, ModelBakeSettings settings, Identifier id, boolean hasDepth) { + return invokeModifyAfterBake(unbakedModel, baker, parent, textureGetter, settings, id, hasDepth); + } +} diff --git a/src/main/java/me/modmuss50/optifabric/mod/OptifabricSetup.java b/src/main/java/me/modmuss50/optifabric/mod/OptifabricSetup.java index 0a35c9c6..32886dcb 100644 --- a/src/main/java/me/modmuss50/optifabric/mod/OptifabricSetup.java +++ b/src/main/java/me/modmuss50/optifabric/mod/OptifabricSetup.java @@ -234,6 +234,10 @@ protected boolean isPresent() { Mixins.addConfiguration("optifabric.compat.fabric-lifecycle-events.new-mixins.json"); } + if (isPresent("fabric-model-loading-api-v1")) { + Mixins.addConfiguration("optifabric.compat.fabric-model-loading-api.mixins.json"); + } + Mixins.addConfiguration("optifabric.optifine.mixins.json"); if (OptifabricSetup.isPresent("minecraft", "<=1.19.2")) { Mixins.addConfiguration("optifabric.optifine.old-mixins.json"); diff --git a/src/main/java/me/modmuss50/optifabric/mod/OptifineSetup.java b/src/main/java/me/modmuss50/optifabric/mod/OptifineSetup.java index 619a98ac..7d04ab4b 100644 --- a/src/main/java/me/modmuss50/optifabric/mod/OptifineSetup.java +++ b/src/main/java/me/modmuss50/optifabric/mod/OptifineSetup.java @@ -272,6 +272,12 @@ private static IMappingProvider createMappings(String from, String to, IMappingP ClassDef builtChunk = nameToClass.get("net/minecraft/class_846$class_851"); extraFields.put(new Member(rebuildTask.getName(from), "this$1", 'L' + builtChunk.getName(from) + ';'), "field_20839"); + ClassDef bakerImpl = nameToClass.get("net/minecraft/class_1088$class_7778"); + if (bakerImpl != null) {//Only present in 1.19.3+ + ClassDef modelLoader = nameToClass.get("net/minecraft/class_1088"); + extraFields.put(new Member(bakerImpl.getName(from), "this$0", 'L' + modelLoader.getName(from) + ';'), "field_40571"); + } + ClassDef particleManager = nameToClass.get("net/minecraft/class_702"); particleManager.getFields().stream().filter(field -> "field_3835".equals(field.getName("intermediary"))).forEach(field -> { extraFields.put(new Member(particleManager.getName(from), field.getName(from), "Ljava/util/Map;"), field.getName(to)); diff --git a/src/main/resources/optifabric.compat.fabric-model-loading-api.mixins.json b/src/main/resources/optifabric.compat.fabric-model-loading-api.mixins.json new file mode 100644 index 00000000..23c9fee7 --- /dev/null +++ b/src/main/resources/optifabric.compat.fabric-model-loading-api.mixins.json @@ -0,0 +1,8 @@ +{ + "parent": "optifabric.mixins.json", + "package": "me.modmuss50.optifabric.compat.fabricmodelloadingapi.mixin", + "plugin": "me.modmuss50.optifabric.compat.fabricmodelloadingapi.ModelLoadingMixinPlugin", + "mixins": [ + "ModelLoaderBakerImplMixin" + ] +} \ No newline at end of file diff --git a/src/shim/java/net/minecraft/class_7775.java b/src/shim/java/net/minecraft/class_7775.java new file mode 100644 index 00000000..2c1012b2 --- /dev/null +++ b/src/shim/java/net/minecraft/class_7775.java @@ -0,0 +1,4 @@ +package net.minecraft; + +public interface class_7775 { +}