Skip to content
13 changes: 13 additions & 0 deletions asm-api/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
dependencies {
/* OW2 ASM v5.0.3 */
compileOnly('org.ow2.asm:asm-debug-all:5.0.3')

/* Google Guava v17.0 */
compileOnly('com.google.guava:guava:17.0')

/* Apache Commons Lang v3 */
compileOnly('org.apache.commons:commons-lang3:3.3.2')

/* Apache Log4J v2.0-beta9 */
compileOnly('org.apache.logging.log4j:log4j-api:2.0-beta9')
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package codes.biscuit.skyblockaddons.asm.api;

/**
* Listener to triggered actions by triggers that were injected using {@link Transformer}
*
* @author iHDeveloper
*/
public interface Hook {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package codes.biscuit.skyblockaddons.asm.api;

import codes.biscuit.skyblockaddons.asm.api.helper.TransformClassHelper;
import org.objectweb.asm.tree.ClassNode;

/**
* Transforming the targeted classes in order to change how the class behave.
* Or, injecting hooks triggers.
*
* @author iHDeveloper
*/
public abstract class Transformer {

/**
* Puts a single class helper into an array
*
* @param classHelper The class helper to put into an array
* @return An array containing single class helper
*/
protected TransformClassHelper[] single(TransformClassHelper classHelper) {
return new TransformClassHelper[] { classHelper };
}

/**
* Puts multiple class helpers into an array
* @param classHelpers The class helpers to put into an array
* @return An array containing multiple class helpers
*/
protected TransformClassHelper[] multiple(TransformClassHelper... classHelpers) {
return classHelpers;
}

/**
* Get the targeted class helpers
*
* @return An array of class helpers
*/
public abstract TransformClassHelper[] targets();

/**
* Transform a class node with its helper
*
* @param engine The engine which is performing the transformation process
* @param targetClassHelper The class helper of the target to transform
* @param node The class node of the target
*/
public abstract void transform(TransformerEngine engine, TransformClassHelper targetClassHelper, ClassNode node);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package codes.biscuit.skyblockaddons.asm.api;

import codes.biscuit.skyblockaddons.asm.api.helper.TransformClassHelper;
import codes.biscuit.skyblockaddons.asm.api.helper.normal.NormalTransformClassHelper;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import org.apache.commons.lang3.mutable.MutableInt;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.tree.ClassNode;

/**
* Manage the transformers and transform any class node.
*
* @author iHDeveloper
*/
public abstract class TransformerEngine {

private Logger logger = LogManager.getLogger("SBA: ASM Transformers");
private Multimap<String, Transformer> transformers = ArrayListMultimap.create();
private MutableInt writeFlags = new MutableInt();

/**
* Create an engine with transformers built-in
*
* @param transformers The transformers to register into the engine
*/
public TransformerEngine(Transformer[] transformers) {
for (Transformer transformer : transformers) {
register(transformer);
}
}

/**
* Check if the class name is a target for transformation
*
* @param name The class name
*/
public boolean exists(String name) {
return transformers.containsKey(name);
}

/**
* Transform the class node through the transformers
*
* @param node The class to transform
*/
public void transform(String name, ClassNode node) {
TransformClassHelper classHelper = new NormalTransformClassHelper(name);

writeFlags.setValue(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);

for (Transformer transformer : transformers.get(name)) {
transformer.transform(this, classHelper, node);
}
}

/**
* Get the engine logger
*
* @return The logger of the engine
*/
public Logger getLogger() {
return logger;
}

/**
* Set the write flags of the current class for the writer
*
* @param flags The flags for the class writer see {@link ClassWriter}
*/
public void setWriteFlags(int flags) {
writeFlags.setValue(flags);
}

/**
* Get the current write flags
*
* @return The write flags as integer
*/
public int getWriteFlags() {
return writeFlags.getValue();
}

/**
* Register a transformer with its targets
*
* @param transformer The transformer to register
*/
protected void register(Transformer transformer) {
for (TransformClassHelper targetClassHelper : transformer.targets()) {
transformers.put(targetClassHelper.getTransformerName(), transformer);
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package codes.biscuit.skyblockaddons.asm.api.helper;

/**
* A helper for getting result from hook to include in return or another function.
*
* @param <V> The type of the result we are getting from the hook
*
* @author iHDeveloper
*/
public class HookResult<V> {

private boolean empty = false;
private V value = null;

/**
* Check if the result is empty or not. Or, have the result been set before or not.
*
* @return Is the result empty or not
*/
public boolean is() {
return empty;
}

/**
* Set the result to be nothing but it's not empty!
*/
public void set() {
set(null);
}

/**
* Set the result to certain value. And, it's not empty anymore.
*
* @param value The value to include in the result
*/
public void set(V value) {
this.value = value;
this.empty = true;
}

/**
* Get the value from the result
*
* @return The value that's has been set by the hook
*/
public V get() {
return value;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package codes.biscuit.skyblockaddons.asm.api.helper;

import lombok.Getter;

/**
* An identifier for a class to transform
*
* @author iHDeveloper
*/
public abstract class TransformClassHelper {

/**
* @return The name used for the owner of a field or method, or a field type.
*/
public final String getNameAsOwner() {
return "L" + getName() + ";";
}

/**
* @return The name used to identify this class
*/
public String getTransformerName() {
// The regex matches single slash or multiple and replace them with one dot
return getName().replaceAll("(\\/)+", ".");
}

public boolean equals(TransformClassHelper classHelper) {
return getTransformerName().equals(classHelper.getTransformerName());
}

/**
* @return The raw name of the class
*/
public abstract String getName();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package codes.biscuit.skyblockaddons.asm.api.helper;

import lombok.Getter;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.FieldInsnNode;

/**
* An identifier for a field to transform
*
* @author iHDeveloper
*/
@Getter
public class TransformFieldHelper {

private final TransformClassHelper owner;
private final String name;
private String type;

/**
* Create a field helper to help the transformation process
*
* @param owner The owner of the field
* @param name The name of the field
* @param type A non-class field type {@link TransformFieldTypes}
*/
public TransformFieldHelper(TransformClassHelper owner, String name, char type) {
this(owner, name, "");
this.type = "" + type;
}

/**
* Create a field helper to help the transformation process
*
* @param owner The owner of the field
* @param name The name of the field
* @param type A class helper if the field type is class
*/
public TransformFieldHelper(TransformClassHelper owner, String name, TransformClassHelper type) {
this(owner, name, type.getNameAsOwner());
}

/**
* Create a field helper to help the transformation process
*
* @param owner The owner of the field
* @param name The name of the field
* @param type The raw name of the class
*/
public TransformFieldHelper(TransformClassHelper owner, String name, String type) {
this.owner = owner;
this.name = name;
this.type = "L" + type + ";";
}

/**
* Generate the get field instruction of the field
*
* @return An instruction node of the get field instruction
*/
public FieldInsnNode createGetInstruction() {
return new FieldInsnNode(Opcodes.GETFIELD, owner.getNameAsOwner(), name, type);
}

/**
* Generate the put instruction of the field
*
* @return An instruction node of the put field instruction
*/
public FieldInsnNode createPutInstruction() {
return new FieldInsnNode(Opcodes.PUTFIELD, owner.getNameAsOwner(), name, type);
}

public boolean equals(FieldInsnNode insnNode) {
return name.equals(insnNode.name) && type.equals(insnNode.desc);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package codes.biscuit.skyblockaddons.asm.api.helper;

public final class TransformFieldTypes {
public static final char BYTE = 'B';
public static final char CHAR = 'C';
public static final char DOUBLE = 'D';
public static final char FLOAT = 'F';
public static final char INT = 'I';
public static final char LONG = 'j';
public static final char SHORT = 'S';
public static final char BOOLEAN = 'Z';
}
Loading