[Resource] ReflectionExecutor - Finally readable reflection!

Discussion in 'Resources' started by molenzwiebel, Nov 23, 2013.

Thread Status:
Not open for further replies.
  1. Offline

    molenzwiebel

    What can ReflectionExecutor do?

    The reflection way of sending a packet:
    Code:java
    1. Object handle = p.getClass().getMethod("getHandle").invoke(p);
    2.  
    3. Object connection = handle.getClass().getField("playerConnection").get(handle);
    4. connection.getClass().getMethod("sendPacket", Object.class).invoke(connection, packet);

    The ReflectionExecutor way of sending a packet:
    Code:java
    1. ReflectionExecutor.execute("getHandle().playerConnection.sendPacket({1})", p, packet);


    The reflection way of creating a Packet20NamedEntitySpawn:
    Code:java
    1. String NMS_PATH = "net.minecraft.server." + (Bukkit.getServer() != null ? Bukkit.getServer().getClass().getPackage().getName().replace(".", ",").split(",")[3] : "UNKNOWN");
    2. Class<?> packetClass = Class.forName(NMS_PATH+".Packet20NamedEntitySpawn");
    3. Constructor<?> constr = packetClass.getConstructor(Class.forName(NMS_PATH+".EntityHuman"));
    4. Object packet = constr.newInstance(p.getClass().getMethod("getHandle").invoke(p));

    The ReflectionExecutor way of creating a Packet20NamedEntitySpawn:
    Code:java
    1. ReflectionObject packet = ReflectionObject.fromNMS("Packet20NamedEntitySpawn", ReflectionExecutor.execute("getHandle()", p));


    What is ReflectionExecutor?
    ReflectionExecutor is an utility class written by me. It aims to simplify the difficult process of bypassing the limits of referencing NMS. ReflectionExecutor exists of two parts:
    • The Executor part
    • The Object part
    Using the executor
    Using the executor is not that hard really. It only contains one method. Execute.
    Code:
    ReflectionExecutor.execute(command, toCallOn, args);
    Command => The command to call. getHandle() for example
    toCallOn => The object the provided command needs to be called on. the player for example
    args => The arguments. These can be referenced with {Argument Number} in your code. The first argument can be referenced by {1}.
    For example:
    Code:java
    1. String str = "Demo";
    2. System.out.println(ReflectionExecutor.execute("charAt({1})", str, 1); //Prints e

    Using the object
    ReflectionExecutor also contains a subclass called ReflectionObject. This is used for modifying objects. Here is how you make one:
    Code:
    new ReflectionObject(object);
    object => the object the ReflectionObject wraps around.
    Code:
    ReflectionObject.fromNMS(nmsClass, arguments);
    This method tries to create a new instance of nmsClass with the specified arguments. If it succeeds, it will return the created object wrapped in a ReflectionObject.
    nmsClass => The NMS class. Can be a member of net.minecraft.server.VERSION. (For example, Packet20NamedEntitySpawn), or a normal java class (For example, java.lang.String)
    For all the methods, see the documentation!
    Downloads
    Find the download here
    Documentation here

    Placeholder for future stuff

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Jun 5, 2016
    KingFaris11, DSH105, TigerHix and 5 others like this.
  2. molenzwiebel This looks really nice. I will probably not use it in the future because I just finished my own reflection framework :/ (which contains more features then yourse, anyways this is a neat tool :p )
     
  3. Offline

    Ultimate_n00b

    Neat, I might be looking into using this in the future.
     
  4. Offline

    Bammerbom

  5. Offline

    Ultimate_n00b

    Yep.
     
  6. Offline

    ccrama

    molenzwiebel Very nice library. I'm having some issues though, especially with calling a third class to execute a function on an object with a second object, case in point:

    Code:java
    1. System.out.println(ReflectionExecutor.NMS_PATH + "NMS PATH"); //just a check
    2.  
    3. ReflectionObject es = ReflectionObject.fromNMS("EntityWitherSkull", ReflectionExecutor.execute("getHandle()", loc.getWorld()));
    4. ReflectionObject.fromNMS("Entity", ReflectionExecutor.execute("setLocation()", es,loc.getX(), loc.getY() + 1 + 55, loc.getZ(), 0, 0)); //this line. I need to use the Entity class to call setLocation() on my EntityWitherSkull object
    5. ReflectionExecutor.execute("addEntity()",ReflectionExecutor.execute("getHandle()", loc.getWorld()), es);
    6. ReflectionObject hs = ReflectionObject.fromNMS("EntityHorse", ReflectionExecutor.execute("getHandle()", loc.getWorld()));
    7. ReflectionExecutor.execute("setLocation()",hs, loc.getX(), loc.getY() + 55, loc.getZ(), 0, 0);
    8. ReflectionExecutor.execute("setAge()", hs, -1700000);
    9. ReflectionExecutor.execute("setCustomName()", hs, text);
    10. ReflectionExecutor.execute("setCustomNameVisible()", hs, true);
    11. ReflectionExecutor.execute("getHandle().playerConnection.sendPacket({1})", p, hs);
    12.  
    13. ReflectionObject ae = ReflectionObject.fromNMS("PacketPlayOutAttachEntity", 0, hs, es);
    14. ReflectionExecutor.execute("getHandle().playerConnection.sendPacket({1})", p, ae);
    15.  
    16. int ides = (int) ReflectionExecutor.execute("getID()",es);
    17. int idhs = (int) ReflectionExecutor.execute("getID()",hs);
    18. return Arrays.asList(ides, idhs );


    I believe some of the rest of my code may not work, and if you could spot check that, that would be awesome.
    Thanks!
     
  7. Offline

    RawCode

    reflection may be hard to read only for users who decided "iam very smart and will outsmart bukkit team version barrier".

    version barrier placed for a reason, you shoud not try to overcome it, especially in public closed source plugins.
     
    Garris0n likes this.
  8. Offline

    Garris0n

    I guess the only thing is that some people want their plugin to support more than one version. If they made the plugin automatically break on a new version that they haven't updated it for then I suppose I'd be fine with that, but otherwise the plugin is eventually going to break something.
     
  9. Offline

    RawCode

    Reason for version barrier "to prevent random destructive issues".

    Just imagine situation - you are using NMS World class and some methods like "a" or "b" - in new version method signature left intact, but method completely different.

    now it may remove world or regenerate chunks or wipe all animals in world - people who use your plugin, will be happy about "i dont need to update it" very limited amount of time.

    after some time i decided to abandon any attempts to overcome version barrier - each version you must double check your NMS code and force users to update.

    it will be good move to place some useless import into main class just to force users to update with new major bukkit version.
     
  10. Offline

    Garris0n

    Exactly. It can be useful to make your plugin work with older versions, but you should include something to break it with newer versions until you can verify that it doesn't do anything horrible.
     
    Cirno, DSH105, TigerHix and 2 others like this.
  11. Offline

    RawCode

    If something can be used wrong, it will be used wrong.

    Some features must be hard to use or undocumented to prevent random "noobs" from using it.
     
    TigerHix likes this.
  12. Offline

    ccrama

    RawCode Although it could be used wrongly around big updates in code (ie 1.6-1.7, 1.7-1.8), the developer could easily use reflection to handle 1.7_R1, R2, R3, which all appear to be non-version specific, but have different names due to Bukkit's nomenclature. Even Bukkit dev only has support for 1.7.2 R1-3 for developers to post their plugins, and most users don't even know how to find out what R version they have, and still think there is no support for, say, 1.7.5 or 9. Using reflection, developers have the option to put out one version of code, which works with every renamed version and revision. When something breaks on a large version update, just change a few things in your code and you're back in business.
     
  13. Offline

    RawCode

    Read my post, at least single time please, i explained why version barrier exists. ccrama
     
    xTrollxDudex likes this.
  14. Offline

    Cirno

    If the last statement was true, then everyone in the world would be standing around, wondering how to use this new fangled thing named "fire".
     
  15. Offline

    RawCode

    as you may know, currently every state enforce and punish "parents" who let children to start fire.

    many objects have notes "keep away from children"
     
    Garris0n likes this.
Thread Status:
Not open for further replies.

Share This Page