I don't remember what is in this
parent
0a33756ccd
commit
3f8260cf41
@ -1,4 +1,2 @@
|
|||||||
shortcut
|
|
||||||
assets
|
|
||||||
build
|
build
|
||||||
.gradle
|
.gradle
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,160 @@
|
|||||||
|
package com.zivilon.cinder_loe.coremod;
|
||||||
|
|
||||||
|
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.ClassNode;
|
||||||
|
import org.objectweb.asm.tree.FieldNode;
|
||||||
|
import org.objectweb.asm.tree.InsnList;
|
||||||
|
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||||
|
import org.objectweb.asm.tree.IntInsnNode;
|
||||||
|
import org.objectweb.asm.tree.TypeInsnNode;
|
||||||
|
import org.objectweb.asm.tree.InsnNode;
|
||||||
|
import org.objectweb.asm.tree.LdcInsnNode;
|
||||||
|
import org.objectweb.asm.tree.FieldInsnNode;
|
||||||
|
import org.objectweb.asm.tree.MethodInsnNode;
|
||||||
|
import org.objectweb.asm.tree.MethodNode;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class LOTRShieldAdder implements IClassTransformer {
|
||||||
|
public static List<BannerInfo> custom_banners = new ArrayList<>();
|
||||||
|
|
||||||
|
public void registerShields() {
|
||||||
|
custom_banners = new ArrayList<>();
|
||||||
|
// Arguments: enum name, texture name, ID, faction name
|
||||||
|
register("RED_DWARF", "redDwarf", 42, "DURINS_FOLK");
|
||||||
|
// register("TEST", "test", 43, "GONDOR");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] transform(String name, String transformedName, byte[] basicClass) {
|
||||||
|
if ("lotr.common.LOTRShields".equals(transformedName)) {
|
||||||
|
registerShields();
|
||||||
|
|
||||||
|
// Get class
|
||||||
|
ClassReader classReader = new ClassReader(basicClass);
|
||||||
|
ClassNode classNode = new ClassNode();
|
||||||
|
classReader.accept(classNode, 0);
|
||||||
|
|
||||||
|
|
||||||
|
// Add the new enum constant
|
||||||
|
for (BannerInfo banner : custom_banners) {
|
||||||
|
FieldNode newEnumConstant = new FieldNode(
|
||||||
|
Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC + Opcodes.ACC_FINAL + Opcodes.ACC_ENUM,
|
||||||
|
banner.enum_name,
|
||||||
|
"Llotr/common/LOTRShields;",
|
||||||
|
null,
|
||||||
|
null
|
||||||
|
);
|
||||||
|
classNode.fields.add(newEnumConstant);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Locate <clinit>
|
||||||
|
MethodNode clinit = null;
|
||||||
|
for (MethodNode method : classNode.methods) {
|
||||||
|
if ("<clinit>".equals(method.name)) {
|
||||||
|
clinit = method;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
InsnList insns = clinit.instructions;
|
||||||
|
AbstractInsnNode constructor_injection_point = null;
|
||||||
|
|
||||||
|
for (int i = 0; i < insns.size(); i++) {
|
||||||
|
AbstractInsnNode insn = insns.get(i);
|
||||||
|
// Check if the instruction is a BIPUSH
|
||||||
|
if (insn.getOpcode() == Opcodes.BIPUSH) {
|
||||||
|
IntInsnNode intInsn = (IntInsnNode) insn;
|
||||||
|
// Check if the operand is 42, indicating the size of the $VALUES array
|
||||||
|
if (intInsn.operand == 42) {
|
||||||
|
// Found the instruction to modify
|
||||||
|
constructor_injection_point = insn;
|
||||||
|
// Modify the operand from 42 to 43 to account for the new enum constant
|
||||||
|
intInsn.operand = 42 + custom_banners.size();
|
||||||
|
System.out.println("Enum array length set to " + intInsn.operand);
|
||||||
|
System.out.println("Banner list size: " + custom_banners.size());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the constructor instructions to add new banner
|
||||||
|
InsnList constructor_injection = new InsnList();
|
||||||
|
for (BannerInfo banner : custom_banners) {
|
||||||
|
constructor_injection.add(new TypeInsnNode(Opcodes.NEW, "lotr/common/item/LOTRItemBanner$BannerType"));
|
||||||
|
constructor_injection.add(new InsnNode(Opcodes.DUP));
|
||||||
|
System.out.println("Registering with enum " + banner.enum_name);
|
||||||
|
constructor_injection.add(new LdcInsnNode(banner.enum_name));
|
||||||
|
System.out.println("Registering with identifier " + banner.identifier);
|
||||||
|
constructor_injection.add(new LdcInsnNode(banner.identifier));
|
||||||
|
constructor_injection.add(new FieldInsnNode(Opcodes.GETSTATIC, "lotr/common/fac/LOTRFaction", banner.faction, "Llotr/common/fac/LOTRFaction;"));
|
||||||
|
constructor_injection.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, "lotr/common/item/LOTRItemBanner$BannerType", "<init>", "(Ljava/lang/String;IILjava/lang/String;Llotr/common/fac/LOTRFaction;)V", false));
|
||||||
|
constructor_injection.add(new FieldInsnNode(Opcodes.PUTSTATIC, "lotr/common/item/LOTRItemBanner$BannerType", banner.enum_name, "Llotr/common/item/LOTRItemBanner$BannerType;"));
|
||||||
|
}
|
||||||
|
// Insert the new instructions
|
||||||
|
if (constructor_injection_point != null) {
|
||||||
|
insns.insertBefore(constructor_injection_point, constructor_injection);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Modifying the $VALUES array
|
||||||
|
// Create new instruction list to be injected later
|
||||||
|
InsnList values_array_injection = new InsnList();
|
||||||
|
|
||||||
|
// Add instructions to the instruction list
|
||||||
|
for (BannerInfo banner : custom_banners) {
|
||||||
|
values_array_injection.add(new InsnNode(Opcodes.DUP));
|
||||||
|
values_array_injection.add(new FieldInsnNode(Opcodes.GETSTATIC, "lotr/common/item/LOTRItemBanner$BannerType", banner.enum_name, "Llotr/common/item/LOTRItemBanner$BannerType;"));
|
||||||
|
values_array_injection.add(new InsnNode(Opcodes.AASTORE));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the putstatic instruction for $VALUES
|
||||||
|
// This is where the fields are injected into a list, we want to inject our instructions before this
|
||||||
|
AbstractInsnNode values_injection_point = null;
|
||||||
|
|
||||||
|
while (constructor_injection_point != null) {
|
||||||
|
constructor_injection_point = constructor_injection_point.getNext();
|
||||||
|
if (constructor_injection_point.getOpcode() == Opcodes.PUTSTATIC) {
|
||||||
|
values_injection_point = constructor_injection_point;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert the new instructions before the putstatic instruction
|
||||||
|
if (values_injection_point != null) {
|
||||||
|
insns.insertBefore(values_injection_point, values_array_injection);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the modified class back to a byte array
|
||||||
|
ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
|
||||||
|
classNode.accept(classWriter);
|
||||||
|
return classWriter.toByteArray(); // Return the modified class
|
||||||
|
}
|
||||||
|
return basicClass; // Return the unmodified class for all other classes
|
||||||
|
}
|
||||||
|
|
||||||
|
public void register(String enum_name, String identifier, int ordinal, String faction) {
|
||||||
|
System.out.println("Registering banner " + enum_name + " " + identifier);
|
||||||
|
custom_banners.add(new BannerInfo(enum_name, identifier, ordinal, faction));
|
||||||
|
}
|
||||||
|
|
||||||
|
public class BannerInfo {
|
||||||
|
String enum_name;
|
||||||
|
String identifier;
|
||||||
|
int ordinal;
|
||||||
|
String faction;
|
||||||
|
|
||||||
|
public BannerInfo(String enum_name, String identifier, int ordinal, String faction) {
|
||||||
|
this.enum_name = enum_name;
|
||||||
|
this.identifier = identifier;
|
||||||
|
this.ordinal = ordinal;
|
||||||
|
this.faction = faction;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue