Add support for mod access transformers without a coremod requirement.

Use the "FMLAT" manifest attribute, with a space separate list of files
that live in the 'META-INF' directory. They should conform to standard AT
formatting.
This commit is contained in:
cpw 2014-06-24 21:34:07 -04:00
parent 237c28b6cb
commit 88a411550a
5 changed files with 101 additions and 16 deletions

View file

@ -8,7 +8,7 @@
"assets": "1.7.10",
"libraries": [
{
"name": "com.mojang:realms:1.2.3"
"name": "com.mojang:realms:1.2.4"
},
{
"name": "org.apache.commons:commons-compress:1.8.1"

View file

@ -27,10 +27,14 @@ import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
@ -51,6 +55,8 @@ import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import com.google.common.io.ByteSource;
import com.google.common.io.CharSource;
import com.google.common.io.LineProcessor;
import com.google.common.io.Resources;
@ -59,7 +65,7 @@ import cpw.mods.fml.relauncher.FMLRelaunchLog;
public class AccessTransformer implements IClassTransformer
{
private static final boolean DEBUG = Boolean.parseBoolean(System.getProperty("fml.debugAccessTransformer", "false"));
private class Modifier
class Modifier
{
public String name = "";
public String desc = "";
@ -100,7 +106,41 @@ public class AccessTransformer implements IClassTransformer
readMapFile(rulesFile);
}
private void readMapFile(String rulesFile) throws IOException
AccessTransformer(JarFile jar) throws IOException
{
Manifest manifest = jar.getManifest();
String atList = manifest.getMainAttributes().getValue("FMLAT");
for (String at : atList.split(" "))
{
JarEntry jarEntry = jar.getJarEntry("META-INF/"+at);
if (jarEntry != null)
{
processATFile(new JarByteSource(jar,jarEntry).asCharSource(Charsets.UTF_8));
}
}
FMLRelaunchLog.fine("Loaded %d rules from AccessTransformer mod jar file %s\n", modifiers.size(), jar.getName());
}
AccessTransformer(Class<? extends AccessTransformer> dummyClazz)
{
// This is a noop
}
private class JarByteSource extends ByteSource {
private JarFile jar;
private JarEntry entry;
public JarByteSource(JarFile jar, JarEntry entry)
{
this.jar = jar;
this.entry = entry;
}
@Override
public InputStream openStream() throws IOException
{
return jar.getInputStream(entry);
}
}
void readMapFile(String rulesFile) throws IOException
{
File file = new File(rulesFile);
URL rulesResource;
@ -112,7 +152,12 @@ public class AccessTransformer implements IClassTransformer
{
rulesResource = Resources.getResource(rulesFile);
}
Resources.readLines(rulesResource, Charsets.UTF_8, new LineProcessor<Void>()
processATFile(Resources.asCharSource(rulesResource, Charsets.UTF_8));
FMLRelaunchLog.fine("Loaded %d rules from AccessTransformer config file %s\n", modifiers.size(), rulesFile);
}
private void processATFile(CharSource rulesResource) throws IOException
{
rulesResource.readLines(new LineProcessor<Void>()
{
@Override
public Void getResult()
@ -160,7 +205,6 @@ public class AccessTransformer implements IClassTransformer
return true;
}
});
FMLRelaunchLog.fine("Loaded %d rules from AccessTransformer config file %s\n", modifiers.size(), rulesFile);
}
@Override
@ -217,7 +261,7 @@ public class AccessTransformer implements IClassTransformer
if ((n.name.equals(m.name) && n.desc.equals(m.desc)) || m.name.equals("*"))
{
n.access = getFixedAccess(n.access, m);
// constructors always use INVOKESPECIAL
if (!n.name.equals("<init>"))
{
@ -225,14 +269,14 @@ public class AccessTransformer implements IClassTransformer
// so that overridden methods will be called. Only need to scan this class, because obviously the method was private.
boolean wasPrivate = (m.oldAccess & ACC_PRIVATE) == ACC_PRIVATE;
boolean isNowPrivate = (m.newAccess & ACC_PRIVATE) == ACC_PRIVATE;
if (wasPrivate && !isNowPrivate)
{
nowOverridable.add(n);
}
}
if (DEBUG)
{
System.out.println(String.format("Method: %s.%s%s %s -> %s", name, n.name, n.desc, toBinary(m.oldAccess), toBinary(m.newAccess)));
@ -244,7 +288,7 @@ public class AccessTransformer implements IClassTransformer
}
}
}
replaceInvokeSpecial(classNode, nowOverridable);
}
}
@ -253,7 +297,7 @@ public class AccessTransformer implements IClassTransformer
classNode.accept(writer);
return writer.toByteArray();
}
private void replaceInvokeSpecial(ClassNode clazz, List<MethodNode> toReplace)
{
for (MethodNode method : clazz.methods)
@ -477,4 +521,12 @@ public class AccessTransformer implements IClassTransformer
}
}
}
Multimap<String, Modifier> getModifiers()
{
return modifiers;
}
boolean isEmpty()
{
return modifiers.isEmpty();
}
}

View file

@ -0,0 +1,34 @@
package cpw.mods.fml.common.asm.transformers;
import java.io.IOException;
import java.util.List;
import java.util.jar.JarFile;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
public class ModAccessTransformer extends AccessTransformer {
private static List<AccessTransformer> embedded = Lists.newArrayList();
public ModAccessTransformer() throws IOException
{
super(ModAccessTransformer.class);
for (AccessTransformer at : embedded)
{
mergeModifiers(at.getModifiers());
}
}
private void mergeModifiers(Multimap<String, Modifier> modifiers)
{
getModifiers().putAll(modifiers);
}
public static void addJar(JarFile jar) throws IOException
{
AccessTransformer at = new AccessTransformer(jar);
if (!at.isEmpty())
{
embedded.add(at);
}
}
}

View file

@ -31,6 +31,7 @@ public class FMLDeobfTweaker implements ITweaker {
{
classLoader.registerTransformer(transformer);
}
classLoader.registerTransformer("cpw.mods.fml.common.asm.transformers.ModAccessTransformer");
try
{
FMLRelaunchLog.fine("Validating minecraft");

View file

@ -28,21 +28,18 @@ import java.util.List;
import java.util.Map;
import java.util.jar.Attributes;
import java.util.jar.JarFile;
import org.apache.logging.log4j.Level;
import net.minecraft.launchwrapper.ITweaker;
import net.minecraft.launchwrapper.Launch;
import net.minecraft.launchwrapper.LaunchClassLoader;
import org.apache.logging.log4j.Level;
import com.google.common.base.Strings;
import com.google.common.base.Throwables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.ObjectArrays;
import com.google.common.primitives.Ints;
import cpw.mods.fml.common.FMLLog;
import cpw.mods.fml.common.asm.transformers.ModAccessTransformer;
import cpw.mods.fml.common.launcher.FMLInjectionAndSortingTweaker;
import cpw.mods.fml.common.launcher.FMLTweaker;
import cpw.mods.fml.common.toposort.TopologicalSort;
@ -249,6 +246,7 @@ public class CoreModManager {
// Not a coremod
continue;
}
ModAccessTransformer.addJar(jar);
mfAttributes = jar.getManifest().getMainAttributes();
}
catch (IOException ioe)