120 lines
4.1 KiB
Java
120 lines
4.1 KiB
Java
/*
|
|
* Minecraft Forge
|
|
* Copyright (c) 2016-2018.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation version 2.1
|
|
* of the License.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
package net.minecraftforge.fml.common.asm;
|
|
|
|
import java.util.ListIterator;
|
|
|
|
import net.minecraft.launchwrapper.IClassTransformer;
|
|
|
|
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.FieldNode;
|
|
import org.objectweb.asm.tree.MethodInsnNode;
|
|
import org.objectweb.asm.tree.MethodNode;
|
|
|
|
public class FieldRedirectTransformer implements IClassTransformer
|
|
{
|
|
private final String clsName;
|
|
private final String TYPE;
|
|
private final String DESC;
|
|
private final String bypass;
|
|
|
|
protected FieldRedirectTransformer(String cls, String type, String bypass)
|
|
{
|
|
this.clsName = cls;
|
|
this.TYPE = type;
|
|
this.DESC = "()" + type;
|
|
this.bypass = bypass;
|
|
}
|
|
|
|
@Override
|
|
public byte[] transform(String name, String transformedName, byte[] basicClass)
|
|
{
|
|
if (!this.clsName.equals(transformedName))
|
|
return basicClass;
|
|
|
|
ClassNode classNode = new ClassNode();
|
|
ClassReader classReader = new ClassReader(basicClass);
|
|
classReader.accept(classNode, 0);
|
|
|
|
FieldNode fieldRef = null;
|
|
for (FieldNode f : classNode.fields)
|
|
{
|
|
if (this.TYPE.equals(f.desc) && fieldRef == null)
|
|
{
|
|
fieldRef = f;
|
|
}
|
|
else if (this.TYPE.equals(f.desc))
|
|
{
|
|
throw new RuntimeException("Error processing " + clsName + " - found a duplicate holder field");
|
|
}
|
|
}
|
|
if (fieldRef == null)
|
|
{
|
|
throw new RuntimeException("Error processing " + clsName + " - no holder field declared (is the code somehow obfuscated?)");
|
|
}
|
|
|
|
MethodNode getMethod = null;
|
|
for (MethodNode m: classNode.methods)
|
|
{
|
|
if (m.name.equals(this.bypass)) continue;
|
|
if (this.DESC.equals(m.desc) && getMethod == null)
|
|
{
|
|
getMethod = m;
|
|
}
|
|
else if (this.DESC.equals(m.desc))
|
|
{
|
|
throw new RuntimeException("Error processing " + clsName + " - duplicate get method found");
|
|
}
|
|
}
|
|
if (getMethod == null)
|
|
{
|
|
throw new RuntimeException("Error processing " + clsName + " - no get method found (is the code somehow obfuscated?)");
|
|
}
|
|
|
|
for (MethodNode m: classNode.methods)
|
|
{
|
|
if (m.name.equals(this.bypass)) continue;
|
|
for (ListIterator<AbstractInsnNode> it = m.instructions.iterator(); it.hasNext(); )
|
|
{
|
|
AbstractInsnNode insnNode = it.next();
|
|
if (insnNode.getType() == AbstractInsnNode.FIELD_INSN)
|
|
{
|
|
FieldInsnNode fi = (FieldInsnNode)insnNode;
|
|
if (fieldRef.name.equals(fi.name) && fi.getOpcode() == Opcodes.GETFIELD)
|
|
{
|
|
it.remove();
|
|
MethodInsnNode replace = new MethodInsnNode(Opcodes.INVOKEVIRTUAL, classNode.name, getMethod.name, getMethod.desc, false);
|
|
it.add(replace);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS);
|
|
classNode.accept(writer);
|
|
return writer.toByteArray();
|
|
}
|
|
|
|
}
|