Merged everything, should be stable
This commit is contained in:
@@ -1,561 +0,0 @@
|
||||
package mod.sin.wyvern.mastercraft;
|
||||
|
||||
import javassist.bytecode.*;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.PrintWriter;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
|
||||
public class BytecodeTools extends Bytecode {
|
||||
|
||||
//private static final int EMPTY_INT = Integer.MAX_VALUE;
|
||||
|
||||
BytecodeTools(ConstPool constPool){
|
||||
super(constPool);
|
||||
}
|
||||
|
||||
/**
|
||||
* Look for a class in the constant pool.
|
||||
* Throws NoMatchingConstPoolIndexException if the references isn't found.
|
||||
*
|
||||
* @param className String Object type. Full class name using periods.
|
||||
* @return int primitive, index in constant pool table.
|
||||
*/
|
||||
int findClassIndex(String className){
|
||||
int classReferenceIndex = getClassReferenceIndex(className);
|
||||
if (classReferenceIndex == -1)
|
||||
throw new RuntimeException("No matching class found.");
|
||||
this.add((classReferenceIndex >>> 8) & 0xFF, classReferenceIndex & 0xFF);
|
||||
return classReferenceIndex;
|
||||
}
|
||||
|
||||
int addClassIndex(String className){
|
||||
int classReferenceIndex = getClassReferenceIndex(className);
|
||||
if (classReferenceIndex == -1)
|
||||
classReferenceIndex = this.getConstPool().addClassInfo(className);
|
||||
this.add((classReferenceIndex >>> 8) & 0xFF, classReferenceIndex & 0xFF);
|
||||
return classReferenceIndex;
|
||||
}
|
||||
|
||||
int findMethodIndex(int opcode, String name, String descriptor, String className){
|
||||
int methodReferenceIndex;
|
||||
int classReferenceIndex = getClassReferenceIndex(className);
|
||||
if (classReferenceIndex == -1)
|
||||
throw new RuntimeException("No matching class found.");
|
||||
|
||||
methodReferenceIndex = IntStream.range(1, this.getConstPool().getSize())
|
||||
.filter(value -> this.getConstPool().getTag(value) == ConstPool.CONST_Methodref)
|
||||
.filter(value -> this.getConstPool().eqMember(name, descriptor, value) != null)
|
||||
.filter(value -> Objects.equals(this.getConstPool().getMethodrefClass(value), classReferenceIndex))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new RuntimeException("No matching method found."));
|
||||
this.addOpcode(opcode);
|
||||
this.add((methodReferenceIndex >>> 8) & 0xFF, methodReferenceIndex & 0xFF);
|
||||
|
||||
return methodReferenceIndex;
|
||||
}
|
||||
|
||||
int addMethodIndex(int opcode, String name, String methodDescriptor, String className){
|
||||
int classReferenceIndex = getClassReferenceIndex(className);
|
||||
if (classReferenceIndex == -1)
|
||||
classReferenceIndex = this.getConstPool().addClassInfo(className);
|
||||
int indexReference = this.getConstPool().addMethodrefInfo(classReferenceIndex, name, methodDescriptor);
|
||||
this.addOpcode(opcode);
|
||||
this.add((indexReference >>> 8) & 0xFF, indexReference & 0xFF);
|
||||
return indexReference;
|
||||
}
|
||||
|
||||
int findFieldIndex(int opcode, String name, String descriptor, String className){
|
||||
int fieldReferenceIndex;
|
||||
int classReferenceIndex = getClassReferenceIndex(className);
|
||||
if (classReferenceIndex == -1)
|
||||
throw new RuntimeException("No matching class found.");
|
||||
fieldReferenceIndex = IntStream.range(1, this.getConstPool().getSize())
|
||||
.filter(value -> this.getConstPool().getTag(value) == ConstPool.CONST_Fieldref)
|
||||
.filter(value -> this.getConstPool().eqMember(name, descriptor, value) != null)
|
||||
.filter(value -> this.getConstPool().getFieldrefClass(value) == classReferenceIndex)
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new RuntimeException("No matching field found."));
|
||||
this.addOpcode(opcode);
|
||||
this.add((fieldReferenceIndex >>> 8) & 0xFF, fieldReferenceIndex & 0xFF);
|
||||
return fieldReferenceIndex;
|
||||
}
|
||||
|
||||
int addFieldIndex(int opcode, String name, String descriptor, String className){
|
||||
int classReferenceIndex = getClassReferenceIndex(className);
|
||||
if (classReferenceIndex == -1)
|
||||
classReferenceIndex = this.getConstPool().addClassInfo(className);
|
||||
int fieldReferenceIndex = this.getConstPool().addFieldrefInfo(classReferenceIndex, name, descriptor);
|
||||
this.addOpcode(opcode);
|
||||
this.add((fieldReferenceIndex >>> 8) & 0xFF, fieldReferenceIndex & 0xFF);
|
||||
return fieldReferenceIndex;
|
||||
}
|
||||
|
||||
void findStringIndex(String string){
|
||||
int indexReference = IntStream.range(1, this.getConstPool().getSize())
|
||||
.filter(value -> this.getConstPool().getTag(value) == ConstPool.CONST_String)
|
||||
.filter(value -> Objects.equals(this.getConstPool().getStringInfo(value), string))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new RuntimeException("No matching string found."));
|
||||
this.add((indexReference >>> 8) & 0xFF, indexReference & 0xFF);
|
||||
}
|
||||
|
||||
void addStringIndex(String string){
|
||||
int indexReference = this.getConstPool().addStringInfo(string);
|
||||
this.add((indexReference >>> 8) & 0xFF, indexReference & 0xFF);
|
||||
}
|
||||
|
||||
void findLongIndex(long longValue){
|
||||
int indexReference = IntStream.range(1, this.getConstPool().getSize())
|
||||
.filter(value -> this.getConstPool().getTag(value) == ConstPool.CONST_Long)
|
||||
.filter(value -> this.getConstPool().getLongInfo(value) == longValue)
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new RuntimeException("No matching long found."));
|
||||
this.add((indexReference >>> 8) & 0xFF, indexReference & 0xFF);
|
||||
}
|
||||
|
||||
void addLongIndex(long longValue){
|
||||
int indexReference = this.getConstPool().addLongInfo(longValue);
|
||||
this.add((indexReference >>> 8) & 0xFF, indexReference & 0xFF);
|
||||
}
|
||||
|
||||
void findFloatIndex(float floatValue){
|
||||
int indexReference = IntStream.range(1, this.getConstPool().getSize())
|
||||
.filter(value -> this.getConstPool().getTag(value) == ConstPool.CONST_Float)
|
||||
.filter(value -> this.getConstPool().getFloatInfo(value) == floatValue)
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new RuntimeException("No matching float found."));
|
||||
this.add((indexReference >>> 8) & 0xFF, indexReference & 0xFF);
|
||||
}
|
||||
|
||||
void addFloatIndex(float floatValue){
|
||||
int indexReference = this.getConstPool().addFloatInfo(floatValue);
|
||||
this.add((indexReference >>> 8) & 0xFF, indexReference & 0xFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* a double value stored in the constant pool is always a LDC2_W. This is different then a local variable holding a double.
|
||||
*
|
||||
* @param doubleValue primitive double.
|
||||
*/
|
||||
void findDoubleIndex(double doubleValue){
|
||||
int indexReference = IntStream.range(1, this.getConstPool().getSize())
|
||||
.filter(value -> this.getConstPool().getTag(value) == ConstPool.CONST_Double)
|
||||
.filter(value -> this.getConstPool().getDoubleInfo(value) == doubleValue)
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new RuntimeException("No matching double found."));
|
||||
this.addOpcode(Opcode.LDC2_W);
|
||||
this.add((indexReference >>> 8) & 0xFF, indexReference & 0xFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* a double value stored in the constant pool is always a LDC2_W. This is different then a local variable holding a double.
|
||||
*
|
||||
* @param doubleValue primitive double.
|
||||
*/
|
||||
void addDoubleIndex(double doubleValue){
|
||||
int indexReference = this.getConstPool().addDoubleInfo(doubleValue);
|
||||
this.addOpcode(Opcode.LDC2_W);
|
||||
this.add((indexReference >>> 8) & 0xFF, indexReference & 0xFF);
|
||||
}
|
||||
|
||||
private boolean hasAClassDeclaringTag(int tag){
|
||||
return tag == ConstPool.CONST_Methodref || tag == ConstPool.CONST_Fieldref || tag == ConstPool.CONST_InterfaceMethodref;
|
||||
}
|
||||
|
||||
/**
|
||||
* Often a class's name will appear twice in the constant pool. One of the occurrence is not used as a declaring class for anything.
|
||||
* I have no idea why it's present but it can break looking up constant pool references if the unassociated one is picked. JA has a
|
||||
* built in way of finding existent references but a underlying mechanic is that a hash map uses a string class name as a key
|
||||
* in a hashMap. Two equal strings will overwrite each other in this case. This is part the the tools library to look for matches
|
||||
* instead of relying on JA.
|
||||
*
|
||||
* 1. scan the constant pool and get the class references that match className.
|
||||
* 2. scan again through the constant pool looking for class associations that use the references found in #1. One of the options
|
||||
* will have no references and illuminate that one to return the one that should be used.
|
||||
*
|
||||
* @param className String type object, uses full class name and periods.
|
||||
* @return int primitive, the address in constant pool for the class matching className.
|
||||
*/
|
||||
private int getClassReferenceIndex(String className){
|
||||
return IntStream.range(1, this.getConstPool().getSize())
|
||||
.filter(value -> this.getConstPool().getTag(value) == ConstPool.CONST_Class)
|
||||
.filter(value -> Objects.equals(Descriptor.toClassName(this.getConstPool().getClassInfoByDescriptor(value)), className))
|
||||
.filter( verifyIndex ->
|
||||
IntStream.range(1, this.getConstPool().getSize())
|
||||
.filter(value -> hasAClassDeclaringTag(this.getConstPool().getTag(value)))
|
||||
.filter(value -> {
|
||||
boolean result = false;
|
||||
switch (this.getConstPool().getTag(value)) {
|
||||
case ConstPool.CONST_Methodref:
|
||||
result = this.getConstPool().getMethodrefClass(value) == verifyIndex;
|
||||
break;
|
||||
case ConstPool.CONST_Fieldref:
|
||||
result = this.getConstPool().getFieldrefClass(value) == verifyIndex;
|
||||
break;
|
||||
case ConstPool.CONST_InterfaceMethodref:
|
||||
result = this.getConstPool().getInterfaceMethodrefClass(value) == verifyIndex;
|
||||
break;
|
||||
}
|
||||
return result;})
|
||||
.count() > 0
|
||||
)
|
||||
.findFirst()
|
||||
.orElse(-1);
|
||||
}
|
||||
|
||||
void findInterfaceMethodIndex(String name, String descriptor){
|
||||
if(IntStream.range(1, this.getConstPool().getSize())
|
||||
.filter(value -> this.getConstPool().getTag(value) == ConstPool.CONST_InterfaceMethodref)
|
||||
.filter(value -> this.getConstPool().eqMember(name, descriptor, value) != null)
|
||||
.count() != 1){
|
||||
throw new RuntimeException("No matching interface found.");
|
||||
}
|
||||
else {
|
||||
int indexReference = IntStream.range(1, this.getConstPool().getSize())
|
||||
.filter(value -> this.getConstPool().getTag(value) == ConstPool.CONST_InterfaceMethodref)
|
||||
.filter(value -> this.getConstPool().eqMember(name, descriptor, value) != null)
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new RuntimeException("No matching interface found."));
|
||||
this.add((indexReference >>> 8) & 0xFF, indexReference & 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
void addInterfaceMethodIndex(String name, String descriptor){
|
||||
int classIndexReference = IntStream.range(1, this.getConstPool().getSize())
|
||||
.filter(value -> this.getConstPool().getTag(value) == ConstPool.CONST_Class)
|
||||
.filter(value -> Objects.equals(this.getConstPool().getClassInfoByDescriptor(value), Descriptor.toClassName(descriptor)))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new RuntimeException("No matching class found."));
|
||||
int indexReference = this.getConstPool().addInterfaceMethodrefInfo(classIndexReference, name, descriptor);
|
||||
this.add((indexReference >>> 8) & 0xFF, indexReference & 0xFF);
|
||||
}
|
||||
|
||||
void codeBranching(int opcode, int branchCount){
|
||||
this.addOpcode(opcode);
|
||||
this.add((branchCount >>> 8) & 0xFF, branchCount & 0xFF);
|
||||
}
|
||||
|
||||
void localVariableIndex(int opcode, int slot){
|
||||
this.addOpcode(opcode);
|
||||
this.add(slot);
|
||||
}
|
||||
|
||||
void integerIndex(int opcode, int value){
|
||||
switch (opcode) {
|
||||
case Opcode.BIPUSH :
|
||||
this.addOpcode(Opcode.BIPUSH);
|
||||
this.add((byte)value);
|
||||
break;
|
||||
case Opcode.SIPUSH :
|
||||
this.addOpcode(Opcode.SIPUSH);
|
||||
this.add((value >>> 8) & 0xFF, value & 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode the value for arg "integer" into the appropriate byteCode opCode + operand for the java-int. Add the
|
||||
* encoded information to the byte code object "bytecode".
|
||||
*
|
||||
* @param integer int value.
|
||||
*/
|
||||
void addInteger(int integer) {
|
||||
switch (integer) {
|
||||
case -1:
|
||||
this.add(Opcode.ICONST_M1);
|
||||
break;
|
||||
case 0:
|
||||
this.add(Opcode.ICONST_0);
|
||||
break;
|
||||
case 1:
|
||||
this.add(Opcode.ICONST_1);
|
||||
break;
|
||||
case 2:
|
||||
this.add(Opcode.ICONST_2);
|
||||
break;
|
||||
case 3:
|
||||
this.add(Opcode.ICONST_3);
|
||||
break;
|
||||
case 4:
|
||||
this.add(Opcode.ICONST_4);
|
||||
break;
|
||||
case 5:
|
||||
this.add(Opcode.ICONST_5);
|
||||
break;
|
||||
default:
|
||||
if (integer >= Byte.MIN_VALUE && integer <= Byte.MAX_VALUE) {
|
||||
this.add(Opcode.BIPUSH);
|
||||
// integer bound to byte size.
|
||||
this.add(integer);
|
||||
} else if (integer >= Short.MIN_VALUE && integer <= Short.MAX_VALUE) {
|
||||
this.add(Opcode.SIPUSH);
|
||||
// Since byte code requires byte sized blocks, break up integer with bitmask and shift.
|
||||
this.add((integer & 0xff00) >>> 8, integer & 0x00ff);
|
||||
} else {
|
||||
// Appends LDC or LDC_W depending on constant pool size.
|
||||
this.addLdc(this.getConstPool().addIntegerInfo(integer));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode the byte code represented by a opCode + operand(s) at the position in arg "instructionIndex". Return
|
||||
* decoded data as java-int.
|
||||
*
|
||||
* @param codeIterator JA CodeIterator object.
|
||||
* @param instructionIndex int value, it is the codeIterator index of an opCode.
|
||||
* @return int value.
|
||||
*/
|
||||
int getInteger(CodeIterator codeIterator, int instructionIndex) {
|
||||
int opCode = codeIterator.byteAt(instructionIndex);
|
||||
switch (opCode) {
|
||||
case Opcode.ICONST_M1:
|
||||
return -1;
|
||||
case Opcode.ICONST_0:
|
||||
return 0;
|
||||
case Opcode.ICONST_1:
|
||||
return 1;
|
||||
case Opcode.ICONST_2:
|
||||
return 2;
|
||||
case Opcode.ICONST_3:
|
||||
return 3;
|
||||
case Opcode.ICONST_4:
|
||||
return 4;
|
||||
case Opcode.ICONST_5:
|
||||
return 5;
|
||||
case Opcode.BIPUSH:
|
||||
return codeIterator.byteAt(instructionIndex + 1);
|
||||
case Opcode.SIPUSH:
|
||||
return codeIterator.s16bitAt(instructionIndex + 1);
|
||||
case Opcode.LDC:
|
||||
return this.getConstPool().getIntegerInfo(codeIterator.byteAt(instructionIndex + 1));
|
||||
case Opcode.LDC_W:
|
||||
return this.getConstPool().getIntegerInfo(codeIterator.u16bitAt(instructionIndex + 1));
|
||||
default:
|
||||
throw new RuntimeException(String.format("Failed to decode integer. Pos = %d, Bytecode = %d", instructionIndex, opCode));
|
||||
}
|
||||
}
|
||||
|
||||
static int findSlotInLocalVariableTable(CodeAttribute codeAttribute, String variableName){
|
||||
LocalVariableAttribute table = (LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag);
|
||||
int tableOrdinal;
|
||||
tableOrdinal = IntStream.range(0,table.tableLength()).filter(value -> Objects.equals(table.variableName(value), variableName )).findFirst().orElse(-1);
|
||||
if (tableOrdinal == -1){
|
||||
return -1;
|
||||
}
|
||||
return table.index(tableOrdinal);
|
||||
}
|
||||
|
||||
static int findLineNumberInLineNumberTable(CodeAttribute codeAttribute, String variableName){
|
||||
LocalVariableAttribute table = (LocalVariableAttribute) codeAttribute.getAttribute(LineNumberAttribute.tag);
|
||||
int tableOrdinal;
|
||||
tableOrdinal = IntStream.range(0,table.tableLength()).filter(value -> Objects.equals(table.variableName(value), variableName )).findFirst().orElse(-1);
|
||||
if (tableOrdinal == -1){
|
||||
return -1;
|
||||
}
|
||||
return table.index(tableOrdinal);
|
||||
}
|
||||
|
||||
private static int[] getInstruction(int size, int index, CodeIterator codeIterator) {
|
||||
int[] toReturn = null;
|
||||
int bitLine;
|
||||
int bitLine2;
|
||||
switch (size) {
|
||||
case 1:
|
||||
bitLine = codeIterator.byteAt(index);
|
||||
toReturn = new int[]{
|
||||
bitLine
|
||||
};
|
||||
break;
|
||||
case 2:
|
||||
bitLine = codeIterator.s16bitAt(index);
|
||||
toReturn = new int[]{
|
||||
(bitLine & 0xff00) >>> 8,
|
||||
bitLine & 0x00ff
|
||||
};
|
||||
break;
|
||||
case 3:
|
||||
bitLine = codeIterator.s32bitAt(index);
|
||||
toReturn = new int[]{
|
||||
(bitLine & 0xff000000) >>> 24,
|
||||
(bitLine & 0x00ff0000) >>> 16,
|
||||
(bitLine & 0x0000ff00) >>> 8
|
||||
// not using the last byte
|
||||
};
|
||||
break;
|
||||
case 4:
|
||||
bitLine = codeIterator.s32bitAt(index);
|
||||
toReturn = new int[]{
|
||||
(bitLine & 0xff000000) >>> 24,
|
||||
(bitLine & 0x00ff0000) >>> 16,
|
||||
(bitLine & 0x0000ff00) >>> 8,
|
||||
(bitLine & 0x000000ff)
|
||||
};
|
||||
break;
|
||||
case 5:
|
||||
bitLine = codeIterator.s32bitAt(index);
|
||||
bitLine2 = codeIterator.byteAt(index + 4);
|
||||
toReturn = new int[]{
|
||||
(bitLine & 0xff000000) >>> 24,
|
||||
(bitLine & 0x00ff0000) >>> 16,
|
||||
(bitLine & 0x0000ff00) >>> 8,
|
||||
(bitLine & 0x000000ff),
|
||||
bitLine2
|
||||
};
|
||||
break;
|
||||
case 6:
|
||||
bitLine = codeIterator.s32bitAt(index);
|
||||
bitLine2 = codeIterator.s16bitAt(index + 4);
|
||||
toReturn = new int[]{
|
||||
(bitLine & 0xff000000) >>> 24,
|
||||
(bitLine & 0x00ff0000) >>> 16,
|
||||
(bitLine & 0x0000ff00) >>> 8,
|
||||
(bitLine & 0x000000ff),
|
||||
(bitLine2 & 0xff00) >>> 8,
|
||||
(bitLine2 & 0x00ff)
|
||||
};
|
||||
break;
|
||||
case 7:
|
||||
bitLine = codeIterator.s32bitAt(index);
|
||||
bitLine2 = codeIterator.s32bitAt(index + 4);
|
||||
toReturn = new int[]{
|
||||
(bitLine & 0xff000000) >>> 24,
|
||||
(bitLine & 0x00ff0000) >>> 16,
|
||||
(bitLine & 0x0000ff00) >>> 8,
|
||||
(bitLine & 0x000000ff),
|
||||
(bitLine2 & 0xff000000) >>> 24,
|
||||
(bitLine2 & 0x00ff0000) >>> 16,
|
||||
(bitLine2 & 0x0000ff00) >>> 8
|
||||
// not using the last byte
|
||||
};
|
||||
break;
|
||||
case 8:
|
||||
bitLine = codeIterator.s32bitAt(index);
|
||||
bitLine2 = codeIterator.s32bitAt(index + 4);
|
||||
toReturn = new int[]{
|
||||
(bitLine & 0xff000000) >>> 24,
|
||||
(bitLine & 0x00ff0000) >>> 16,
|
||||
(bitLine & 0x0000ff00) >>> 8,
|
||||
(bitLine & 0x000000ff),
|
||||
(bitLine2 & 0xff000000) >>> 24,
|
||||
(bitLine2 & 0x00ff0000) >>> 16,
|
||||
(bitLine2 & 0x0000ff00) >>> 8,
|
||||
(bitLine2 & 0x000000ff)
|
||||
};
|
||||
break;
|
||||
}
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
public static void byteCodePrint(String destinationPath, CodeIterator codeIterator) throws FileNotFoundException, BadBytecode {
|
||||
Path printPath = Paths.get(destinationPath);
|
||||
PrintWriter out = new PrintWriter(printPath.toFile());
|
||||
final String[] instructionOut = {""};
|
||||
codeIterator.begin();
|
||||
while (codeIterator.hasNext()) {
|
||||
int index = codeIterator.next();
|
||||
int[] instruction = getInstruction(codeIterator.lookAhead() - index, index, codeIterator);
|
||||
instructionOut[0] += Integer.toString(index);
|
||||
instructionOut[0] += " ";
|
||||
instructionOut[0] += Mnemonic.OPCODE[instruction[0]];
|
||||
if (instruction.length > 1) {
|
||||
instructionOut[0] += " ";
|
||||
IntStream.range(1, instruction.length)
|
||||
.forEach(value -> {
|
||||
instructionOut[0] += Integer.toString(instruction[value]);
|
||||
instructionOut[0] += " ";
|
||||
});
|
||||
}
|
||||
out.println(instructionOut[0]);
|
||||
instructionOut[0] = "";
|
||||
}
|
||||
out.close();
|
||||
}
|
||||
|
||||
static void printArrayToHex(Object[] obj, String name, Logger logger){
|
||||
int length = obj.length;
|
||||
int[] c = new int[length];
|
||||
for (int i=0;i<length;i++){
|
||||
c[i]=(int)obj[i];
|
||||
}
|
||||
String[] a = new String[length];
|
||||
for (int i=0;i<length;i++){
|
||||
a[i]=String.format("%02X", c[i] & 0xff);
|
||||
}
|
||||
logger.log(Level.INFO,name + " : " + Arrays.toString(a));
|
||||
}
|
||||
|
||||
// BDEW EXTRAS
|
||||
public static void putInteger(ConstPool cp, Bytecode code, int val) {
|
||||
switch (val) {
|
||||
case -1:
|
||||
code.add(Bytecode.ICONST_M1);
|
||||
break;
|
||||
case 0:
|
||||
code.add(Bytecode.ICONST_0);
|
||||
break;
|
||||
case 1:
|
||||
code.add(Bytecode.ICONST_1);
|
||||
break;
|
||||
case 2:
|
||||
code.add(Bytecode.ICONST_2);
|
||||
break;
|
||||
case 3:
|
||||
code.add(Bytecode.ICONST_3);
|
||||
break;
|
||||
case 4:
|
||||
code.add(Bytecode.ICONST_4);
|
||||
break;
|
||||
case 5:
|
||||
code.add(Bytecode.ICONST_5);
|
||||
break;
|
||||
default:
|
||||
if (val >= Byte.MIN_VALUE && val <= Byte.MAX_VALUE) {
|
||||
code.add(Bytecode.BIPUSH);
|
||||
code.add(val);
|
||||
} else if (val >= Short.MIN_VALUE && val <= Short.MAX_VALUE) {
|
||||
code.add(Bytecode.SIPUSH);
|
||||
code.add(val >> 8 & 0xFF, val & 0xFF);
|
||||
} else {
|
||||
code.addLdc(cp.addIntegerInfo(val));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static int getInteger(ConstPool cp, CodeIterator iterator, int pos) {
|
||||
int op = iterator.byteAt(pos);
|
||||
switch (op) {
|
||||
case Bytecode.ICONST_M1:
|
||||
return -1;
|
||||
case Bytecode.ICONST_0:
|
||||
return 0;
|
||||
case Bytecode.ICONST_1:
|
||||
return 1;
|
||||
case Bytecode.ICONST_2:
|
||||
return 2;
|
||||
case Bytecode.ICONST_3:
|
||||
return 3;
|
||||
case Bytecode.ICONST_4:
|
||||
return 4;
|
||||
case Bytecode.ICONST_5:
|
||||
return 5;
|
||||
case Bytecode.BIPUSH:
|
||||
return iterator.byteAt(pos + 1);
|
||||
case Bytecode.SIPUSH:
|
||||
return iterator.s16bitAt(pos + 1);
|
||||
case Bytecode.LDC:
|
||||
return cp.getIntegerInfo(iterator.byteAt(pos + 1));
|
||||
case Bytecode.LDC_W:
|
||||
return cp.getIntegerInfo(iterator.u16bitAt(pos + 1));
|
||||
default:
|
||||
throw new RuntimeException(String.format("Failed to decode integer. Pos = %d, Bytecode = %d", pos, op));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,11 +5,11 @@ import javassist.CannotCompileException;
|
||||
import javassist.ClassPool;
|
||||
import javassist.NotFoundException;
|
||||
import javassist.bytecode.BadBytecode;
|
||||
import net.bdew.wurm.tools.server.ModTitles;
|
||||
|
||||
public class CustomTitles {
|
||||
public static Titles.Title GremlinSlayer;
|
||||
public static int GREMLIN_SLAYER = 704;
|
||||
public static void register(ClassPool cp) throws NotFoundException, BadBytecode, CannotCompileException {
|
||||
TitleInjector injector = new TitleInjector(cp);
|
||||
injector.addTitle("GremlinSlayer", 704, "Gremlin Slayer", "Gremlin Slayer", -1, "NORMAL");
|
||||
ModTitles.addTitle(GREMLIN_SLAYER, "Gremlin Slayer", "Gremlin Slayer", -1, "NORMAL");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,223 +0,0 @@
|
||||
package mod.sin.wyvern.mastercraft;
|
||||
|
||||
import com.wurmonline.server.skills.SkillList;
|
||||
import javassist.*;
|
||||
import javassist.bytecode.*;
|
||||
|
||||
import org.gotti.wurmunlimited.modloader.classhooks.CodeReplacer;
|
||||
import org.gotti.wurmunlimited.modloader.classhooks.HookManager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
class ExtendTitleEnum {
|
||||
|
||||
private final String className;
|
||||
private final int valuesSizerIndex; // the bytecode index which puts a size specifying value on the stack for anewarray.
|
||||
private final int populateVALUESIndex; // the bytecode index where references to various enum instances are put in the $VALUES array.
|
||||
private final ConstPool constPool;
|
||||
|
||||
private static ArrayList<EnumFields> toExtendEntries = new ArrayList<>();
|
||||
private static ExtendTitleEnum singletonInstance;
|
||||
|
||||
private ExtendTitleEnum(String className, int valuesSizerIndex, int populateVALUESIndex, ConstPool constPool) {
|
||||
this.className = className;
|
||||
this.valuesSizerIndex = valuesSizerIndex;
|
||||
this.populateVALUESIndex = populateVALUESIndex;
|
||||
this.constPool = constPool;
|
||||
}
|
||||
|
||||
/**
|
||||
* Goes through the enum class's initiator to find bytecode index positions.
|
||||
*
|
||||
* @throws BadBytecode forwarded, Javassist stuff.
|
||||
*/
|
||||
static void builder(String className) throws BadBytecode, NotFoundException {
|
||||
int valuesSizerIndex = -1;
|
||||
//int indexANEWARRAY = -1;
|
||||
int populateVALUESIndex = -1;
|
||||
CtClass ctClassEnum = HookManager.getInstance().getClassPool().get(className);
|
||||
ConstPool constPool = ctClassEnum.getClassFile().getConstPool();
|
||||
CodeIterator codeIterator = ctClassEnum.getClassInitializer().getMethodInfo().getCodeAttribute().iterator();
|
||||
// Get the byte code instruction index for
|
||||
// 1) size value for ANEWARRAY,
|
||||
// 2) the VALUES array assignment or population.
|
||||
BytecodeTools b = new BytecodeTools(constPool);
|
||||
String valuesDescriptor = className.replace(".", "/");
|
||||
valuesDescriptor = "[L" + valuesDescriptor + ";";
|
||||
int constPoolValuesIndex = b.findFieldIndex(Opcode.PUTSTATIC, "$VALUES",
|
||||
valuesDescriptor, className);
|
||||
codeIterator.begin();
|
||||
int lastIndex = 0;
|
||||
while (codeIterator.hasNext()){
|
||||
int instructionIndex = codeIterator.next();
|
||||
int opCode = codeIterator.byteAt(instructionIndex);
|
||||
switch (opCode){
|
||||
case Opcode.ANEWARRAY :
|
||||
valuesSizerIndex = lastIndex;
|
||||
//indexANEWARRAY = instructionIndex;
|
||||
break;
|
||||
case Opcode.PUTSTATIC :
|
||||
int cpAddress = codeIterator.u16bitAt(instructionIndex+1);
|
||||
if (cpAddress == constPoolValuesIndex){
|
||||
populateVALUESIndex = instructionIndex;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
lastIndex = instructionIndex;
|
||||
}
|
||||
|
||||
synchronized (ExtendTitleEnum.class) {
|
||||
singletonInstance = new ExtendTitleEnum(className, valuesSizerIndex, populateVALUESIndex, constPool);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static ExtendTitleEnum getSingletonInstance() {
|
||||
return singletonInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* A method to create data structures and add record a reference for that object.
|
||||
*
|
||||
* @param fieldName the name for the enum entry.
|
||||
* @param titleId an ordinal for the Titles.Title enum.
|
||||
* @param maleName in-game title name for male toons.
|
||||
* @param femaleName in-game title name for femaleName toons.
|
||||
* @param skillId A id number for the skill associated with the title, see {@link SkillList}
|
||||
* @param titleTypes A string representation of entries in {@link com.wurmonline.server.players.Titles.TitleType}. In
|
||||
* order to avoid premature class initialization for Javassist's bytecode stages we use a string
|
||||
* instead of the WU object. The string must match one of the enum field names.
|
||||
*/
|
||||
synchronized void addExtendEntry(String fieldName, int titleId, String maleName, String femaleName, int skillId, String titleTypes) {
|
||||
if (singletonInstance == null) {
|
||||
throw new RuntimeException("ExtendTitleEnum instance is null, build it before addExtendEntry");
|
||||
}
|
||||
EnumFields enumFields = new EnumFields(fieldName, titleId, maleName, femaleName, skillId, titleTypes);
|
||||
toExtendEntries.add(enumFields);
|
||||
}
|
||||
|
||||
class EnumFields {
|
||||
final String fieldName;
|
||||
final int titleId;
|
||||
final String maleName;
|
||||
final String femaleName;
|
||||
final int skillId;
|
||||
final String titleTypes;
|
||||
|
||||
/**
|
||||
* @param fieldName the name for the enum entry.
|
||||
* @param titleId an ordinal for the Titles.Title enum.
|
||||
* @param maleName in-game title name for male toons.
|
||||
* @param femaleName in-game title name for femaleName toons.
|
||||
* @param skillId A id number for the skill associated with the title, see {@link SkillList}
|
||||
* @param titleTypes A string representation of entries in {@link com.wurmonline.server.players.Titles.TitleType}. In
|
||||
* order to avoid premature class initialization for Javassist's bytecode stages we use a string
|
||||
* instead of the WU object.
|
||||
**/
|
||||
EnumFields(String fieldName, int titleId, String maleName, String femaleName,
|
||||
int skillId, String titleTypes){
|
||||
this.fieldName = fieldName;
|
||||
this.titleId = titleId;
|
||||
this.maleName = maleName;
|
||||
this.femaleName = femaleName;
|
||||
this.skillId = skillId;
|
||||
this.titleTypes = titleTypes;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Intended to be used in WurmServerMod-initiate section and it's for bytecode changes. This adds field objects to the enum class.
|
||||
*
|
||||
* @throws CannotCompileException forwarded, Javassist stuff.
|
||||
*/
|
||||
private synchronized void createFieldsInEnum() throws CannotCompileException, NotFoundException {
|
||||
if (toExtendEntries.size() == 0){
|
||||
throw new RuntimeException("Can not extend an enum without values in toExtendEntries arrayList.");
|
||||
}
|
||||
|
||||
CtClass enumCtClass = HookManager.getInstance().getClassPool().get(this.className);
|
||||
for (EnumFields enumData : toExtendEntries) {
|
||||
CtField field = new CtField(enumCtClass, enumData.fieldName, enumCtClass);
|
||||
field.setModifiers(Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL | Modifier.ENUM);
|
||||
enumCtClass.addField(field);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method uses JA bytecode to inject into the Enum's class initiator in order to expand the enum's $VALUES field.
|
||||
*
|
||||
* @throws BadBytecode forwarded, Javassist stuff.
|
||||
*/
|
||||
private void resizeEnumVALUES() throws BadBytecode, ClassNotFoundException, NotFoundException {
|
||||
int expansion = toExtendEntries.size();
|
||||
CtClass ctClassEnum = HookManager.getInstance().getClassPool().get(this.className);
|
||||
CodeIterator codeIterator = ctClassEnum.getClassInitializer().getMethodInfo().getCodeAttribute().iterator();
|
||||
|
||||
BytecodeTools findBytecode = new BytecodeTools(this.constPool);
|
||||
int currentSize = findBytecode.getInteger(codeIterator, this.valuesSizerIndex);
|
||||
findBytecode.addInteger(currentSize);
|
||||
findBytecode.addOpcode(Opcode.ANEWARRAY);
|
||||
findBytecode.addClassIndex(this.className);
|
||||
|
||||
BytecodeTools replaceBytecode = new BytecodeTools(this.constPool);
|
||||
replaceBytecode.addInteger(currentSize + expansion);
|
||||
replaceBytecode.addOpcode(Opcode.ANEWARRAY);
|
||||
replaceBytecode.addClassIndex(this.className);
|
||||
|
||||
CodeReplacer codeReplacer = new CodeReplacer(ctClassEnum.getClassInitializer().getMethodInfo().getCodeAttribute());
|
||||
codeReplacer.replaceCode(findBytecode.get(), replaceBytecode.get());
|
||||
}
|
||||
|
||||
/**
|
||||
* This method builds bytecode to inject into the enum's initiator. The injected code initializes new enum entries and adds
|
||||
* a reference of that new object to the $VALUES array.
|
||||
*
|
||||
* @throws BadBytecode forwarded, JA stuff.
|
||||
* @throws ClassNotFoundException forwarded, JA stuff.
|
||||
* @throws NotFoundException forwarded, JA stuff.
|
||||
*/
|
||||
synchronized void ExtendEnumEntries() throws BadBytecode, ClassNotFoundException, NotFoundException, CannotCompileException {
|
||||
createFieldsInEnum();
|
||||
CtClass ctClassEnum = HookManager.getInstance().getClassPool().get(this.className);
|
||||
CodeIterator initiatorCodeIterator = ctClassEnum.getClassInitializer().getMethodInfo().getCodeAttribute().iterator();
|
||||
|
||||
BytecodeTools enumInitiator = new BytecodeTools(ctClassEnum.getClassFile().getConstPool());
|
||||
BytecodeTools populateVALUES = new BytecodeTools(ctClassEnum.getClassFile().getConstPool());
|
||||
int extensionCounter = 0;
|
||||
int valuesSize = enumInitiator.getInteger(initiatorCodeIterator, this.valuesSizerIndex);
|
||||
// Construct the two bytecode objects to be inserted. The multiple enumData in toExtendEntries are combined into one
|
||||
// long bytecode sequence and inserted at the proper point.
|
||||
for (EnumFields enumData : toExtendEntries) {
|
||||
enumInitiator.addOpcode(Opcode.NEW);
|
||||
enumInitiator.findClassIndex(this.className);
|
||||
enumInitiator.addOpcode(Opcode.DUP);
|
||||
enumInitiator.addLdc(enumData.fieldName);
|
||||
enumInitiator.addInteger(valuesSize + extensionCounter);
|
||||
enumInitiator.addInteger(enumData.titleId);
|
||||
enumInitiator.addLdc(enumData.maleName);
|
||||
enumInitiator.addLdc(enumData.femaleName);
|
||||
enumInitiator.addInteger(enumData.skillId);
|
||||
enumInitiator.addFieldIndex(Opcode.GETSTATIC, enumData.titleTypes,
|
||||
"Lcom/wurmonline/server/players/Titles$TitleType;",
|
||||
"com/wurmonline/server/players/Titles$TitleType");
|
||||
enumInitiator.addMethodIndex(Opcode.INVOKESPECIAL, "<init>",
|
||||
"(Ljava/lang/String;IILjava/lang/String;Ljava/lang/String;ILcom/wurmonline/server/players/Titles$TitleType;)V",
|
||||
this.className);
|
||||
enumInitiator.addFieldIndex(Opcode.PUTSTATIC, enumData.fieldName, "Lcom/wurmonline/server/players/Titles$Title;",
|
||||
this.className);
|
||||
|
||||
populateVALUES.addOpcode(Opcode.DUP);
|
||||
populateVALUES.addInteger(valuesSize + extensionCounter);
|
||||
extensionCounter++;
|
||||
populateVALUES.findFieldIndex(Opcode.GETSTATIC, enumData.fieldName, "Lcom/wurmonline/server/players/Titles$Title;",
|
||||
this.className);
|
||||
populateVALUES.addOpcode(Opcode.AASTORE);
|
||||
}
|
||||
// Do bytecode changes from the bottom up so bytecode indexes don't change after every insert.
|
||||
initiatorCodeIterator.insert(populateVALUESIndex, populateVALUES.get());
|
||||
resizeEnumVALUES();
|
||||
initiatorCodeIterator.insert(valuesSizerIndex, enumInitiator.get());
|
||||
}
|
||||
}
|
||||
@@ -1,271 +0,0 @@
|
||||
package mod.sin.wyvern.mastercraft;
|
||||
|
||||
import com.wurmonline.server.Server;
|
||||
import com.wurmonline.server.items.Item;
|
||||
import com.wurmonline.server.players.Titles;
|
||||
import com.wurmonline.server.skills.Skill;
|
||||
import com.wurmonline.server.skills.SkillList;
|
||||
import javassist.*;
|
||||
import javassist.bytecode.BadBytecode;
|
||||
import javassist.expr.ExprEditor;
|
||||
import javassist.expr.MethodCall;
|
||||
import mod.sin.lib.Util;
|
||||
import org.gotti.wurmunlimited.modloader.ReflectionUtil;
|
||||
import org.gotti.wurmunlimited.modloader.classhooks.HookManager;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class Mastercraft {
|
||||
private static Logger logger = Logger.getLogger(Mastercraft.class.getName());
|
||||
public static double getNewDifficulty(Skill skill, double diff, Item item){
|
||||
if(skill.affinity > 0){
|
||||
diff -= skill.affinity;
|
||||
}
|
||||
if(skill.getKnowledge() > 99.0d){
|
||||
diff -= 8d-((100d-skill.getKnowledge())*8d);
|
||||
}
|
||||
if(skill.getKnowledge() > 90.0d){
|
||||
diff -= 2d-((100d-skill.getKnowledge())*0.2d);
|
||||
}
|
||||
if(item != null){
|
||||
if(item.getRarity() > 0){
|
||||
diff -= item.getRarity();
|
||||
}
|
||||
if(item.getCurrentQualityLevel() > 99.0f){
|
||||
diff -= 3d-((100d-item.getCurrentQualityLevel())*3d);
|
||||
}
|
||||
if(item.getCurrentQualityLevel() > 90.0f){
|
||||
diff -= 1d-((100d-item.getCurrentQualityLevel())*0.1d);
|
||||
}
|
||||
}
|
||||
return diff;
|
||||
}
|
||||
public static float getCastPowerIncrease(Skill skill){
|
||||
double addedPower = 0;
|
||||
if(skill.affinity > 0){
|
||||
addedPower += 2*skill.affinity;
|
||||
}
|
||||
if(skill.getKnowledge() > 0){
|
||||
float lowFloat1 = Math.min(Server.rand.nextFloat(), Server.rand.nextFloat());
|
||||
float lowFloat2 = Math.min(Server.rand.nextFloat(), Server.rand.nextFloat());
|
||||
addedPower += Math.min(skill.getKnowledge()*lowFloat1, skill.getKnowledge()*lowFloat2);
|
||||
}else{
|
||||
logger.warning("Error: Some player just tried casting with no channeling skill!");
|
||||
}
|
||||
return (float) addedPower;
|
||||
}
|
||||
public static float getFavorCostMultiplier(Skill skill){
|
||||
float mult = 1f;
|
||||
if(skill.affinity > 0){
|
||||
mult -= skill.affinity*0.02f; //2% reduction per affinity
|
||||
}
|
||||
if(skill.getKnowledge() > 90d){
|
||||
mult -= 0.1d-((100d-skill.getKnowledge())*0.01d);
|
||||
}
|
||||
if(skill.getKnowledge() > 99d){
|
||||
mult -= 0.1d-((100-skill.getKnowledge())*0.1d);
|
||||
}
|
||||
return mult;
|
||||
}
|
||||
public static void addNewTitles(){
|
||||
try {
|
||||
ExtendTitleEnum.builder("com.wurmonline.server.players.Titles$Title");
|
||||
// GM/Developer Titles
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Game_Master", 500, "Game Master", "Game Master", -1, "NORMAL");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Developer", 501, "Developer", "Developer", -1, "NORMAL");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Pet_Me", 502, "Pet Me", "Pet Me", -1, "NORMAL");
|
||||
|
||||
// Troll Titles
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Macro_King", 550, "Macro King", "Macro King", -1, "NORMAL");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Drama_Queen", 551, "Drama Queen", "Drama Queen", -1, "NORMAL");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Zergling", 552, "Zergling", "Zergling", -1, "NORMAL");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Special_Title", 553, "Special Guy", "Special Girl", -1, "NORMAL");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Prophet_Ear", 554, "Prophet Ear", "Prophet Ear", -1, "NORMAL");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Koza", 555, "Koza", "Koza", -1, "NORMAL");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Wyvern_Hunter", 556, "Wyvern Hunter", "Wyvern Hunter", -1, "NORMAL");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Overlord", 557, "Overlord", "Overlord", -1, "NORMAL");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Troll", 558, "Troll", "Troll", -1, "NORMAL");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Beggar", 559, "Beggar", "Beggar", -1, "NORMAL");
|
||||
|
||||
// Contest Titles
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Home_Decorator", 600, "Home Decorator", "Home Decorator", -1, "NORMAL");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Arena_Champion", 601, "Champion of the Arena", "Champion of the Arena", -1, "NORMAL");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Pastamancer", 602, "Pastamancer", "Pastamancer", -1, "NORMAL");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Pizzamancer", 603, "Pizzamancer", "Pizzamancer", -1, "NORMAL");
|
||||
|
||||
// Special Event Titles
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Titan_Slayer", 700, "Titanslayer", "Titanslayer", -1, "NORMAL");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Spectral_Slayer", 701, "Spectral Warrior", "Spectral Warrior", -1, "NORMAL");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Holdstrong_Architect", 702, "Holdstrong Architect", "Holdstrong Architect", -1, "NORMAL");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Stronghold_Architect", 703, "Stronghold Architect", "Stronghold Architect", -1, "NORMAL");
|
||||
//ExtendTitleEnum.getSingletonInstance().addExtendEntry("Gremlin_Slayer", 704, "Gremlin Slayer", "Gremlin Slayer", -1, "NORMAL");
|
||||
|
||||
// Donation titles
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Donator", 800, "Donator", "Donator", -1, "NORMAL");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Pazza_FavoriteGM", 801, "Sindusks Favourite GM", "Sindusks Favourite GM", -1, "NORMAL");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Warriorgen_ThatGuy", 802, "That Guy", "That Guy", -1, "NORMAL");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Eternallove_WarriorgensWife", 803, "Warriorgens Wife", "Warriorgens Wife", -1, "NORMAL");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Bambam_ThornOne", 804, "Thorn One", "Thorn One", -1, "NORMAL");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Svenja_CareDependant", 805, "The care-dependent", "The care-dependent", -1, "NORMAL");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Alexia_TheTreasuring", 806, "The Treasuring", "The Treasuring", -1, "NORMAL");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Reevi_ScienceGuy", 807, "Science Guy", "Science Guy", -1, "NORMAL");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Genocide_GrandDesigner", 808, "Grand Designer", "Grand Designer", -1, "NORMAL");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Seleas_CrazyCatLord", 809, "The Crazy Cat Lord", "The Crazy Cat Lord", -1, "NORMAL");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Piratemax_Slave", 810, "Slave", "Slave", -1, "NORMAL");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Eltacolad_TrueTaco", 811, "The One True Taco", "The One True Taco", -1, "NORMAL");
|
||||
|
||||
// Characteristic Titles
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("MindLogic_Normal", 1000, "Logical", "Logical", 100, "NORMAL");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("MindLogic_Minor", 1001, "Intelligent", "Intelligent", 100, "MINOR");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("MindLogic_Master", 1002, "Brilliant", "Brilliant", 100, "MASTER");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("MindLogic_Legendary", 1003, "Mentalist", "Mentalist", 100, "LEGENDARY");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("MindSpeed_Normal", 1004, "Keen", "Keen", 101, "NORMAL");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("MindSpeed_Minor", 1005, "Thinker", "Thinker", 101, "MINOR");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("MindSpeed_Master", 1006, "Clever", "Clever", 101, "MASTER");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("MindSpeed_Legendary", 1007, "Mind Over Matter", "Mind Over Matter", 101, "LEGENDARY");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("BodyStrength_Normal", 1008, "Strong", "Strong", 102, "NORMAL");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("BodyStrength_Minor", 1009, "Fortified", "Fortified", 102, "MINOR");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("BodyStrength_Master", 1010, "Unyielding", "Unyielding", 102, "MASTER");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("BodyStrength_Legendary", 1011, "Force of Nature", "Force of Nature", 102, "LEGENDARY");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("BodyStamina_Normal", 1012, "Enduring", "Enduring", 103, "NORMAL");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("BodyStamina_Minor", 1013, "Resilient", "Resilient", 103, "MINOR");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("BodyStamina_Master", 1014, "Vigorous", "Vigorous", 103, "MASTER");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("BodyStamina_Legendary", 1015, "Unstoppable", "Unstoppable", 103, "LEGENDARY");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("BodyControl_Normal", 1016, "Nimble", "Nimble", 104, "NORMAL");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("BodyControl_Minor", 1017, "Deft", "Deft", 104, "MINOR");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("BodyControl_Master", 1018, "Skillful", "Skillful", 104, "MASTER");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("BodyControl_Legendary", 1019, "Manipulator", "Manipulator", 104, "LEGENDARY");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("SoulStrength_Normal", 1020, "Spirited", "Spirited", 105, "NORMAL");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("SoulStrength_Minor", 1021, "Diviner", "Diviner", 105, "MINOR");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("SoulStrength_Master", 1022, "Anima", "Anima", 105, "MASTER");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("SoulStrength_Legendary", 1023, "Prophet", "Prophet", 105, "LEGENDARY");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("SoulDepth_Normal", 1024, "Sensible", "Sensible", 106, "NORMAL");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("SoulDepth_Minor", 1025, "Medium", "Medium", 106, "MINOR");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("SoulDepth_Master", 1026, "Spiritual", "Spiritual", 106, "MASTER");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("SoulDepth_Legendary", 1027, "Planewalker", "Planewalker", 106, "LEGENDARY");
|
||||
|
||||
// Skill Titles (Full)
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Staff_Normal", 1100, "Acolyte", "Acolyte", 10090, "NORMAL");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Staff_Minor", 1101, "Disciple", "Disciple", 10090, "MINOR");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Staff_Master", 1102, "Monk", "Monk", 10090, "MASTER");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Staff_Legendary", 1103, "Sensei", "Sensei", 10090, "LEGENDARY");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Scythe_Normal", 1104, "Mower", "Mower", 10047, "NORMAL");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Scythe_Minor", 1105, "Harvester", "Harvester", 10047, "MINOR");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Scythe_Master", 1106, "Scythian", "Scythian", 10047, "MASTER");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Scythe_Legendary", 1107, "Reaper", "Reaper", 10047, "LEGENDARY");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Defensive_Normal", 1108, "Resistant", "Resistant", 10054, "NORMAL");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Defensive_Minor", 1109, "Guardian", "Guardian", 10054, "MINOR");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Defensive_Master", 1110, "Bulwark", "Bulwark", 10054, "MASTER");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Defensive_Legendary", 1111, "Unbreakable", "Unbreakable", 10054, "LEGENDARY");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Aggressive_Normal", 1112, "Angry", "Angry", 10053, "NORMAL");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Aggressive_Minor", 1113, "Violent", "Violent", 10053, "MINOR");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Aggressive_Master", 1114, "Battleborn", "Battleborn", 10053, "MASTER");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Aggressive_Legendary", 1115, "Warmonger", "Warmonger", 10053, "LEGENDARY");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Normal_Normal", 1116, "Infantry", "Infantry", 10055, "NORMAL");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Normal_Minor", 1117, "Marauder", "Marauder", 10055, "MINOR");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Normal_Master", 1118, "Gladiator", "Gladiator", 10055, "MASTER");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Normal_Legendary", 1119, "Templar", "Templar", 10055, "LEGENDARY");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Weaponless_Normal", 1120, "Scrapper", "Scrapper", 10052, "NORMAL");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Weaponless_Minor", 1121, "Brawler", "Brawler", 10052, "MINOR");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Weaponless_Master", 1122, "Boxer", "Boxer", 10052, "MASTER");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Weaponless_Legendary", 1123, "Martial Artist", "Martial Artist", 10052, "LEGENDARY");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("BladesSmithing_Normal", 1124, "Bladesmith", "Bladesmith", SkillList.SMITHING_WEAPON_BLADES, "NORMAL");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("BladesSmithing_Minor", 1125, "Renowned Bladesmith", "Renowned Bladesmith", SkillList.SMITHING_WEAPON_BLADES, "MINOR");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("BladesSmithing_Master", 1126, "Master Bladesmith", "Master Bladesmith", SkillList.SMITHING_WEAPON_BLADES, "MASTER");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("BladesSmithing_Legendary", 1127, "Legendary Bladesmith", "Legendary Bladesmith", SkillList.SMITHING_WEAPON_BLADES, "LEGENDARY");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("HeadSmithing_Normal", 1128, "Headsmither", "Headsmither", SkillList.SMITHING_WEAPON_HEADS, "NORMAL");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("HeadSmithing_Minor", 1129, "Renowned Headsmither", "Renowned Headsmither", SkillList.SMITHING_WEAPON_HEADS, "MINOR");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("HeadSmithing_Master", 1130, "Master Headsmither", "Master Headsmither", SkillList.SMITHING_WEAPON_HEADS, "MASTER");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("HeadSmithing_Legendary", 1131, "Legendary Headsmither", "Legendary Headsmither", SkillList.SMITHING_WEAPON_HEADS, "LEGENDARY");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Hatchet_Normal", 1132, "Hatcheter", "Hatcheter", SkillList.HATCHET, "NORMAL");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Hatchet_Minor", 1133, "Renowned Hatcheter", "Renowned Hatcheter", SkillList.HATCHET, "MINOR");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Hatchet_Master", 1134, "Master Hatcheter", "Master Hatcheter", SkillList.HATCHET, "MASTER");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Hatchet_Legendary", 1135, "Hatchslinging Slasher", "Hatchslinging Slasher", SkillList.HATCHET, "LEGENDARY");
|
||||
|
||||
// Skill Titles (100)
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Archery_Legendary", 1500, "Legendary Marksman", "Legendary Marksman", 1030, "LEGENDARY");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Body_Legendary", 1501, "Hercules", "Hercules", 1, "LEGENDARY");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Axes_Legendary", 1502, "Viking", "Viking", 1003, "LEGENDARY");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Baking_Legendary", 1503, "Patissier", "Patissier", 10039, "LEGENDARY");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Archaeology_Legendary", 1504, "Curator", "Curator", 10069, "LEGENDARY");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("CarvingKnife_Legendary", 1505, "Woodsculptor", "Woodsculptor", 10007, "LEGENDARY");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Taming_Legendary", 1506, "King of the Jungle", "Queen of the Jungle", 10078, "LEGENDARY");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Climbing_Legendary", 1507, "Moonwalker", "Moonwalker", 10073, "LEGENDARY");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Tracking_Legendary", 1508, "Bloodhound", "Bloodhound", 10018, "LEGENDARY");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Clubs_Legendary", 1509, "Bam Bam", "Bam Bam", 1025, "LEGENDARY");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Catapults_Legendary", 1510, "Castle Crasher", "Castle Crasher", 10077, "LEGENDARY");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Firemaking_Legendary", 1511, "Incendiary", "Incendiary", 1010, "LEGENDARY");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Gardening_Legendary", 1512, "Earthbound", "Earthbound", 10045, "LEGENDARY");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Hammers_Legendary", 1513, "Doomhammer", "Doomhammer", 1027, "LEGENDARY");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Locksmithing_Legendary", 1514, "Vault Smith", "Vault Smith", 10034, "LEGENDARY");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Religion_Legendary", 1515, "Chosen", "Chosen", 1026, "LEGENDARY");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Yoyo_Legendary", 1516, "String Theorist", "String Theorist", 10050, "LEGENDARY");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Nature_Legendary", 1517, "Naturalist", "Naturalist", 1019, "LEGENDARY");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Mind_Legendary", 1518, "Enlightened", "Enlightened", 2, "LEGENDARY");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Mauls_Legendary", 1519, "Breaker", "Breaker", 1004, "LEGENDARY");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Shipbuilding_Legendary", 1520, "Naval Engineer", "Naval Engineer", 10082, "LEGENDARY");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("NaturalSubstances_Legendary", 1521, "Biochemist", "Biochemist", 10042, "LEGENDARY");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("WarMachines_Legendary", 1522, "Eradicator", "Eradicator", 1029, "LEGENDARY");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Thievery_Legendary", 1523, "Shadow", "Shadow", 1028, "LEGENDARY");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Swords_Legendary", 1524, "Samurai", "Samurai", 1000, "LEGENDARY");
|
||||
ExtendTitleEnum.getSingletonInstance().addExtendEntry("Forestry_Legendary", 1525, "Silvanus", "Mother Nature", 10048, "LEGENDARY");
|
||||
ExtendTitleEnum.getSingletonInstance().ExtendEnumEntries();
|
||||
|
||||
} catch (BadBytecode | ClassNotFoundException | NotFoundException | CannotCompileException e) {
|
||||
logger.warning(e.getMessage());
|
||||
}
|
||||
}
|
||||
public static void changeExistingTitles(){
|
||||
for (Titles.Title title : Titles.Title.values()) {
|
||||
if (Objects.equals("Pumpkin King", title.getFemaleName())){
|
||||
try {
|
||||
ReflectionUtil.setPrivateField(title, ReflectionUtil.getField(title.getClass(), "femaleName"), "Pumpkin Queen");
|
||||
} catch (IllegalArgumentException | IllegalAccessException | ClassCastException | NoSuchFieldException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public static void preInit(){
|
||||
try {
|
||||
ClassPool classPool = HookManager.getInstance().getClassPool();
|
||||
Class<Mastercraft> thisClass = Mastercraft.class;
|
||||
|
||||
// - Reduce skill check difficulty with high skills or tools - //
|
||||
CtClass ctSkill = classPool.get("com.wurmonline.server.skills.Skill");
|
||||
|
||||
/*ctSkill.getDeclaredMethod("checkAdvance").insertBefore(""
|
||||
+ "$1 = "+Mastercraft.class.getName()+".getNewDifficulty(this, $1, $2);");*/
|
||||
Util.setReason("Modify difficulty for skill checks in MasterCraft.");
|
||||
String replace = "$1 = "+Mastercraft.class.getName()+".getNewDifficulty(this, $1, $2);";
|
||||
Util.insertBeforeDeclared(thisClass, ctSkill, "checkAdvance", replace);
|
||||
|
||||
// - Increase spellcasting power for skilled channelers - //
|
||||
CtClass ctSpell = classPool.get("com.wurmonline.server.spells.Spell");
|
||||
CtMethod[] ctRuns = ctSpell.getDeclaredMethods("run");
|
||||
for(CtMethod method : ctRuns){
|
||||
method.instrument(new ExprEditor(){
|
||||
public void edit(MethodCall m) throws CannotCompileException {
|
||||
if (m.getMethodName().equals("doEffect")) {
|
||||
m.replace("$2 += "+Mastercraft.class.getName()+".getCastPowerIncrease(castSkill);"
|
||||
+ "$_ = $proceed($$);");
|
||||
logger.info("Instrumented doEffect in run()");
|
||||
}
|
||||
}
|
||||
});
|
||||
method.instrument(new ExprEditor(){
|
||||
public void edit(MethodCall m) throws CannotCompileException {
|
||||
if (m.getMethodName().equals("depleteFavor")) {
|
||||
m.replace("$1 *= "+Mastercraft.class.getName()+".getFavorCostMultiplier(castSkill);"
|
||||
+ "$_ = $proceed($$);");
|
||||
logger.info("Instrumented depleteFavor in run()");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (CannotCompileException | NotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
package mod.sin.wyvern.mastercraft;
|
||||
|
||||
import javassist.ClassPool;
|
||||
import javassist.*;
|
||||
import javassist.bytecode.*;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class TitleInjector {
|
||||
private final CtClass titleCls;
|
||||
private final ConstPool constPool;
|
||||
private final CodeIterator codeIterator;
|
||||
private int insertPos = -1;
|
||||
private int lastOrd = -1;
|
||||
private int arraySizePos = -1;
|
||||
|
||||
|
||||
public TitleInjector(ClassPool classPool) throws NotFoundException, BadBytecode {
|
||||
titleCls = classPool.getCtClass("com.wurmonline.server.players.Titles$Title");
|
||||
CtConstructor initializer = titleCls.getClassInitializer();
|
||||
CodeAttribute codeAttr = initializer.getMethodInfo().getCodeAttribute();
|
||||
constPool = codeAttr.getConstPool();
|
||||
codeIterator = codeAttr.iterator();
|
||||
|
||||
BytecodeTools b = new BytecodeTools(constPool);
|
||||
|
||||
// My code needs a bit more stack space than javac-generated one
|
||||
codeAttr.setMaxStack(codeAttr.getMaxStack() + 3);
|
||||
|
||||
while (codeIterator.hasNext()) {
|
||||
int pos = codeIterator.next();
|
||||
int op = codeIterator.byteAt(pos);
|
||||
if (op == Bytecode.AASTORE) {
|
||||
insertPos = codeIterator.next();
|
||||
} else if (op == Bytecode.ANEWARRAY) {
|
||||
arraySizePos = pos - 2;
|
||||
} else if (op == Bytecode.NEW) {
|
||||
pos = codeIterator.next(); // dup
|
||||
pos = codeIterator.next(); // ldc of ident
|
||||
pos = codeIterator.next(); // here's the ordinal
|
||||
lastOrd = BytecodeTools.getInteger(constPool, codeIterator, pos);
|
||||
}
|
||||
}
|
||||
|
||||
if (insertPos == -1) throw new RuntimeException("Failed to find AASTORE");
|
||||
if (lastOrd == -1) throw new RuntimeException("Failed to find ordinals");
|
||||
if (arraySizePos == -1) throw new RuntimeException("Failed to array size position");
|
||||
}
|
||||
|
||||
public void saveDebug() throws IOException, CannotCompileException, NotFoundException {
|
||||
titleCls.writeFile();
|
||||
}
|
||||
|
||||
|
||||
public void addTitle(String ident, int id, String name, String femaleName, int skillId, String type) throws BadBytecode, CannotCompileException {
|
||||
int ordinal = ++lastOrd;
|
||||
Bytecode code = new Bytecode(constPool);
|
||||
|
||||
// When starting the values array is on stack, dup it for later use
|
||||
code.add(Bytecode.DUP);
|
||||
|
||||
// Put out ordinal, will be used by AASTORE
|
||||
BytecodeTools.putInteger(constPool, code, ordinal);
|
||||
|
||||
// Make new instance, and dupe that too
|
||||
code.addNew("com.wurmonline.server.players.Titles$Title");
|
||||
code.add(Bytecode.DUP);
|
||||
|
||||
// Put constructor parameters into stack
|
||||
code.addLdc(ident);
|
||||
BytecodeTools.putInteger(constPool, code, ordinal);
|
||||
BytecodeTools.putInteger(constPool, code, id);
|
||||
code.addLdc(name);
|
||||
code.addLdc(femaleName);
|
||||
BytecodeTools.putInteger(constPool, code, skillId);
|
||||
code.addGetstatic("com.wurmonline.server.players.Titles$TitleType", type, "Lcom/wurmonline/server/players/Titles$TitleType;");
|
||||
|
||||
// Call constructor, this will use one copy of our instance duped above, we need 2 more so dup it again
|
||||
code.addInvokespecial("com.wurmonline.server.players.Titles$Title", "<init>", "(Ljava/lang/String;IILjava/lang/String;Ljava/lang/String;ILcom/wurmonline/server/players/Titles$TitleType;)V");
|
||||
code.add(Bytecode.DUP);
|
||||
|
||||
// Put instance into static field - this will use the second copy of our instance
|
||||
code.addPutstatic("mod.sin.wyvern.mastercraft.CustomTitles", ident, "Lcom/wurmonline/server/players/Titles$Title;");
|
||||
|
||||
// And finally stick it into values array, this will use the duped array, ordinal and the final copy of our instance
|
||||
code.add(Bytecode.AASTORE);
|
||||
|
||||
// End of bytecode gen, insert it into the initializer
|
||||
byte[] bytes = code.get();
|
||||
codeIterator.insertAt(insertPos, bytes);
|
||||
insertPos += bytes.length;
|
||||
|
||||
// And increase array size
|
||||
codeIterator.write16bit(codeIterator.u16bitAt(arraySizePos) + 1, arraySizePos);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user