mirror of
https://github.com/xfl03/MCCustomSkinLoader.git
synced 2026-11-11 23:07:31 +00:00
191 lines
7.6 KiB
Java
191 lines
7.6 KiB
Java
package customskinloader.forge;
|
|
|
|
import java.lang.annotation.ElementType;
|
|
import java.lang.annotation.Retention;
|
|
import java.lang.annotation.RetentionPolicy;
|
|
import java.lang.annotation.Target;
|
|
import java.util.HashMap;
|
|
import java.util.Map;
|
|
import java.util.function.Supplier;
|
|
|
|
import customskinloader.forge.platform.IFMLPlatform;
|
|
import org.objectweb.asm.commons.Remapper;
|
|
import org.objectweb.asm.tree.ClassNode;
|
|
import org.objectweb.asm.tree.MethodNode;
|
|
|
|
public class TransformerManager {
|
|
|
|
@Retention(RetentionPolicy.RUNTIME)
|
|
@Target(ElementType.TYPE)
|
|
public @interface TransformTarget {
|
|
String className();
|
|
|
|
String methodNameSrg() default "";
|
|
|
|
String[] methodNames() default {};
|
|
|
|
String desc() default "";
|
|
}
|
|
|
|
public interface IClassTransformer {
|
|
ClassNode transform(ClassNode cn);
|
|
}
|
|
|
|
public interface IMethodTransformer {
|
|
MethodNode transform(ClassNode cn, MethodNode mn);
|
|
}
|
|
|
|
public static boolean isDevelopmentEnvironment = false;
|
|
/** If true, match {@link TransformTarget#methodNames} if {@link TransformTarget#methodNameSrg} fails to match. */
|
|
public static boolean useDeobfName = false;
|
|
private final static Remapper remapper = IFMLPlatform.FMLPlatformInitializer.getPlatform().getRemapper();
|
|
|
|
public static String mapClassName(String name) {
|
|
return remapper.mapType(name);
|
|
}
|
|
|
|
public static String mapFieldName(String owner, String name, String desc) {
|
|
return remapper.mapFieldName(owner, name, desc);
|
|
}
|
|
|
|
public static String mapFieldDesc(String desc) {
|
|
return remapper.mapDesc(desc);
|
|
}
|
|
|
|
public static String mapMethodName(String owner, String name, String desc) {
|
|
return remapper.mapMethodName(owner, name, desc);
|
|
}
|
|
|
|
public static String mapMethodDesc(String desc) {
|
|
return remapper.mapMethodDesc(desc);
|
|
}
|
|
|
|
public static boolean checkClassName(String name, String deobfName) {
|
|
if (isDevelopmentEnvironment) {
|
|
return name.equals(deobfName);
|
|
} else {
|
|
return mapClassName(name).equals(deobfName);
|
|
}
|
|
}
|
|
|
|
public static boolean checkFieldName(String owner, String name, String desc, String srgName) {
|
|
if (isDevelopmentEnvironment) {
|
|
return mapFieldName(owner, srgName, desc).equals(name);
|
|
} else {
|
|
return mapFieldName(owner, name, desc).equals(srgName);
|
|
}
|
|
}
|
|
|
|
public static boolean checkFieldDesc(String desc, String deobfDesc) {
|
|
if (isDevelopmentEnvironment) {
|
|
return desc.equals(deobfDesc);
|
|
} else {
|
|
return mapFieldDesc(desc).equals(deobfDesc);
|
|
}
|
|
}
|
|
|
|
public static boolean checkMethodName(String owner, String name, String desc, String srgName) {
|
|
if (isDevelopmentEnvironment) {
|
|
return mapMethodName(owner, srgName, desc).equals(name);
|
|
} else {
|
|
return mapMethodName(owner, name, desc).equals(srgName);
|
|
}
|
|
}
|
|
|
|
public static boolean checkMethodDesc(String desc, String deobfDesc) {
|
|
if (isDevelopmentEnvironment) {
|
|
return desc.equals(deobfDesc);
|
|
} else {
|
|
return mapMethodDesc(desc).equals(deobfDesc);
|
|
}
|
|
}
|
|
|
|
public Map<String, IClassTransformer> classMap = new HashMap<>();
|
|
public Map<String, Map<Supplier<String>, IMethodTransformer>> srgMap = new HashMap<>();
|
|
public Map<String, Map<String, IMethodTransformer>> map = new HashMap<>();
|
|
|
|
public TransformerManager(IClassTransformer[] classTransformers, IMethodTransformer[] methodTransformers) {
|
|
for (IClassTransformer t : classTransformers) {
|
|
TransformTarget tt = this.getTransformTarget(t.getClass());
|
|
if (tt != null) {
|
|
addClassTransformer(tt.className(), t);
|
|
}
|
|
}
|
|
for (IMethodTransformer t : methodTransformers) {
|
|
TransformTarget tt = this.getTransformTarget(t.getClass());
|
|
if (tt != null) {
|
|
addMethodTransformer(tt, tt.className(), t);
|
|
}
|
|
}
|
|
}
|
|
|
|
private TransformTarget getTransformTarget(Class<?> cl) {
|
|
ForgeTweaker.logger.info("[CSL DEBUG] REGISTERING TRANSFORMER %s", cl.getName());
|
|
if (!cl.isAnnotationPresent(TransformTarget.class)) {
|
|
ForgeTweaker.logger.info("[CSL DEBUG] ERROR occurs while parsing Annotation");
|
|
return null;
|
|
}
|
|
return cl.getAnnotation(TransformTarget.class);
|
|
}
|
|
|
|
private void addClassTransformer(String className, IClassTransformer transformer) {
|
|
if (!classMap.containsKey(className)) {
|
|
classMap.put(className, transformer);
|
|
ForgeTweaker.logger.info("[CSL DEBUG] REGISTERING CLASS %s", className);
|
|
}
|
|
}
|
|
|
|
private void addMethodTransformer(TransformTarget target, String className, IMethodTransformer transformer) {
|
|
if (!srgMap.containsKey(className)) {
|
|
srgMap.put(className, new HashMap<>());
|
|
}
|
|
if (!target.methodNameSrg().equals("")) {
|
|
// FMLDeobfRemapper has not been setup when this line being reached.
|
|
Supplier<String> mappedMethod = () -> (isDevelopmentEnvironment ? mapMethodName(className.replace(".", "/"), target.methodNameSrg(), target.desc()) : target.methodNameSrg()) + target.desc();
|
|
srgMap.get(className).put(mappedMethod, transformer);
|
|
ForgeTweaker.logger.info("[CSL DEBUG] REGISTERING SRG METHOD %s::%s", className, target.methodNameSrg() + target.desc());
|
|
}
|
|
if (!map.containsKey(className))
|
|
map.put(className, new HashMap<>());
|
|
for (String methodName : target.methodNames()) {
|
|
map.get(className).put(methodName + target.desc(), transformer);
|
|
ForgeTweaker.logger.info("[CSL DEBUG] REGISTERING METHOD %s::%s", className, methodName + target.desc());
|
|
}
|
|
}
|
|
|
|
public ClassNode transform(ClassNode classNode, String className) {
|
|
IClassTransformer transformer = classMap.get(className);
|
|
if (transformer != null) {
|
|
try {
|
|
classNode = transformer.transform(classNode);
|
|
ForgeTweaker.logger.info("[CSL DEBUG] Successfully transformed class %s", className);
|
|
} catch (Exception e) {
|
|
ForgeTweaker.logger.warning("[CSL DEBUG] An error happened when transforming class %s", className);
|
|
ForgeTweaker.logger.warning(e);
|
|
}
|
|
}
|
|
return classNode;
|
|
}
|
|
|
|
public MethodNode transform(ClassNode classNode, MethodNode methodNode, String className, String methodName, String methodDesc) {
|
|
String methodTarget = methodName + methodDesc;
|
|
Map<Supplier<String>, IMethodTransformer> transSrgMap = srgMap.get(className);
|
|
IMethodTransformer transformer = transSrgMap == null ? null : transSrgMap.get(transSrgMap.keySet().stream().filter(s -> s.get().equals(methodTarget)).findFirst().orElse(null));
|
|
|
|
Map<String, IMethodTransformer> transMap = map.get(className);
|
|
if (useDeobfName && transMap != null && transformer == null) {
|
|
transformer = transMap.get(methodTarget);
|
|
}
|
|
if (transformer != null) {
|
|
try {
|
|
methodNode = transformer.transform(classNode, methodNode);
|
|
ForgeTweaker.logger.info("[CSL DEBUG] Successfully transformed method %s in class %s", methodName, className);
|
|
} catch (Exception e) {
|
|
ForgeTweaker.logger.warning("[CSL DEBUG] An error happened when transforming method %s in class %s", methodTarget, className);
|
|
ForgeTweaker.logger.warning(e);
|
|
}
|
|
}
|
|
return methodNode;
|
|
}
|
|
}
|