2016-12-25 17:05:30 +08:00
package customskinloader.forge ;
2016-12-29 16:44:16 +08:00
import java.lang.annotation.ElementType ;
2016-12-31 23:05:55 +08:00
import java.lang.annotation.Retention ;
import java.lang.annotation.RetentionPolicy ;
2016-12-29 16:44:16 +08:00
import java.lang.annotation.Target ;
2016-12-25 17:05:30 +08:00
import java.util.ArrayList ;
import java.util.HashMap ;
import java.util.List ;
import java.util.Map ;
2018-06-25 00:34:32 +08:00
import customskinloader.Logger ;
2016-12-25 17:05:30 +08:00
import org.objectweb.asm.ClassReader ;
import org.objectweb.asm.ClassWriter ;
import org.objectweb.asm.tree.ClassNode ;
import org.objectweb.asm.tree.MethodNode ;
import net.minecraft.launchwrapper.IClassTransformer ;
import net.minecraftforge.fml.common.asm.transformers.deobf.FMLDeobfuscatingRemapper ;
2018-07-26 20:50:41 +08:00
import customskinloader.forge.transformer.* ;
2018-06-25 00:56:47 +08:00
import customskinloader.forge.transformer.PlayerTabTransformer.ScoreObjectiveTransformer ;
import customskinloader.forge.transformer.SkinManagerTransformer.* ;
import customskinloader.forge.transformer.SpectatorMenuTransformer.PlayerMenuObjectTransformer ;
2017-01-01 01:06:40 +08:00
2016-12-25 17:05:30 +08:00
public class TransformerManager implements IClassTransformer {
2018-06-25 00:56:47 +08:00
public static Logger logger = new Logger ( "CustomSkinLoader/ForgePlugin.log" );
2018-02-12 12:20:28 +08:00
@Retention ( RetentionPolicy . RUNTIME )
@Target ( ElementType . TYPE )
public @interface TransformTarget {
2018-06-25 00:34:32 +08:00
String className ();
String [] methodNames ();
String desc ();
2018-02-12 12:20:28 +08:00
}
public interface IMethodTransformer {
2018-06-25 00:34:32 +08:00
void transform ( ClassNode cn , MethodNode mn );
2018-02-12 12:20:28 +08:00
}
private static final IMethodTransformer [] TRANFORMERS = {
new InitTransformer (),
new LoadSkinTransformer (),
new LoadProfileTexturesTransformer (),
new LoadSkinFromCacheTransformer (),
new ScoreObjectiveTransformer (),
2018-07-26 20:50:41 +08:00
new PlayerMenuObjectTransformer (),
new FakeSkinManagerTransformer . InitTransformer ()
};
2018-02-12 12:20:28 +08:00
private Map < String , Map < String , IMethodTransformer >> map ;
public TransformerManager (){
map = new HashMap < String , Map < String , IMethodTransformer >> ();
for ( IMethodTransformer t : TRANFORMERS ){
2018-06-25 00:34:32 +08:00
logger . info ( "[CSL DEBUG] REGISTERING TRANSFORMER %s" , t . getClass (). getName ());
2018-02-12 12:20:28 +08:00
if ( ! t . getClass (). isAnnotationPresent ( TransformTarget . class )){
2018-06-25 00:34:32 +08:00
logger . info ( "[CSL DEBUG] ERROR occurs while parsing Annotation." );
2018-02-12 12:20:28 +08:00
continue ;
}
addMethodTransformer ( t . getClass (). getAnnotation ( TransformTarget . class ), t );
}
}
private void addMethodTransformer ( TransformTarget target , IMethodTransformer transformer ) {
if ( ! map . containsKey ( target . className ()))
map . put ( target . className (), new HashMap < String , IMethodTransformer > ());
for ( String methodName : target . methodNames ()){
map . get ( target . className ()). put ( methodName + target . desc (), transformer );
2018-06-25 00:34:32 +08:00
logger . info ( "[CSL DEBUG] REGISTERING METHOD %s(%s)" , target . className (), methodName + target . desc ());
2018-02-12 12:20:28 +08:00
}
}
//From: https://github.com/RecursiveG/UniSkinMod/blob/1.9.4/src/main/java/org/devinprogress/uniskinmod/coremod/BaseAsmTransformer.java#L83-L114
@Override
public byte [] transform ( String obfClassName , String className , byte [] bytes ) {
if ( ! map . containsKey ( className )) return bytes ;
2018-06-25 00:34:32 +08:00
logger . info ( "[CSL DEBUG] CLASS %s will be transformed" , className );
2018-02-12 12:20:28 +08:00
Map < String , IMethodTransformer > transMap = map . get ( className );
ClassReader cr = new ClassReader ( bytes );
ClassNode cn = new ClassNode ();
cr . accept ( cn , 0 );
2016-12-25 17:05:30 +08:00
2018-02-12 12:20:28 +08:00
// NOTE: `map` = convert obfuscated name to srgName;
2018-06-25 00:34:32 +08:00
List < MethodNode > ml = new ArrayList < MethodNode > ( cn . methods );
2018-02-12 12:20:28 +08:00
for ( MethodNode mn : ml ) {
String methodName = FMLDeobfuscatingRemapper . INSTANCE . mapMethodName ( obfClassName , mn . name , mn . desc );
String methodDesc = FMLDeobfuscatingRemapper . INSTANCE . mapMethodDesc ( mn . desc );
if ( transMap . containsKey ( methodName + methodDesc )) {
try {
2018-06-25 00:34:32 +08:00
logger . info ( "[CSL DEBUG] Transforming method %s in class %s(%s)" , methodName + methodDesc , obfClassName , className );
2018-02-12 12:20:28 +08:00
transMap . get ( methodName + methodDesc ). transform ( cn , mn );
2018-06-25 00:34:32 +08:00
logger . info ( "[CSL DEBUG] Successfully transformed method %s in class %s(%s)" , methodName + methodDesc , obfClassName , className );
2018-02-12 12:20:28 +08:00
} catch ( Exception e ) {
2018-06-25 00:34:32 +08:00
logger . warning ( "[CSL DEBUG] An error happened when transforming method %s in class %s(%s). The whole class was not modified." , methodName + methodDesc , obfClassName , className );
2018-02-12 12:20:28 +08:00
e . printStackTrace ();
return bytes ;
}
}
}
2016-12-25 17:05:30 +08:00
2018-02-12 12:20:28 +08:00
ClassWriter cw = new ClassWriter ( ClassWriter . COMPUTE_FRAMES | ClassWriter . COMPUTE_MAXS );
cn . accept ( cw );
return cw . toByteArray ();
}
2016-12-25 17:05:30 +08:00
}