Use a RFB plugin for GLSM transforms when available (#329)

This commit is contained in:
Raven Szewczyk authored and GitHub committed 2024-02-25 12:58:19 -08:00
1 parent 6d28df74a6
commit c996e5e58c
8 files changed
+182 -30

No files matched your search

+7
View File
@@ -14,6 +14,13 @@ tasks.test {
jvmArgs("-Djava.library.path=${tasks.extractNatives2.get().destinationFolder.asFile.get().path}")
}
tasks.processResources {
inputs.property("version", project.version.toString())
filesMatching("META-INF/rfb-plugin/*") {
expand("version" to project.version.toString())
}
}
tasks.register<Copy>("copyDependencies") {
group = "Angelica"
description = "Collect dependencies into the testDependencies folder"
+4 -2
View File
@@ -51,7 +51,9 @@ configurations {
dependencies {
compileOnly("com.github.GTNewHorizons:Hodgepodge:2.4.4")
compileOnly("org.projectlombok:lombok:1.18.22") {transitive = false }
compileOnly("com.gtnewhorizons.retrofuturabootstrap:RetroFuturaBootstrap:0.4.0") { transitive = false }
compileOnly("org.projectlombok:lombok:1.18.22") { transitive = false }
annotationProcessor("org.projectlombok:lombok:1.18.22")
// Iris Shaders
@@ -71,7 +73,7 @@ dependencies {
// Notfine Deps
compileOnly("thaumcraft:Thaumcraft:1.7.10-4.2.3.5:dev")
runtimeOnlyNonPublishable("com.github.GTNewHorizons:Baubles:1.0.1.16:dev")
compileOnly("com.github.GTNewHorizons:twilightforest:2.5.1:dev") {transitive = false }
compileOnly("com.github.GTNewHorizons:twilightforest:2.5.1:dev") { transitive = false }
compileOnly(rfg.deobf('curse.maven:witchery-69673:2234410'))
compileOnly("com.falsepattern:chunkapi-mc1.7.10:0.5.0:api")
@@ -21,13 +21,13 @@ public class MixinCompatHackTweaker implements ITweaker {
@Override
public void acceptOptions(List<String> args, File gameDir, File assetsDir, String profile) {
verifyDependencies();
if(DISABLE_OPTIFINE_AND_FASTCRAFT) {
LOGGER.info("Disabling Optifine and Fastcraft (if present)");
disableOptifineAndFastcraft();
}
}
private void verifyDependencies() {
if(MixinCompatHackTweaker.class.getResource("/it/unimi/dsi/fastutil/ints/Int2ObjectMap.class") == null) {
throw new RuntimeException("Missing dependency: Angelica requires GTNHLib 0.2.1 or newer! Download: https://modrinth.com/mod/gtnhlib");
@@ -82,8 +82,12 @@ public class MixinCompatHackTweaker implements ITweaker {
@Override
public String[] getLaunchArguments() {
if (FMLLaunchHandler.side().isClient()) {
// Run after Mixins, but before LWJGl3ify
Launch.classLoader.registerTransformer(RedirectorTransformer.class.getName());
final boolean rfbLoaded = Launch.blackboard.getOrDefault("angelica.rfbPluginLoaded", Boolean.FALSE) == Boolean.TRUE;
if (!rfbLoaded) {
// Run after Mixins, but before LWJGl3ify
Launch.classLoader.registerTransformer(RedirectorTransformer.class.getName());
}
if(AngelicaConfig.enableSodium) {
Launch.classLoader.registerTransformer(BlockTransformer.class.getName());
}
@@ -0,0 +1,28 @@
package com.gtnewhorizons.angelica.loading.rfb;
import com.gtnewhorizons.retrofuturabootstrap.api.PluginContext;
import com.gtnewhorizons.retrofuturabootstrap.api.RetroFuturaBootstrap;
import com.gtnewhorizons.retrofuturabootstrap.api.RfbClassTransformer;
import com.gtnewhorizons.retrofuturabootstrap.api.RfbPlugin;
import net.minecraft.launchwrapper.Launch;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class AngelicaRfbPlugin implements RfbPlugin {
@Override
public void onConstruction(@NotNull PluginContext ctx) {
Launch.blackboard.put("angelica.rfbPluginLoaded", Boolean.TRUE);
}
@Override
public @NotNull RfbClassTransformer @Nullable [] makeTransformers() {
final boolean isServer = (null == RetroFuturaBootstrap.API.launchClassLoader().findClassMetadata("net.minecraft.client.main.Main"));
if (isServer) {
return null;
}
return new RfbClassTransformer[] {
new RedirectorTransformerWrapper()
};
}
}
@@ -0,0 +1,61 @@
package com.gtnewhorizons.angelica.loading.rfb;
import com.gtnewhorizons.angelica.transform.RedirectorTransformer;
import com.gtnewhorizons.retrofuturabootstrap.api.ClassNodeHandle;
import com.gtnewhorizons.retrofuturabootstrap.api.ExtensibleClassLoader;
import com.gtnewhorizons.retrofuturabootstrap.api.RfbClassTransformer;
import org.intellij.lang.annotations.Pattern;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.jar.Manifest;
/** RFB wrapper for {@link com.gtnewhorizons.angelica.transform.RedirectorTransformer} */
public class RedirectorTransformerWrapper implements RfbClassTransformer {
public final RedirectorTransformer inner = new RedirectorTransformer();
@Pattern("[a-z0-9-]+")
@Override
public @NotNull String id() {
return "redirector";
}
@Override
public @NotNull String @Nullable [] sortAfter() {
return new String[] {"*", "mixin:mixin"};
}
@Override
public @NotNull String @Nullable [] sortBefore() {
return new String[] {"lwjgl3ify:redirect"};
}
@Override
public @NotNull String @Nullable [] additionalExclusions() {
return RedirectorTransformer.getTransformerExclusions().toArray(new String[0]);
}
@Override
public boolean shouldTransformClass(@NotNull ExtensibleClassLoader classLoader,
@NotNull RfbClassTransformer.Context context, @Nullable Manifest manifest, @NotNull String className,
@NotNull ClassNodeHandle classNode) {
if (!classNode.isPresent()) {
return false;
}
if (!classNode.isOriginal()) {
// If a class is already a transformed ClassNode, conservatively continue processing.
return true;
}
return inner.shouldRfbTransform(classNode.getOriginalBytes());
}
@Override
public void transformClass(@NotNull ExtensibleClassLoader classLoader, @NotNull RfbClassTransformer.Context context,
@Nullable Manifest manifest, @NotNull String className, @NotNull ClassNodeHandle classNode) {
final boolean changed = inner.transformClassNode(className, classNode.getNode());
if (changed) {
classNode.computeMaxs();
}
}
}
@@ -3,9 +3,9 @@ package com.gtnewhorizons.angelica.transform;
import com.google.common.collect.ImmutableList;
import net.minecraft.launchwrapper.IClassTransformer;
import org.apache.commons.lang3.tuple.Pair;
import org.spongepowered.asm.lib.ClassReader;
import org.spongepowered.asm.lib.ClassWriter;
import org.spongepowered.asm.lib.tree.ClassNode;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.tree.ClassNode;
import java.util.List;
@@ -6,24 +6,27 @@ import com.gtnewhorizons.angelica.loading.AngelicaTweaker;
import net.coderbot.iris.IrisLogging;
import net.minecraft.launchwrapper.IClassTransformer;
import net.minecraft.launchwrapper.Launch;
import net.minecraft.launchwrapper.LaunchClassLoader;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.spongepowered.asm.lib.ClassReader;
import org.spongepowered.asm.lib.ClassWriter;
import org.spongepowered.asm.lib.Opcodes;
import org.spongepowered.asm.lib.tree.AbstractInsnNode;
import org.spongepowered.asm.lib.tree.ClassNode;
import org.spongepowered.asm.lib.tree.FieldInsnNode;
import org.spongepowered.asm.lib.tree.InsnList;
import org.spongepowered.asm.lib.tree.InsnNode;
import org.spongepowered.asm.lib.tree.IntInsnNode;
import org.spongepowered.asm.lib.tree.LdcInsnNode;
import org.spongepowered.asm.lib.tree.MethodInsnNode;
import org.spongepowered.asm.lib.tree.MethodNode;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.FieldInsnNode;
import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.InsnNode;
import org.objectweb.asm.tree.IntInsnNode;
import org.objectweb.asm.tree.LdcInsnNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.nio.file.Files;
import java.util.Arrays;
import java.util.Collections;
@@ -90,6 +93,9 @@ public class RedirectorTransformer implements IClassTransformer {
// Block owners we *shouldn't* redirect because they shadow one of our fields
private static final Set<String> blockOwnerExclusions = Collections.newSetFromMap(new ConcurrentHashMap<>());
// Needed because the config is loaded in LaunchClassLoader, but we need to access it in the parent system loader.
private static final MethodHandle angelicaConfigSodiumEnabledGetter;
static {
glCapRedirects.put(org.lwjgl.opengl.GL11.GL_ALPHA_TEST, "AlphaTest");
glCapRedirects.put(org.lwjgl.opengl.GL11.GL_BLEND, "Blend");
@@ -203,6 +209,22 @@ public class RedirectorTransformer implements IClassTransformer {
methodRedirects.put(EXTBlendFunc, RedirectMap.newMap().add("glBlendFuncSeparateEXT", "tryBlendFuncSeparate"));
methodRedirects.put(ARBMultiTexture, RedirectMap.newMap().add("glActiveTextureARB"));
methodRedirects.put(Project, RedirectMap.newMap().add("gluPerspective"));
try {
final Class<?> angelicaConfig = Class.forName("com.gtnewhorizons.angelica.config.AngelicaConfig", true, Launch.classLoader);
final MethodHandle sodiumGetter = MethodHandles.lookup().findStaticGetter(angelicaConfig, "enableSodium", boolean.class);
angelicaConfigSodiumEnabledGetter = sodiumGetter;
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}
}
private static boolean isSodiumEnabled() {
try {
return (boolean) angelicaConfigSodiumEnabledGetter.invokeExact();
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
private boolean isVanillaBlockSubclass(String className) {
@@ -221,6 +243,14 @@ public class RedirectorTransformer implements IClassTransformer {
return isVanillaBlockSubclass(className) || moddedBlockSubclasses.contains(className);
}
public static List<String> getTransformerExclusions() {
return Collections.unmodifiableList(TransformerExclusions);
}
public boolean shouldRfbTransform(byte[] basicClass) {
return cstPoolParser.find(basicClass, true);
}
@Override
public byte[] transform(final String className, String transformedName, byte[] basicClass) {
if (basicClass == null) return null;
@@ -237,9 +267,27 @@ public class RedirectorTransformer implements IClassTransformer {
return basicClass;
}
// Keep in sync with com.gtnewhorizons.angelica.loading.rfb.RedirectorTransformerWrapper
final ClassReader cr = new ClassReader(basicClass);
final ClassNode cn = new ClassNode();
cr.accept(cn, 0);
final boolean changed = transformClassNode(transformedName, cn);
if (changed) {
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
cn.accept(cw);
final byte[] bytes = cw.toByteArray();
saveTransformedClass(bytes, transformedName);
return bytes;
}
return basicClass;
}
/** @return Was the class changed? */
public boolean transformClassNode(String transformedName, ClassNode cn)
{
if (cn == null) {
return false;
}
// Track subclasses of Block
if (!isVanillaBlockSubclass(cn.name) && isBlockSubclass(cn.superName)) {
@@ -338,7 +386,7 @@ public class RedirectorTransformer implements IClassTransformer {
}
}
else if ((node.getOpcode() == Opcodes.GETFIELD || node.getOpcode() == Opcodes.PUTFIELD) && node instanceof FieldInsnNode fNode) {
if(!blockOwnerExclusions.contains(fNode.owner) && isBlockSubclass(fNode.owner) && AngelicaConfig.enableSodium) {
if(!blockOwnerExclusions.contains(fNode.owner) && isBlockSubclass(fNode.owner) && isSodiumEnabled()) {
Pair<String, String> fieldToRedirect = null;
for(Pair<String, String> blockPairs : BlockBoundsFields) {
if(fNode.name.equals(blockPairs.getLeft()) || fNode.name.equals(blockPairs.getRight())) {
@@ -384,14 +432,7 @@ public class RedirectorTransformer implements IClassTransformer {
}
}
if (changed) {
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
cn.accept(cw);
final byte[] bytes = cw.toByteArray();
saveTransformedClass(bytes, transformedName);
return bytes;
}
return basicClass;
return changed;
}
private File outputDir = null;
@@ -0,0 +1,9 @@
name=Angelica
version=${version}
additionalVersions=
className=com.gtnewhorizons.angelica.loading.rfb.AngelicaRfbPlugin
transformerExclusions=com.gtnewhorizons.angelica.transform.RedirectorTransformer
versionConstraints=
loadBefore=
loadAfter=mixin; lwjgl3ify
loadRequires=