diff --git a/Forge/resource/META-INF/coremods.json b/Forge/resource/META-INF/coremods.json new file mode 100644 index 0000000..c7ab21e --- /dev/null +++ b/Forge/resource/META-INF/coremods.json @@ -0,0 +1,3 @@ +{ + "transformers": "transformers.js" +} \ No newline at end of file diff --git a/Forge/resource/META-INF/mods.toml b/Forge/resource/META-INF/mods.toml new file mode 100644 index 0000000..444d591 --- /dev/null +++ b/Forge/resource/META-INF/mods.toml @@ -0,0 +1,19 @@ +modLoader="javafml" +loaderVersion="[25,)" +issueTrackerURL="https://github.com/xfl03/MCCustomSkinLoader/issues" +displayURL="https://github.com/xfl03/MCCustomSkinLoader" +credits="GPLv3" +authors=["xfl03", "JLChnToZ"] +[[mods]] +modId="customskinloader" +version="${modFullVersion}" +displayName="CustomSkinLoader" +description=''' +Custom Skin Loader for Minecraft +''' +[[dependencies.customskinloader]] +modId="forge" +mandatory=true +versionRange="[25,)" +ordering="NONE" +side="CLIENT" \ No newline at end of file diff --git a/Forge/resource/mcmod.info b/Forge/resource/mcmod.info index a437f73..50b66ef 100644 --- a/Forge/resource/mcmod.info +++ b/Forge/resource/mcmod.info @@ -6,6 +6,7 @@ "version": "${modFullVersion}", "url": "https://github.com/xfl03/MCCustomSkinLoader", "authorList": ["xfl03", "JLChnToZ"], - "credits": "GPLv3" + "credits": "GPLv3", + "clientSideOnly": true } ] \ No newline at end of file diff --git a/Forge/resource/transformers.js b/Forge/resource/transformers.js new file mode 100644 index 0000000..4ab3e1e --- /dev/null +++ b/Forge/resource/transformers.js @@ -0,0 +1,35 @@ +var JSAPI = Java.type('customskinloader.forge.loader.ModLauncher'); +function f(cn) { + return JSAPI.instance().transform(cn); +} +function initializeCoreMod() { + return { + 'SkinManagerTransformer': { + 'target': { + 'type': 'CLASS', + 'name': 'net/minecraft/client/resources/SkinManager' + }, + 'transformer': function(cn) { + return f(cn); + } + }, + 'PlayerTabTransformer': { + 'target': { + 'type': 'CLASS', + 'name': 'net/minecraft/client/gui/GuiPlayerTabOverlay' + }, + 'transformer': function(cn) { + return f(cn); + } + }, + 'FakeSkinManagerTransformer': { + 'target': { + 'type': 'CLASS', + 'name': 'customskinloader/fake/FakeSkinManager' + }, + 'transformer': function(cn) { + return f(cn); + } + } + }; +} \ No newline at end of file diff --git a/Forge/source/customskinloader/forge/ForgePlugin.java b/Forge/source/customskinloader/forge/ForgePlugin.java index 3fa68e0..0a942c1 100644 --- a/Forge/source/customskinloader/forge/ForgePlugin.java +++ b/Forge/source/customskinloader/forge/ForgePlugin.java @@ -10,12 +10,7 @@ public class ForgePlugin implements IFMLLoadingPlugin { @Override public String[] getASMTransformerClass() { - try { - Class.forName("cpw.mods.modlauncher.api.ITransformer"); - return new String[]{"customskinloader.forge.transformer.ModLauncher"};//ModLauncher - } catch (ClassNotFoundException ignored) { - return new String[]{"customskinloader.forge.transformer.LaunchWrapper"};//LaunchWrapper - } + return new String[]{"customskinloader.forge.loader.LaunchWrapper"};//LaunchWrapper } @Override diff --git a/Forge/source/customskinloader/forge/TransformerManager.java b/Forge/source/customskinloader/forge/TransformerManager.java index 197335a..d642fb8 100644 --- a/Forge/source/customskinloader/forge/TransformerManager.java +++ b/Forge/source/customskinloader/forge/TransformerManager.java @@ -10,13 +10,7 @@ import java.util.*; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; -import net.minecraftforge.fml.common.asm.transformers.deobf.FMLDeobfuscatingRemapper; - import customskinloader.Logger; -import customskinloader.forge.transformer.*; -import customskinloader.forge.transformer.PlayerTabTransformer.ScoreObjectiveTransformer; -import customskinloader.forge.transformer.SkinManagerTransformer.*; -import customskinloader.forge.transformer.SpectatorMenuTransformer.PlayerMenuObjectTransformer; public class TransformerManager { public static Logger logger = new Logger(new File("./CustomSkinLoader/ForgePlugin.log")); @@ -35,20 +29,11 @@ public class TransformerManager { void transform(ClassNode cn, MethodNode mn); } - private static final IMethodTransformer[] TRANFORMERS = { - new InitTransformer(), - new LoadSkinTransformer(), - new LoadProfileTexturesTransformer(), - new LoadSkinFromCacheTransformer(), - new ScoreObjectiveTransformer(), - new PlayerMenuObjectTransformer(), - new FakeSkinManagerTransformer.InitTransformer() - }; public Map> map; - public TransformerManager() { + public TransformerManager(IMethodTransformer... transformers) { map = new HashMap>(); - for (IMethodTransformer t : TRANFORMERS) { + for (IMethodTransformer t : transformers) { logger.info("[CSL DEBUG] REGISTERING TRANSFORMER %s", t.getClass().getName()); if (!t.getClass().isAnnotationPresent(TransformTarget.class)) { logger.info("[CSL DEBUG] ERROR occurs while parsing Annotation."); @@ -67,32 +52,18 @@ public class TransformerManager { } } - public ClassNode transform(ClassNode classNode) { - String obfClassName = classNode.name; - String className = FMLDeobfuscatingRemapper.INSTANCE.map(obfClassName); - return transform(classNode, className, obfClassName); - } - - public ClassNode transform(ClassNode classNode, String className, String obfClassName) { - logger.info("[CSL DEBUG] CLASS %s will be transformed", className); + public MethodNode transform(ClassNode classNode, MethodNode methodNode, String className, String methodName, String methodDesc) { Map transMap = map.get(className); - - // NOTE: `map` = convert obfuscated name to srgName; - List ml = new ArrayList(classNode.methods); - for (MethodNode mn : ml) { - String methodName = FMLDeobfuscatingRemapper.INSTANCE.mapMethodName(obfClassName, mn.name, mn.desc); - String methodDesc = FMLDeobfuscatingRemapper.INSTANCE.mapMethodDesc(mn.desc); - String methodTarget = methodName + methodDesc; - if (transMap.containsKey(methodTarget)) { - try { - transMap.get(methodTarget).transform(classNode, mn); - logger.info("[CSL DEBUG] Successfully transformed method %s in class %s", methodName, className); - } catch (Exception e) { - logger.warning("[CSL DEBUG] An error happened when transforming method %s in class %s.", methodTarget, className); - logger.warning(e); - } + String methodTarget = methodName + methodDesc; + if (transMap.containsKey(methodTarget)) { + try { + transMap.get(methodTarget).transform(classNode, methodNode); + logger.info("[CSL DEBUG] Successfully transformed method %s in class %s", methodName, className); + } catch (Exception e) { + logger.warning("[CSL DEBUG] An error happened when transforming method %s in class %s.", methodTarget, className); + logger.warning(e); } } - return classNode; + return methodNode; } } diff --git a/Forge/source/customskinloader/forge/loader/LaunchWrapper.java b/Forge/source/customskinloader/forge/loader/LaunchWrapper.java new file mode 100644 index 0000000..3921945 --- /dev/null +++ b/Forge/source/customskinloader/forge/loader/LaunchWrapper.java @@ -0,0 +1,50 @@ +package customskinloader.forge.loader; + +import customskinloader.forge.TransformerManager; +import customskinloader.forge.transformer.PlayerTabTransformer; +import customskinloader.forge.transformer.SkinManagerTransformer; +import customskinloader.forge.transformer.SpectatorMenuTransformer; + +import net.minecraft.launchwrapper.IClassTransformer; +import net.minecraftforge.fml.common.asm.transformers.deobf.FMLDeobfuscatingRemapper; + +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.MethodNode; + +//LaunchWrapper for 1.13- +public class LaunchWrapper implements IClassTransformer { + + private static final TransformerManager.IMethodTransformer[] TRANFORMERS = { + new SkinManagerTransformer.InitTransformer(), + new SkinManagerTransformer.LoadSkinTransformer(), + new SkinManagerTransformer.LoadProfileTexturesTransformer(), + new SkinManagerTransformer.LoadSkinFromCacheTransformer(), + new PlayerTabTransformer.ScoreObjectiveTransformer(), + new SpectatorMenuTransformer.PlayerMenuObjectTransformer() + }; + private TransformerManager transformerManager = new TransformerManager(TRANFORMERS); + + //From: https://github.com/RecursiveG/UniSkinMod/blob/1.9.4/src/main/java/org/devinprogress/uniskinmod/coremod/BaseAsmTransformer.java#L83-L114 + public byte[] transform(String obfClassName, String className, byte[] bytes) { + if (!transformerManager.map.containsKey(className)) return bytes;//Check if should be transformed + + //Parse bytes to ClassNode + ClassReader cr = new ClassReader(bytes); + ClassNode cn = new ClassNode(); + cr.accept(cn, 0); + + //Transform ClassNode + for (MethodNode mn : cn.methods) { + String methodName = FMLDeobfuscatingRemapper.INSTANCE.mapMethodName(obfClassName, mn.name, mn.desc); + String methodDesc = FMLDeobfuscatingRemapper.INSTANCE.mapMethodDesc(mn.desc); + transformerManager.transform(cn, mn, className, methodName, methodDesc); + } + + //Parse Class Node to bytes + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); + cn.accept(cw); + return cw.toByteArray(); + } +} diff --git a/Forge/source/customskinloader/forge/loader/ModLauncher.java b/Forge/source/customskinloader/forge/loader/ModLauncher.java new file mode 100644 index 0000000..9ef7119 --- /dev/null +++ b/Forge/source/customskinloader/forge/loader/ModLauncher.java @@ -0,0 +1,45 @@ +package customskinloader.forge.loader; + +import customskinloader.forge.TransformerManager; +import customskinloader.forge.transformer.FakeSkinManagerTransformer; +import customskinloader.forge.transformer.PlayerTabTransformer; +import customskinloader.forge.transformer.SkinManagerTransformer; + +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.MethodNode; + +//ModLauncher for 1.13+ +public class ModLauncher { + + private static final TransformerManager.IMethodTransformer[] TRANFORMERS = { + new SkinManagerTransformer.InitTransformer(), + new SkinManagerTransformer.LoadSkinTransformer(), + new SkinManagerTransformer.LoadProfileTexturesTransformer(), + new SkinManagerTransformer.LoadSkinFromCacheTransformer(), + new PlayerTabTransformer.ScoreObjectiveTransformer(), + new FakeSkinManagerTransformer.InitTransformer() + }; + private TransformerManager transformerManager = new TransformerManager(TRANFORMERS); + + public ClassNode transform(ClassNode input) { + for (MethodNode mn : input.methods) { + transformerManager.transform(input, mn, input.name, mn.name, mn.desc); + } + return input; + } + + //Singleton + private volatile static ModLauncher INSTANCE = null; + + public static ModLauncher instance() { + if (INSTANCE == null) { + synchronized (ModLauncher.class) { + if (INSTANCE == null) { + INSTANCE = new ModLauncher(); + } + } + } + return INSTANCE; + } + +} diff --git a/Forge/source/customskinloader/forge/transformer/FakeSkinManagerTransformer.java b/Forge/source/customskinloader/forge/transformer/FakeSkinManagerTransformer.java index d62226b..b2906e5 100644 --- a/Forge/source/customskinloader/forge/transformer/FakeSkinManagerTransformer.java +++ b/Forge/source/customskinloader/forge/transformer/FakeSkinManagerTransformer.java @@ -10,7 +10,7 @@ import org.objectweb.asm.commons.ClassRemapper; import org.objectweb.asm.tree.*; /** - * Transformer of FakeSkinManager for 1.13 + * Transformer of FakeSkinManager for 1.13+ */ public class FakeSkinManagerTransformer { private static boolean needTransform = false; @@ -19,11 +19,13 @@ public class FakeSkinManagerTransformer { private final static String NEW_TARGET_CLASS = "net/minecraft/client/renderer/texture/ThreadDownloadImageData"; private final static String CALLBACK_CLASS = "net/minecraft/client/resources/SkinManager$SkinAvailableCallback"; + /* No Need for Detecting 1.13 private static void init() { if (!needInit) return; needTransform = TARGET_CLASS == FMLDeobfuscatingRemapper.INSTANCE.unmap(TARGET_CLASS); needInit = false; } + */ @TransformTarget(className = "customskinloader.fake.FakeSkinManager", methodNames = {""}, @@ -31,8 +33,10 @@ public class FakeSkinManagerTransformer { public static class InitTransformer implements IMethodTransformer { @Override public void transform(ClassNode cn, MethodNode mn) { + /* No Need for Detecting 1.13 init(); if (!needTransform) return; + */ TransformerManager.logger.info("1.13 detected, FakeSkinManager will be transformed."); ClassNameRemapper.remapClassName(cn, TARGET_CLASS, NEW_TARGET_CLASS); MethodNameRemapper.remapMethodName(cn, CALLBACK_CLASS, "func_180521_a", "onSkinTextureAvailable"); diff --git a/Forge/source/customskinloader/forge/transformer/LaunchWrapper.java b/Forge/source/customskinloader/forge/transformer/LaunchWrapper.java deleted file mode 100644 index 75610c7..0000000 --- a/Forge/source/customskinloader/forge/transformer/LaunchWrapper.java +++ /dev/null @@ -1,30 +0,0 @@ -package customskinloader.forge.transformer; - -import customskinloader.forge.TransformerManager; -import net.minecraft.launchwrapper.IClassTransformer; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.tree.ClassNode; - -public class LaunchWrapper implements IClassTransformer { - private TransformerManager transformerManager = new TransformerManager(); - - //LaunchWrapper - //From: https://github.com/RecursiveG/UniSkinMod/blob/1.9.4/src/main/java/org/devinprogress/uniskinmod/coremod/BaseAsmTransformer.java#L83-L114 - public byte[] transform(String obfClassName, String className, byte[] bytes) { - if (!transformerManager.map.containsKey(className)) return bytes;//Check if should be transformed - - //Parse bytes to ClassNode - ClassReader cr = new ClassReader(bytes); - ClassNode cn = new ClassNode(); - cr.accept(cn, 0); - - //Transform ClassNode - transformerManager.transform(cn, className, obfClassName); - - //Parse Class Node to bytes - ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); - cn.accept(cw); - return cw.toByteArray(); - } -} diff --git a/Forge/source/customskinloader/forge/transformer/ModLauncher.java b/Forge/source/customskinloader/forge/transformer/ModLauncher.java deleted file mode 100644 index 711b8c2..0000000 --- a/Forge/source/customskinloader/forge/transformer/ModLauncher.java +++ /dev/null @@ -1,33 +0,0 @@ -package customskinloader.forge.transformer; - -import cpw.mods.modlauncher.api.ITransformer; -import cpw.mods.modlauncher.api.ITransformerVotingContext; -import cpw.mods.modlauncher.api.TransformerVoteResult; -import customskinloader.forge.TransformerManager; -import net.minecraftforge.fml.common.asm.transformers.deobf.FMLDeobfuscatingRemapper; -import org.objectweb.asm.tree.ClassNode; - -import java.util.HashSet; -import java.util.Set; - -public class ModLauncher implements ITransformer { - private TransformerManager transformerManager = new TransformerManager(); - - //ModLauncher - public ClassNode transform(ClassNode input, ITransformerVotingContext context) { - return transformerManager.transform(input); - } - - public TransformerVoteResult castVote(ITransformerVotingContext context) { - return TransformerVoteResult.YES; - } - - public Set targets() { - Set sets = new HashSet(); - for (String className : transformerManager.map.keySet()) { - String obfName = FMLDeobfuscatingRemapper.INSTANCE.unmap(className); - sets.add(Target.targetClass(obfName)); - } - return sets; - } -} diff --git a/Forge/source/customskinloader/forge/transformer/SpectatorMenuTransformer.java b/Forge/source/customskinloader/forge/transformer/SpectatorMenuTransformer.java index 48f299f..1e988c3 100644 --- a/Forge/source/customskinloader/forge/transformer/SpectatorMenuTransformer.java +++ b/Forge/source/customskinloader/forge/transformer/SpectatorMenuTransformer.java @@ -14,6 +14,9 @@ import org.objectweb.asm.tree.MethodNode; import customskinloader.forge.TransformerManager.IMethodTransformer; import customskinloader.forge.TransformerManager.TransformTarget; +/** + * Transformer of Spectator Menu for 1.13- + */ public class SpectatorMenuTransformer { @TransformTarget(className="net.minecraft.client.gui.spectator.PlayerMenuObject", methodNames={""}, @@ -31,12 +34,14 @@ public class SpectatorMenuTransformer { if(ain.getOpcode()!=Opcodes.INVOKESTATIC) continue; + /* No Need for Detecting 1.13 MethodInsnNode min = (MethodInsnNode)ain; String deobfName = FMLDeobfuscatingRemapper.INSTANCE.map(min.owner); if(!deobfName.equals("net/minecraft/client/entity/AbstractClientPlayer")) {//Fix 1.13 TransformerManager.logger.info("InvokeStatic to " + deobfName + " in PlayerMenuObject will be ignored."); continue; } + */ if(!flag) { //First InvokeStatic