Skip to content

Commit

Permalink
Fix Crashes with SpongeForge
Browse files Browse the repository at this point in the history
  • Loading branch information
IntegerLimit committed Aug 30, 2024
1 parent 2fa87aa commit 121793c
Show file tree
Hide file tree
Showing 36 changed files with 271 additions and 180 deletions.
8 changes: 4 additions & 4 deletions src/main/java/com/nomiceu/nomilabs/NomiLabs.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ public class NomiLabs {

public static final Logger LOGGER = LogManager.getLogger(LabsValues.LABS_MODID);

public NomiLabs() {
FluidRegistry.enableUniversalBucket();
}

@EventHandler
public void onConstruction(FMLConstructionEvent event) {
CommonProxy.onConstruction();
Expand Down Expand Up @@ -74,8 +78,4 @@ public void loadComplete(FMLLoadCompleteEvent event) {
public void serverStopped(FMLServerStoppedEvent event) {
DataFixerHandler.close();
}

static {
FluidRegistry.enableUniversalBucket();
}
}
21 changes: 16 additions & 5 deletions src/main/java/com/nomiceu/nomilabs/config/LabsConfig.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.nomiceu.nomilabs.config;

import net.minecraft.world.EnumDifficulty;
import net.minecraftforge.common.config.Config;

import com.cleanroommc.configanytime.ConfigAnytime;
Expand Down Expand Up @@ -491,6 +490,8 @@ public static class Advanced {
public String[] ignoreBiomes = new String[0];

@Config.Comment({ "List of Fields to be client side only, acting as @SideOnly(Side.CLIENT).",
"DOES NOT WORK WITH CLASSES FROM MINECRAFT OR FORGE!",
"Does not work with classes loaded before Nomi Labs' Static Init!",
"Do not change unless you know what you are doing!",
"Helps with fixing GrS errors Server Side.",
"Format: <CLASS>@<FIELD>",
Expand All @@ -503,6 +504,8 @@ public static class Advanced {
public String[] clientSideFields = new String[0];

@Config.Comment({ "List of Methods to be client side only, acting as @SideOnly(Side.CLIENT).",
"DOES NOT WORK WITH CLASSES FROM MINECRAFT OR FORGE!",
"Does not work with classes loaded before Nomi Labs' Static Init!",
"Do not change unless you know what you are doing!",
"Helps with fixing GrS errors Server Side.",
"Format: <CLASS>@<METHOD>@<DESC>",
Expand All @@ -515,6 +518,8 @@ public static class Advanced {
public String[] clientSideMethods = new String[0];

@Config.Comment({ "List of Fields to be server side only, acting as @SideOnly(Side.SERVER).",
"DOES NOT WORK WITH CLASSES FROM MINECRAFT OR FORGE!",
"Does not work with classes loaded before Nomi Labs' Static Init!",
"Do not change unless you know what you are doing!",
"Helps with fixing GrS errors Client Side.",
"Format: <CLASS>@<FIELD>",
Expand All @@ -527,6 +532,8 @@ public static class Advanced {
public String[] serverSideFields = new String[0];

@Config.Comment({ "List of Methods to be server side only, acting as @SideOnly(Side.SERVER).",
"DOES NOT WORK WITH CLASSES FROM MINECRAFT OR FORGE!",
"Does not work with classes loaded before Nomi Labs' Static Init!",
"Do not change unless you know what you are doing!",
"Helps with fixing GrS errors Client Side.",
"Format: <CLASS>@<METHOD>@<DESC>",
Expand Down Expand Up @@ -714,17 +721,21 @@ public static class DifficultyOverrides {

@Config.Comment({
"Difficulty (Locked) Override in Normal Mode. Does Not Apply if overrideDifficultyNormal is set to false!",
"[default: NORMAL]" })
"Ordinal of Difficulty. Peaceful = 0, Easy = 1, Normal = 2, Hard = 3.",
"[default: 2]" })
@Config.LangKey("config.nomilabs.advanced.difficulty.normal_override")
@Config.RequiresWorldRestart
public EnumDifficulty difficultyNormal = EnumDifficulty.NORMAL;
@Config.RangeInt(min = 0, max = 3)
public int difficultyNormal = 2;

@Config.Comment({
"Difficulty (Locked) Override in Expert Mode. Does Not Apply if overrideDifficultyExpert is set to false!",
"[default: NORMAL]" })
"Ordinal of Difficulty. Peaceful = 0, Easy = 1, Normal = 2, Hard = 3.",
"[default: 2]" })
@Config.LangKey("config.nomilabs.advanced.difficulty.expert_override")
@Config.RequiresWorldRestart
public EnumDifficulty difficultyExpert = EnumDifficulty.NORMAL;
@Config.RangeInt(min = 0, max = 3)
public int difficultyExpert = 2;
}
}

Expand Down
3 changes: 2 additions & 1 deletion src/main/java/com/nomiceu/nomilabs/core/LabsCore.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@

@IFMLLoadingPlugin.Name("LabsCore")
@IFMLLoadingPlugin.MCVersion(ForgeVersion.mcVersion)
@IFMLLoadingPlugin.SortingIndex(1001)
@IFMLLoadingPlugin.TransformerExclusions("com.nomiceu.nomilabs.core.")
@IFMLLoadingPlugin.SortingIndex(-1001)
public class LabsCore implements IFMLLoadingPlugin, IEarlyMixinLoader {

@Override
Expand Down
102 changes: 21 additions & 81 deletions src/main/java/com/nomiceu/nomilabs/core/LabsTransformer.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,41 +3,28 @@
import java.util.*;

import net.minecraft.launchwrapper.IClassTransformer;
import net.minecraftforge.fml.common.FMLLog;
import net.minecraftforge.fml.relauncher.FMLLaunchHandler;
import net.minecraftforge.fml.relauncher.Side;

import org.apache.commons.lang3.tuple.Pair;
import org.apache.logging.log4j.Level;
import org.objectweb.asm.*;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.FieldNode;
import org.objectweb.asm.tree.MethodNode;

import com.nomiceu.nomilabs.config.LabsConfig;

/**
* @apiNote Inspired by net.minecraftforge.fml.common.asm.transformers.SideTransformer
* <p>
* Allows for Client/Server Only Methods to be specified via Config.
*/
@SuppressWarnings({ "unused", "deprecation" })
@SuppressWarnings({ "unused" })
public class LabsTransformer implements IClassTransformer, Opcodes {

// Map of Class -> Pair Of Obf Mapping Lists, Left is Fields, Right is Methods
private static Map<String, Pair<List<ObfMapping>, List<ObfMapping>>> toRemove;
private static final Set<String> excludedTwoLongPackages;
private static final Set<String> transformableClasses;

/**
* Must setup here so FMLCommonHandler has time to load.
*/
private static void setupToRemove() {
if (toRemove != null) return;
static {
excludedTwoLongPackages = new HashSet<>();
excludedTwoLongPackages.add("net/minecraft");
excludedTwoLongPackages.add("net/minecraftforge");

// Can't use Object2ObjectOpenHashMap as in ASM stage
toRemove = new HashMap<>();
// Seperated from To Remove, to not load ObfMapping too early.
transformableClasses = new HashSet<>();
String[] methodsRemove;
String[] fieldsRemove;

if (FMLLaunchHandler.side() == Side.SERVER) {
// Remove CLIENT side methods & fields
fieldsRemove = LabsConfig.advanced.clientSideFields;
Expand All @@ -54,8 +41,7 @@ private static void setupToRemove() {
throw new IllegalStateException("Invalid Field Remove: " + field +
"! Must have Two Parts, Seperated by '@', Got " + parts.length + "!");

toRemove.computeIfAbsent(parts[0], (k) -> Pair.of(new ArrayList<>(), new ArrayList<>()))
.getLeft().add(new ObfMapping(parts[0], parts[1]));
transformableClasses.add(parts[0]);
}

for (var method : methodsRemove) {
Expand All @@ -64,71 +50,25 @@ private static void setupToRemove() {
throw new IllegalStateException("Invalid Method Remove: " + method +
"! Must have Three Parts, Seperated by '@', Got " + parts.length + "!");

toRemove.computeIfAbsent(parts[0], (k) -> Pair.of(new ArrayList<>(), new ArrayList<>()))
.getRight().add(new ObfMapping(parts[0], parts[1], parts[2]));
transformableClasses.add(parts[0]);
}

FMLLog.log("LabsASM", Level.DEBUG, "Computed To Remove: %s", toRemove);
}

@Override
public byte[] transform(String name, String transformedName, byte[] basicClass) {
setupToRemove();

String internalName = transformedName.replace('.', '/');
if (!toRemove.containsKey(internalName)) return basicClass;

var pair = toRemove.get(internalName);
var fieldsRemove = pair.getLeft();
var methodsRemove = pair.getRight();

ClassNode classNode = new ClassNode();
ClassReader classReader = new ClassReader(basicClass);
classReader.accept(classNode, 0);

for (var toRemove : fieldsRemove) {
Iterator<FieldNode> fields = classNode.fields.iterator();
boolean found = false;
while (fields.hasNext()) {
FieldNode field = fields.next();
if (!toRemove.s_name.equals(field.name)) continue;

FMLLog.log("LabsASM", Level.WARN, "Removing Field: %s.%s", classNode.name, field.name);
fields.remove();
found = true;
break;
}

if (!found)
throw new IllegalStateException("Could not find Field " + classNode.name + "." + toRemove.s_name + "!");
String[] parts = internalName.split("/");

// Check the first two parts against the excluded packages
// Don't transform Minecraft or Forge classes, causes errors due to late loading
// Late loading required for compat with SpongeForge
if (parts.length >= 2) {
if (excludedTwoLongPackages.add(parts[0] + "/" + parts[1]))
return basicClass;
}

var gatherer = new LambdaGatherer();
for (var toRemove : methodsRemove) {
Iterator<MethodNode> methods = classNode.methods.iterator();
boolean found = false;
while (methods.hasNext()) {
MethodNode method = methods.next();
if (!toRemove.matches(method)) continue;

FMLLog.log("LabsASM", Level.WARN, "Removing Method: %s.%s%s", classNode.name, method.name,
method.desc);
methods.remove();
gatherer.accept(method);
found = true;
break;
}

if (!found)
throw new IllegalStateException(
"Could not find Method " + classNode.name + "." + toRemove.s_name + toRemove.s_desc + "!");
}

LambdaGatherer.removeDynamicLambdaMethods(gatherer, classNode);

ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS);
classNode.accept(writer);
if (!transformableClasses.contains(internalName)) return basicClass;

return writer.toByteArray();
return SideSpecificRemover.handleTransform(internalName, basicClass);
}
}
7 changes: 2 additions & 5 deletions src/main/java/com/nomiceu/nomilabs/core/LambdaGatherer.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@
import java.util.List;
import java.util.ListIterator;

import net.minecraftforge.fml.common.FMLLog;

import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.objectweb.asm.Handle;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
Expand All @@ -17,7 +15,6 @@
/**
* @apiNote net.minecraftforge.fml.common.asm.transformers.SideTransformer.LambdaGatherer
*/
@SuppressWarnings("deprecation")
public class LambdaGatherer extends MethodVisitor {

private static final Handle META_FACTORY = new Handle(Opcodes.H_INVOKESTATIC, "java/lang/invoke/LambdaMetafactory",
Expand Down Expand Up @@ -68,7 +65,7 @@ public static void removeDynamicLambdaMethods(LambdaGatherer gatherer, ClassNode
if (method.name.equals(dynamicLambdaHandle.getName()) &&
method.desc.equals(dynamicLambdaHandle.getDesc())) {

FMLLog.log("LabsASM", Level.WARN, "Removing Method: %s.%s%s", classNode.name, method.name,
LogManager.getLogger("LabsASM").warn("Removing Method: {}.{}{}", classNode.name, method.name,
method.desc);

methods.remove();
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/com/nomiceu/nomilabs/core/ObfMapping.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
import java.util.Map.Entry;

import net.minecraft.launchwrapper.Launch;
import net.minecraftforge.fml.common.FMLLog;
import net.minecraftforge.fml.common.asm.transformers.deobf.FMLDeobfuscatingRemapper;

import org.apache.logging.log4j.LogManager;
import org.jetbrains.annotations.NotNull;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
Expand Down Expand Up @@ -318,7 +318,7 @@ public MCPRemapper() {
Resources.readLines(mappings[1].toURI().toURL(), Charsets.UTF_8, this);
Resources.readLines(mappings[2].toURI().toURL(), Charsets.UTF_8, this);
} catch (IOException e) {
FMLLog.log.error("Could not instantiate Nomi Labs MCPRemapper", e);
LogManager.getLogger("LabsASM").error("Could not instantiate Nomi Labs MCPRemapper", e);
}
}

Expand Down
Loading

0 comments on commit 121793c

Please sign in to comment.