Hi, i need to add additional field in login packet from client.
Reason is: i need to check hwid of clients for ban(i have implemented and working hwid class).
I have working mod on 1.7.10, its uses ASM to modify login packet on clientside and bukkit to read it on clien.
package my_class.hwidmod.coremod;
import net.minecraft.launchwrapper.IClassTransformer;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.tree.*;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
import static org.objectweb.asm.Opcodes.*;
@SuppressWarnings("unused")
public final class ASMTransformer implements IClassTransformer
{
private static final String HWID_UTILS_CLASS_NAME = "my_class_here/HwidUtils";
private static final String HWID_UTILS_METHOD_GET_HWID_NAME = "getHwid";
private static final String HWID_UTILS_METHOD_GET_HWID_DESC = "()[B";
private static final String FIELD_HWID_NAME = "hwid";
private static final String FIELD_HWID_DESC = "[B";
private static final String METHOD_GET_HWID_NAME = "getHwid";
private static final String METHOD_GET_HWID_DESC = "()[B";
@Override
public byte[] transform(String name, String transformedName, byte[] basicClass)
{
if (transformedName.equals("net.minecraft.network.login.client.C00PacketLoginStart"))
return transformLoginPacket(basicClass);
return basicClass;
}
private static byte[] transformLoginPacket(byte[] basicClass)
{
ClassNode classNode = new ClassNode();
new ClassReader(basicClass).accept(classNode, 0);
// May be need add it before static field __OBFID?
classNode.visitField(ACC_PRIVATE, FIELD_HWID_NAME, FIELD_HWID_DESC, null, null).visitEnd();
MethodVisitor getterVisitor = classNode.visitMethod(ACC_PUBLIC, METHOD_GET_HWID_NAME, METHOD_GET_HWID_DESC, null, null);
getterVisitor.visitVarInsn(ALOAD, 0);
getterVisitor.visitFieldInsn(GETFIELD, classNode.name, FIELD_HWID_NAME, FIELD_HWID_DESC);
getterVisitor.visitInsn(ARETURN);
getterVisitor.visitEnd();
MethodNode methodNode = findMethod(classNode, "<init>", "()V");
for (AbstractInsnNode returnInsnNode : findAllInsnNodes(methodNode, RETURN))
{
InsnList insnList = new InsnList();
insnList.add(new VarInsnNode(ALOAD, 0));
insnList.add(new FieldInsnNode(GETSTATIC, "org/apache/commons/lang3/ArrayUtils", "EMPTY_BYTE_ARRAY", "[B"));
insnList.add(new FieldInsnNode(PUTFIELD, classNode.name, FIELD_HWID_NAME, FIELD_HWID_DESC));
methodNode.instructions.insertBefore(returnInsnNode, insnList);
}
methodNode = findMethod(classNode, "<init>", "(Lcom/mojang/authlib/GameProfile;)V");
for (AbstractInsnNode returnInsnNode : findAllInsnNodes(methodNode, RETURN))
{
InsnList insnList = new InsnList();
insnList.add(new VarInsnNode(ALOAD, 0));
insnList.add(new MethodInsnNode(INVOKESTATIC, HWID_UTILS_CLASS_NAME, HWID_UTILS_METHOD_GET_HWID_NAME, HWID_UTILS_METHOD_GET_HWID_DESC, false));
insnList.add(new FieldInsnNode(PUTFIELD, classNode.name, FIELD_HWID_NAME, FIELD_HWID_DESC));
methodNode.instructions.insertBefore(returnInsnNode, insnList);
}
methodNode = findMethod(classNode, CoreMod.isObfuscated() ? "func_148837_a" : "readPacketData", "(Lnet/minecraft/network/PacketBuffer;)V");
for (AbstractInsnNode returnInsnNode : findAllInsnNodes(methodNode, RETURN))
{
InsnList insnList = new InsnList();
insnList.add(new VarInsnNode(ALOAD, 0));
insnList.add(new VarInsnNode(ALOAD, 1));
insnList.add(new MethodInsnNode(INVOKESTATIC, "net/minecraft/network/Packet", CoreMod.isObfuscated() ? "func_148834_a" : "readBlob", "(Lio/netty/buffer/ByteBuf;)[B", false));
insnList.add(new FieldInsnNode(PUTFIELD, classNode.name, FIELD_HWID_NAME, FIELD_HWID_DESC));
methodNode.instructions.insertBefore(returnInsnNode, insnList);
}
methodNode = findMethod(classNode, CoreMod.isObfuscated() ? "func_148840_b" : "writePacketData", "(Lnet/minecraft/network/PacketBuffer;)V");
for (AbstractInsnNode returnInsnNode : findAllInsnNodes(methodNode, RETURN))
{
InsnList insnList = new InsnList();
insnList.add(new VarInsnNode(ALOAD, 1));
insnList.add(new VarInsnNode(ALOAD, 0));
insnList.add(new FieldInsnNode(GETFIELD, classNode.name, FIELD_HWID_NAME, FIELD_HWID_DESC));
insnList.add(new MethodInsnNode(INVOKESTATIC, "net/minecraft/network/Packet", CoreMod.isObfuscated() ? "func_148838_a" : "writeBlob", "(Lio/netty/buffer/ByteBuf;[B)V", false));
methodNode.instructions.insertBefore(returnInsnNode, insnList);
}
ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS);
classNode.accept(classWriter);
return classWriter.toByteArray();
}
private static MethodNode findMethod(ClassNode classNode, String name, String desc)
{
for (MethodNode methodNode : classNode.methods)
{
if (methodNode.name.equals(name) && methodNode.desc.equals(desc))
return methodNode;
}
throw new NullPointerException("Method " + classNode.name + '.' + name + desc + " not found");
}
private static List<AbstractInsnNode> findAllInsnNodes(MethodNode methodNode, int opcode)
{
return findAllInsnNodes(methodNode.instructions, opcode);
}
private static List<AbstractInsnNode> findAllInsnNodes(InsnList insnList, int opcode)
{
List<AbstractInsnNode> list = new ArrayList<AbstractInsnNode>(1);
for (ListIterator<AbstractInsnNode> iterator = insnList.iterator(); iterator.hasNext(); )
{
AbstractInsnNode insnNode = iterator.next();
if (insnNode.getOpcode() == opcode)
list.add(insnNode);
}
return list;
}
}
But, as far as i know asm is bad practice and dont have suport now. And theris zero documentation on this.
So how can i achive custom field in login packet in 1.12.2?
Iam thinking about modifying userPropertis but don know how to do it with forge.