diff options
author | Linnea Gräf <nea@nea.moe> | 2024-08-10 01:59:34 +0200 |
---|---|---|
committer | Linnea Gräf <nea@nea.moe> | 2024-08-12 21:02:44 +0200 |
commit | 3c7e6b6177de6ef3cff8a46bb1726466a299cdde (patch) | |
tree | 2ebc75e705b5422a68d5d7f04d88e3d8934cf02d /src/main/java | |
parent | 1606188d9ad65c66e9d873497ea3271dbdadaf77 (diff) | |
download | Firmament-3c7e6b6177de6ef3cff8a46bb1726466a299cdde.tar.gz Firmament-3c7e6b6177de6ef3cff8a46bb1726466a299cdde.tar.bz2 Firmament-3c7e6b6177de6ef3cff8a46bb1726466a299cdde.zip |
Add indigo support to custom block textures
Diffstat (limited to 'src/main/java')
6 files changed, 215 insertions, 7 deletions
diff --git a/src/main/java/moe/nea/firmament/init/ClientPlayerRiser.java b/src/main/java/moe/nea/firmament/init/ClientPlayerRiser.java index 18dfa17..0a5bedd 100644 --- a/src/main/java/moe/nea/firmament/init/ClientPlayerRiser.java +++ b/src/main/java/moe/nea/firmament/init/ClientPlayerRiser.java @@ -1,4 +1,3 @@ - package moe.nea.firmament.init; import me.shedaniel.mm.api.ClassTinkerers; @@ -14,11 +13,15 @@ import java.lang.reflect.Modifier; import java.util.Objects; public class ClientPlayerRiser extends RiserUtils { - String PlayerEntity = remapper.mapClassName("intermediary", "net.minecraft.class_1657"); - String World = remapper.mapClassName("intermediary", "net.minecraft.class_1937"); + @IntermediaryName(net.minecraft.entity.player.PlayerEntity.class) + String PlayerEntity; + @IntermediaryName(net.minecraft.world.World.class) + String World; String GameProfile = "com.mojang.authlib.GameProfile"; - String BlockPos = remapper.mapClassName("intermediary", "net.minecraft.class_2338"); - String AbstractClientPlayerEntity = remapper.mapClassName("intermediary", "net.minecraft.class_742"); + @IntermediaryName(net.minecraft.util.math.BlockPos.class) + String BlockPos; + @IntermediaryName(net.minecraft.client.network.AbstractClientPlayerEntity.class) + String AbstractClientPlayerEntity; String GuiPlayer = "moe.nea.firmament.gui.entity.GuiPlayer"; // World world, BlockPos pos, float yaw, GameProfile gameProfile Type constructorDescriptor = Type.getMethodType(Type.VOID_TYPE, getTypeForClassName(World), getTypeForClassName(BlockPos), Type.FLOAT_TYPE, getTypeForClassName(GameProfile)); diff --git a/src/main/java/moe/nea/firmament/init/EarlyRiser.java b/src/main/java/moe/nea/firmament/init/EarlyRiser.java index 77c044d..5eab563 100644 --- a/src/main/java/moe/nea/firmament/init/EarlyRiser.java +++ b/src/main/java/moe/nea/firmament/init/EarlyRiser.java @@ -6,5 +6,6 @@ public class EarlyRiser implements Runnable { public void run() { new ClientPlayerRiser().addTinkerers(); new HandledScreenRiser().addTinkerers(); + new SectionBuilderRiser().addTinkerers(); } } diff --git a/src/main/java/moe/nea/firmament/init/HandledScreenRiser.java b/src/main/java/moe/nea/firmament/init/HandledScreenRiser.java index 0215523..baa0501 100644 --- a/src/main/java/moe/nea/firmament/init/HandledScreenRiser.java +++ b/src/main/java/moe/nea/firmament/init/HandledScreenRiser.java @@ -2,6 +2,8 @@ package moe.nea.firmament.init; import me.shedaniel.mm.api.ClassTinkerers; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.screen.ingame.HandledScreen; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.ClassNode; @@ -17,8 +19,10 @@ import org.objectweb.asm.tree.VarInsnNode; import java.lang.reflect.Modifier; public class HandledScreenRiser extends RiserUtils { - String Screen = remapper.mapClassName("intermediary", "net.minecraft.class_437"); - String HandledScreen = remapper.mapClassName("intermediary", "net.minecraft.class_465"); + @IntermediaryName(net.minecraft.client.gui.screen.Screen.class) + String Screen; + @IntermediaryName(net.minecraft.client.gui.screen.ingame.HandledScreen.class) + String HandledScreen; Type mouseScrolledDesc = Type.getMethodType(Type.BOOLEAN_TYPE, Type.DOUBLE_TYPE, Type.DOUBLE_TYPE, Type.DOUBLE_TYPE, Type.DOUBLE_TYPE); String mouseScrolled = remapper.mapMethodName("intermediary", "net.minecraft.class_364", "method_25401", mouseScrolledDesc.getDescriptor()); diff --git a/src/main/java/moe/nea/firmament/init/Intermediary.java b/src/main/java/moe/nea/firmament/init/Intermediary.java new file mode 100644 index 0000000..61494d7 --- /dev/null +++ b/src/main/java/moe/nea/firmament/init/Intermediary.java @@ -0,0 +1,63 @@ +package moe.nea.firmament.init; + +import net.fabricmc.loader.api.FabricLoader; +import net.fabricmc.loader.api.MappingResolver; +import org.objectweb.asm.Type; + +import java.util.List; + +public class Intermediary { + private static final MappingResolver RESOLVER = FabricLoader.getInstance().getMappingResolver(); + + static String methodName(Object object) { + throw new AssertionError("Cannot be called at runtime"); + } + + static <T> String className() { + throw new AssertionError("Cannot be called at runtime"); + } + + static String id(String source) { + return source; + } + +// public record Class( +// Type intermediaryClass +// ) { +// public Class(String intermediaryClass) { +// this(Type.getObjectType(intermediaryClass.replace('.', '/'))); +// } +// +// public String getMappedName() { +// return RESOLVER.mapClassName("intermediary", intermediaryClass.getInternalName() +// .replace('/', '.')); +// } +// } +// +// public record Method( +// Type intermediaryClassName, +// String intermediaryMethodName, +// Type intermediaryReturnType, +// List<Type> intermediaryArgumentTypes +// ) { +// public Method( +// String intermediaryClassName, +// String intermediaryMethodName, +// String intermediaryReturnType, +// String... intermediaryArgumentTypes +// ) { +// this(intermediaryClassName, intermediaryMethodName, intermediaryReturnType, List.of(intermediaryArgumentTypes)); +// } +// +// public String getMappedMethodName() { +// return RESOLVER.mapMethodName("intermediary", +// intermediaryClassName.getInternalName().replace('/', '.')); +// } +// +// public Type getIntermediaryDescriptor() { +// return Type.getMethodType(intermediaryReturnType, intermediaryArgumentTypes.toArray(Type[]::new)); +// } +// +// +// } +} diff --git a/src/main/java/moe/nea/firmament/init/IntermediaryName.java b/src/main/java/moe/nea/firmament/init/IntermediaryName.java new file mode 100644 index 0000000..a22ad0f --- /dev/null +++ b/src/main/java/moe/nea/firmament/init/IntermediaryName.java @@ -0,0 +1,21 @@ +package moe.nea.firmament.init; + +import net.fabricmc.loader.api.MappingResolver; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Injects the intermediary name of the given field into this field by replacing its initializer with a call to + * {@link MappingResolver#mapClassName(String, String)} + */ +@Retention(RetentionPolicy.SOURCE) +@Target(ElementType.FIELD) +public @interface IntermediaryName { + // String method() default ""; +// +// String field() default ""; + Class<?> value(); +} diff --git a/src/main/java/moe/nea/firmament/init/SectionBuilderRiser.java b/src/main/java/moe/nea/firmament/init/SectionBuilderRiser.java new file mode 100644 index 0000000..2be11a6 --- /dev/null +++ b/src/main/java/moe/nea/firmament/init/SectionBuilderRiser.java @@ -0,0 +1,116 @@ +package moe.nea.firmament.init; + +import me.shedaniel.mm.api.ClassTinkerers; +import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.block.BlockState; +import net.minecraft.client.render.block.BlockModels; +import net.minecraft.client.render.block.BlockRenderManager; +import net.minecraft.client.render.chunk.SectionBuilder; +import net.minecraft.client.render.model.BakedModel; +import net.minecraft.util.math.BlockPos; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.LocalVariableNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.VarInsnNode; + +public class SectionBuilderRiser extends RiserUtils { + + @IntermediaryName(SectionBuilder.class) + String SectionBuilder; + @IntermediaryName(BlockPos.class) + String BlockPos; + @IntermediaryName(BlockRenderManager.class) + String BlockRenderManager; + @IntermediaryName(BlockState.class) + String BlockState; + @IntermediaryName(BakedModel.class) + String BakedModel; + String CustomBlockTextures = "moe.nea.firmament.features.texturepack.CustomBlockTextures"; + + Type getModelDesc = Type.getMethodType( + getTypeForClassName(BlockRenderManager), + getTypeForClassName(BlockState) + ); + String getModel = remapper.mapMethodName( + "intermediary", + Intermediary.<BlockRenderManager>className(), + Intermediary.methodName(net.minecraft.client.render.block.BlockRenderManager::getModel), + Type.getMethodDescriptor( + getTypeForClassName(Intermediary.<BakedModel>className()), + getTypeForClassName(Intermediary.<BlockState>className()) + ) + ); + + @Override + public void addTinkerers() { + if (FabricLoader.getInstance().isModLoaded("fabric-renderer-indigo")) + ClassTinkerers.addTransformation(SectionBuilder, this::handle, true); + } + + private void handle(ClassNode classNode) { + for (MethodNode method : classNode.methods) { + if (method.name.endsWith("$fabric-renderer-indigo$hookChunkBuildTessellate") && + method.name.startsWith("redirect$")) { + handleIndigo(method); + return; + } + } + new RuntimeException("Could not inject tesselation hook despite fabric renderer indigo being loaded").printStackTrace(); + } + + private void handleIndigo(MethodNode method) { + LocalVariableNode blockPosVar = null, blockStateVar = null; + for (LocalVariableNode localVariable : method.localVariables) { + if (Type.getType(localVariable.desc).equals(getTypeForClassName(BlockPos))) { + blockPosVar = localVariable; + } + if (Type.getType(localVariable.desc).equals(getTypeForClassName(BlockState))) { + blockStateVar = localVariable; + } + } + if (blockPosVar == null || blockStateVar == null) { + System.err.println("Firmament could inject into indigo: missing either block pos or blockstate"); + return; + } + for (AbstractInsnNode instruction : method.instructions) { + if (instruction.getOpcode() != Opcodes.INVOKEVIRTUAL) continue; + var methodInsn = (MethodInsnNode) instruction; + if (!(methodInsn.name.equals(getModel) && Type.getObjectType(methodInsn.owner).equals(getTypeForClassName(BlockRenderManager)))) + continue; + method.instructions.insertBefore( + methodInsn, + new MethodInsnNode( + Opcodes.INVOKESTATIC, + getTypeForClassName(CustomBlockTextures).getInternalName(), + "enterFallbackCall", + Type.getMethodDescriptor(Type.VOID_TYPE) + )); + + var insnList = new InsnList(); + insnList.add(new MethodInsnNode( + Opcodes.INVOKESTATIC, + getTypeForClassName(CustomBlockTextures).getInternalName(), + "exitFallbackCall", + Type.getMethodDescriptor(Type.VOID_TYPE) + )); + insnList.add(new VarInsnNode(Opcodes.ALOAD, blockPosVar.index)); + insnList.add(new VarInsnNode(Opcodes.ALOAD, blockStateVar.index)); + insnList.add(new MethodInsnNode( + Opcodes.INVOKESTATIC, + getTypeForClassName(CustomBlockTextures).getInternalName(), + "patchIndigo", + Type.getMethodDescriptor(getTypeForClassName(BakedModel), + getTypeForClassName(BakedModel), + getTypeForClassName(BlockPos), + getTypeForClassName(BlockState)), + false + )); + method.instructions.insert(methodInsn, insnList); + } + } +} |