aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLinnea Gräf <nea@nea.moe>2024-08-10 01:59:34 +0200
committerLinnea Gräf <nea@nea.moe>2024-08-12 21:02:44 +0200
commit3c7e6b6177de6ef3cff8a46bb1726466a299cdde (patch)
tree2ebc75e705b5422a68d5d7f04d88e3d8934cf02d /src
parent1606188d9ad65c66e9d873497ea3271dbdadaf77 (diff)
downloadfirmament-3c7e6b6177de6ef3cff8a46bb1726466a299cdde.tar.gz
firmament-3c7e6b6177de6ef3cff8a46bb1726466a299cdde.tar.bz2
firmament-3c7e6b6177de6ef3cff8a46bb1726466a299cdde.zip
Add indigo support to custom block textures
Diffstat (limited to 'src')
-rw-r--r--src/main/java/moe/nea/firmament/init/ClientPlayerRiser.java13
-rw-r--r--src/main/java/moe/nea/firmament/init/EarlyRiser.java1
-rw-r--r--src/main/java/moe/nea/firmament/init/HandledScreenRiser.java8
-rw-r--r--src/main/java/moe/nea/firmament/init/Intermediary.java63
-rw-r--r--src/main/java/moe/nea/firmament/init/IntermediaryName.java21
-rw-r--r--src/main/java/moe/nea/firmament/init/SectionBuilderRiser.java116
-rw-r--r--src/main/kotlin/moe/nea/firmament/Firmament.kt3
-rw-r--r--src/main/kotlin/moe/nea/firmament/features/texturepack/CustomBlockTextures.kt9
-rw-r--r--src/main/resources/firmament.accesswidener2
9 files changed, 227 insertions, 9 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);
+ }
+ }
+}
diff --git a/src/main/kotlin/moe/nea/firmament/Firmament.kt b/src/main/kotlin/moe/nea/firmament/Firmament.kt
index 4b742e8..400dcf2 100644
--- a/src/main/kotlin/moe/nea/firmament/Firmament.kt
+++ b/src/main/kotlin/moe/nea/firmament/Firmament.kt
@@ -33,6 +33,7 @@ import kotlinx.coroutines.plus
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.decodeFromStream
import kotlin.coroutines.EmptyCoroutineContext
+import net.minecraft.client.render.chunk.SectionBuilder
import net.minecraft.command.CommandRegistryAccess
import net.minecraft.util.Identifier
import moe.nea.firmament.commands.registerFirmamentCommand
@@ -112,6 +113,8 @@ object Firmament {
ClientTickEvents.END_CLIENT_TICK.register(ClientTickEvents.EndTick { instance ->
TickEvent.publish(TickEvent(tick++))
})
+ // TODO: remove me
+ Class.forName(SectionBuilder::class.java.name)
IDataHolder.registerEvents()
RepoManager.initialize()
SBData.init()
diff --git a/src/main/kotlin/moe/nea/firmament/features/texturepack/CustomBlockTextures.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/CustomBlockTextures.kt
index 2289be2..c869ba4 100644
--- a/src/main/kotlin/moe/nea/firmament/features/texturepack/CustomBlockTextures.kt
+++ b/src/main/kotlin/moe/nea/firmament/features/texturepack/CustomBlockTextures.kt
@@ -157,7 +157,10 @@ object CustomBlockTextures {
currentIslandReplacements = replacements
if (lastReplacements != replacements) {
MC.nextTick {
- MC.worldRenderer.reload()
+ MC.worldRenderer.chunks?.chunks?.forEach {
+ // false schedules rebuilds outside a 27 block radius to happen async
+ it.scheduleRebuild(false)
+ }
}
}
}
@@ -259,6 +262,10 @@ object CustomBlockTextures {
return BakedReplacements(map.mapValues { LocationReplacements(it.value) })
}
+ @JvmStatic
+ fun patchIndigo(orig: BakedModel, pos: BlockPos, state: BlockState): BakedModel {
+ return getReplacementModel(state, pos) ?: orig
+ }
@Subscribe
fun onStart(event: FinalizeResourceManagerEvent) {
diff --git a/src/main/resources/firmament.accesswidener b/src/main/resources/firmament.accesswidener
index b69b99d..c69725f 100644
--- a/src/main/resources/firmament.accesswidener
+++ b/src/main/resources/firmament.accesswidener
@@ -20,4 +20,4 @@ mutable field net/minecraft/screen/slot/Slot x I
mutable field net/minecraft/screen/slot/Slot y I
accessible field net/minecraft/entity/player/PlayerEntity PLAYER_MODEL_PARTS Lnet/minecraft/entity/data/TrackedData;
-
+accessible field net/minecraft/client/render/WorldRenderer chunks Lnet/minecraft/client/render/BuiltChunkStorage;