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?


  • Moddeurs confirmés

    Pas besoin d'asm, en plus il y a un tuto pour ça:
    http://www.minecraftforgefrance.fr/showthread.php?tid=321


  • Modérateurs

    Explique un peu mieux ton problème.


  • Moddeurs confirmés Rédacteurs Administrateurs

    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,>

Log in to reply