Résolu Coremod ajout de la fonction return
-
Bonjour à tous! j’essaye d’avoir des capes sur mon serveur en utilisant un coremod avec l’asm. J’ai donc fait ça:
package pickandcraftSkin; import static org.objectweb.asm.Opcodes.ALOAD; import static org.objectweb.asm.Opcodes.INVOKESTATIC; import java.util.Iterator; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.InsnList; import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.tree.VarInsnNode; public class EDClassTransformer implements net.minecraft.launchwrapper.IClassTransformer { @Override public byte[] transform(String arg0, String arg1, byte[] arg2) { if (arg0.equals("beu")) { System.out.println("********* INSIDE OBFUSCATED AbstractClientPlayer TRANSFORMER ABOUT TO PATCH: " + arg0); return patchClassASM(arg0, arg2, true); } if (arg0.equals("net.minecraft.client.entity.AbstractClientPlayer")) { System.out.println("********* INSIDE AbstractClientPlayer TRANSFORMER ABOUT TO PATCH: " + arg0); return patchClassASM(arg0, arg2, false); } return arg2; } public byte[] patchClassASM(String name, byte[] bytes, boolean obfuscated) { String targetMethodName = ""; if(obfuscated == true) targetMethodName ="d"; else targetMethodName ="getSkinUrl"; //set up ASM class manipulation stuff. Consult the ASM docs for details ClassNode classNode = new ClassNode(); ClassReader classReader = new ClassReader(bytes); classReader.accept(classNode, 0); //Now we loop over all of the methods declared inside the Explosion class until we get to the targetMethodName "doExplosionB" // find method to inject into @SuppressWarnings("unchecked") Iterator <methodnode>methods = classNode.methods.iterator(); while(methods.hasNext()) { MethodNode m = methods.next(); System.out.println("********* Method Name: "+m.name + " Desc:" + m.desc); //Check if this is doExplosionB and it's method signature is (Z)V which means that it accepts a boolean (Z) and returns a void (V) if ((m.name.equals(targetMethodName) && m.desc.equals("(Ljava/lang/String;)Ljava/lang/String;"))) { System.out.println("********* Inside target method!"); //on supprime tous les noeuds AbstractInsnNode targetNode = null; @SuppressWarnings("unchecked") Iterator <abstractinsnnode>iter = m.instructions.iterator(); int index = -1; while (iter.hasNext()) { index++; targetNode = iter.next(); m.instructions.remove(targetNode); } InsnList toInject = new InsnList(); toInject.add(new VarInsnNode(ALOAD, 0)); toInject.add(new MethodInsnNode(INVOKESTATIC, "pickandcraftSkin/PlayerCustom", "getURLSkincustom", "(Ljava/lang/String;)Ljava/lang/String;")); // inject new instruction list into method instruction list m.instructions.insert(toInject); System.out.println("Patching Complete!"); break; } } //ASM specific for cleaning up and returning the final bytes for JVM processing. ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); classNode.accept(writer); return writer.toByteArray(); } }
Le seul problème c’est que il faudrait ajouter l’instruction return avant l’invocation de la méthode static! comment faire?
PS je ne suis pas sur que mon code est bon c’est la première fois que j’utilise l’ASM[/java]</abstractinsnnode></methodnode>
-
Personne?
-
Pas besoin d’asm, en plus il y a un tuto pour ça:
http://www.minecraftforgefrance.fr/showthread.php?tid=321 -
Explique un peu mieux ton problème.
-
Aucune idée, en revanche tu peux faire un système de cape sans passé par l’asm, il y a un tutoriel sur le forum, et sinon tu peux aussi regarder les sources de FFMT lib.
https://github.com/FFMT/FFMT-libs -
Oui j’ai regarder le tuto sur le forum et je pense utiliser cette méthode pour les oreilles mais pour le reste c’est plus simple avec l’ASM.
Pour l’instant j’ai réussi à supprimer le contenu de la méthode getSkinUrl et getCape Url et à ajouter l’invocation d’une méthode static. Je voudrais maintenant réussir à retourner le résultat! Mais je ne sais pas du tout comment faire!d’ailleurs si vous connaisez un bon tuto sur l’ASM et les spécification du bytecode en raccourcie même en anglais sa intéresserait, parce que vu la taille du tuto officiel… http://docs.oracle.com/javase/specs/jvms/se5.0/html/VMSpecTOC.doc.html
-
j’ai réussi:
SkinFMLLoadingPlugin
package pickandcraftSkin; import java.util.Map; import cpw.mods.fml.relauncher.IFMLLoadingPlugin.MCVersion; @MCVersion(value = "1.6.4") public class SkinFMLLoadingPlugin implements cpw.mods.fml.relauncher.IFMLLoadingPlugin { @Override public String[] getLibraryRequestClass() { // TODO Auto-generated method stub return null; } @Override public String[] getASMTransformerClass() { //This will return the name of the class "mod.culegooner.ExplosionDropsCore.EDClassTransformer" return new String[]{SkinClassTransformer.class.getName()}; } @Override public String getModContainerClass() { //This is the name of our dummy container "mod.culegooner.ExplosionDropsCore.EDDummyContainer" return SkinDummyContainer.class.getName(); } @Override public String getSetupClass() { // TODO Auto-generated method stub return null; } @Override public void injectData(Map <string, object="">data) { } }
SkinClassTransformer
package pickandcraftSkin; import static org.objectweb.asm.Opcodes.ARETURN; import static org.objectweb.asm.Opcodes.ALOAD; import static org.objectweb.asm.Opcodes.INVOKESTATIC; import java.util.Iterator; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.InsnList; import org.objectweb.asm.tree.InsnNode; import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.tree.VarInsnNode; public class SkinClassTransformer implements net.minecraft.launchwrapper.IClassTransformer { @Override public byte[] transform(String arg0, String arg1, byte[] arg2) { //on cherche la classe qui nous interressent. On gère les deux cas: si elle est "obscurcie" ou pas if (arg0.equals("beu")) { System.out.println("********* INSIDE OBFUSCATED AbstractClientPlayer TRANSFORMER ABOUT TO PATCH: " + arg0); return patchClassASM(arg0, arg2, true); } if (arg0.equals("net.minecraft.client.entity.AbstractClientPlayer")) { System.out.println("********* INSIDE AbstractClientPlayer TRANSFORMER ABOUT TO PATCH: " + arg0); return patchClassASM(arg0, arg2, false); } return arg2; } public byte[] patchClassASM(String name, byte[] bytes, boolean obfuscated) { String targetMethod1Name = "", targetMethod2Name = ""; boolean ok1 = false, ok2 = false; if(obfuscated == true) { targetMethod1Name ="d"; targetMethod2Name = "e"; } else { targetMethod1Name ="getSkinUrl"; targetMethod2Name = "getCapeUrl"; } //on prépare la manipulation ClassNode classNode = new ClassNode(); ClassReader classReader = new ClassReader(bytes); classReader.accept(classNode, 0); //Maintenant, on boucle sur toutes les méthodes déclarées dans la classe jusqu'à trouver la/les methode(s) cible(s) Iterator <methodnode>methods = classNode.methods.iterator(); while(methods.hasNext()) { MethodNode m = methods.next(); System.out.println("********* Method Name: "+m.name + " Desc:" + m.desc); //On vérifie si il s'agit de la méthode cible et si elle a la même signature (http://journals.ecs.soton.ac.uk/java/tutorial/native1.1/implementing/method.html) if ((m.name.equals(targetMethod1Name) && m.desc.equals("(Ljava/lang/String;)Ljava/lang/String;"))) { System.out.println("********* Inside target method1!"); InsnList toInject = new InsnList(); toInject.add(new VarInsnNode(ALOAD, 0)); toInject.add(new MethodInsnNode(INVOKESTATIC, "pickandcraftSkin/PlayerCustom", "getURLSkinCustom", "(Ljava/lang/String;)Ljava/lang/String;")); toInject.add(new InsnNode(ARETURN)); // inject new instruction list into method instruction list m.instructions = toInject; ok1 = true; System.out.println("Patching Method1 Complete!"); } else if ((m.name.equals(targetMethod2Name) && m.desc.equals("(Ljava/lang/String;)Ljava/lang/String;"))) { System.out.println("********* Inside target2 method!"); InsnList toInject = new InsnList(); toInject.add(new VarInsnNode(ALOAD, 0)); toInject.add(new MethodInsnNode(INVOKESTATIC, "pickandcraftSkin/PlayerCustom", "getURLCapeCustom", "(Ljava/lang/String;)Ljava/lang/String;")); toInject.add(new InsnNode(ARETURN)); // inject new instruction list into method instruction list m.instructions = toInject; ok2 = true; System.out.println("Patching Method2 Complete!"); } if(ok1 && ok2) break; } //ASM specific for cleaning up and returning the final bytes for JVM processing. ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); classNode.accept(writer); return writer.toByteArray(); } }
PlayerCustom
package pickandcraftSkin; import java.net.HttpURLConnection; import java.net.URL; import net.minecraft.util.StringUtils; public class PlayerCustom { private static String connexion (String adress, String par0Str, String part){ //on construit l'adresse URL en ajoutant le pseudo + l'extension de l'image (png) int code=404; //on lance une connexion à l'url afin de savoir si il y a un skin d'uploader try { URL u = new URL (adress); HttpURLConnection huc = ( HttpURLConnection ) u.openConnection (); huc.setRequestMethod ("GET"); huc.connect () ; //on récupère le code HTTP retourné par le serveur code = huc.getResponseCode() ; System.out.println("SKINURL:code "+code); //si il y est correct on retourne l'adresse if (code == HttpURLConnection.HTTP_OK) return adress; //sinon si il y a une redirection on teste avec la nouvelle url. Bien sur il faudra retourné en php une chaine de texte formaté avec Url du site + le pseudo du joueur + l'extension mais ce n'est pas l'objet de ce tutoriel else if (code == HttpURLConnection.HTTP_MOVED_TEMP || code == HttpURLConnection.HTTP_MOVED_PERM || code == HttpURLConnection.HTTP_SEE_OTHER) { //on récupère la nouvelle adresse String newUrl = huc.getHeaderField("Location"); // et on lance une connection avec la nouvelle URL huc = (HttpURLConnection) new URL(newUrl).openConnection(); huc.setRequestMethod ("GET"); huc.connect () ; code = huc.getResponseCode() ; System.out.println("SKINURL:code "+code); //si cette fois le serveur renvoie un code 200 alors on retourne la nouvelle adresse if (code == HttpURLConnection.HTTP_OK) return newUrl; } } catch(Exception e){ System.out.println("SKINURL:Bad Url."); } //si finalement on ne reçoit aucune réponse 200 on retourne l'adresse par défaut return String.format("http://skins.minecraft.net/Minecraft"+ part + "/%s.png", new Object[] {StringUtils.stripControlCodes(par0Str)}); } public static String getURLSkinCustom(String par0Str) { String adress=String.format("http://monsite/skins/%s.png", new Object[] {StringUtils.stripControlCodes(par0Str)}); return connexion(adress, par0Str, "Skins"); } public static String getURLCapeCustom(String par0Str) { String adress=String.format("http://monsite/capes/%s.png", new Object[] {StringUtils.stripControlCodes(par0Str)}); return connexion(adress, par0Str, "Cloaks"); } } ```</methodnode></string,>