[Tutorial] Simple tricks to make your reflection last longer

Discussion in 'Resources' started by bigteddy98, May 8, 2014.

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

    bigteddy98

    This resource is no longer availabe.
     
    MrAwellstein and Assist like this.
  2. Offline

    bigteddy98

    What? Have you actually read this? I only explain how you can get fields by type instead of by name, I don't get ya :p.

    Owh I get ya, I made a mistake in the first sentence. Thanks.
     
    CaptainBern likes this.
  3. Offline

    BungeeTheCookie

    CaptainBern bigteddy98
    If only Bukkit or Spigot made a non-version dependent NMS library.

    I know that, you silly goose.

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Jun 8, 2016
  4. Offline

    xTrollxDudex

    Oh :X
     
  5. BungeeTheCookie xTrollxDudex Working with NMS can be very dangerous and break servers and worlds. Creating a version independent library is already done, it's called "Bukkit".
     
    DSH105 and gorbb like this.
  6. Offline

    bigteddy98

    NMS code is the only thing we have to do what we really want. Bukkit is a cool API, but really limits what mojang offers us. Why so much hate to NMS the past days? I really don't get it.
     
  7. bigteddy98 You can only make use of these "offers" trough hacky code which can, and will, break stuff if the person who uses it doesn't know how to use it/make it a little bit safe. Servers actually broke in the past with this kind of stuff (outdated plugins etc). Thats one of the reasons why the safeguard was implemented (safeguard being the version tags). If you feel like Bukkit is missing something then why not make a ticket for it, or even a PR (or hop by on IRC so we can talk about it :p )? Also if you know some of my work then you know that I use NMS in almost all of my projects :p

    About your original thread; I like the idea of it, "fuzzy-reflection" (credits to Comphenix for the term "fuzzy-reflection") can be a powerfull alternative for abstraction.
     
  8. Offline

    Ultimate_n00b

    If you don't want to use bukkit then make a server mod.
     
  9. This is a very cool idea of getting past some of the obfuscation. The issue arises when multiple variables are of the same object.
     
  10. Offline

    bigteddy98

    Why? Like I said in the tutorial, the method returns a list of all fields with the same variable type. Mojang hardly ever changes the sequence of these fields. For example the field "j" and "i" in the example above. "i" is the first one (list.get(0)) and "j" is the second one (list.get(1)).

    BigTeddy98, Sander.
     
  11. Offline

    mkremins

    The danger here comes from the exceptions to the "hardly ever". If, for instance, a new field of type Channel happens to be added to the NetworkManager class previous to the Channel field you were originally trying to access, your code's "version-independent" behavior has a good chance of producing a very subtle and difficult-to-trace bug.

    Since your code is still able to get at a Channel object, it won't realize anything is wrong until it attempts to use the retrieved object in an invalid way. Depending on how your plugin is structured, this might first occur a long way away from the actual site of the problem. In this case, the exception that fires as a result will appear incongruous, masking the underlying reason for the failure. Heck, depending on the nature of your code's interaction with the object, you might never actually see an exception raised at all – only a sudden change in your plugin's behavior that you don't have even the faintest idea how to go about tracking down.

    This is the reason to be cautious about using reflection in general, and especially with using reflection to get at obfuscated fields: 99% of the time, Mojang's updates won't even affect your code, but the remaining 1% of cases become much harder to detect and resolve – because the reflection is hacking around many of the safeguards that exist to prevent problems of this sort. That's not to say that reflection should be avoided altogether, but there are distinct tradeoffs that you always need to consider when you make your code dependent on an explicitly private implementation detail that's subject to breaking change at any time.
     
  12. Offline

    RawCode

    invalid.

    version barried done for a reason, not to encourage random "users" to crack it.
     
  13. Offline

    bigteddy98

    I really don't get it anymore... Version changing package names are done for a reason, I know that. Because I heard many people saying "using NMS code is awesome, but can break easily", I made this, to help people a bit with their breaking reflection code. But it seems not to be appreciated... Thanks ;)
     
  14. Offline

    Syd

    I think it's very important to let the version safeguard do it's job.
    You REALLY should check your NMS code when an update comes up. It prevents plugins from fucking up a server thanks to reflection.

    Better use abstraction and per version implementations.
    mbaxter posted a great tutorial for doing this with maven in this forum. This way you can make a plugin downward compatible without any sideeffect on too new servers.

    And generally I think it's a bad idea to look for upward compatibility. You never know what happens in the future. ;)

    Edit: however, getting a by CraftBukkit renamed field seems pretty safe IMO. :D
     
  15. Offline

    RawCode

    illusion of "forward" compatability is harmfull thing.

    i already explained multiple times why you just can't invoke random "void a()" after version change - in new version that method may wipe world or perform other "harmful" action.

    perfonally i found version barrier very usefull and exceptionally smart move.
    it will be nice to add some kind of "soft" version barrier for non NMS plugins to wipe longdead plugins that still used due to lack of alternative.
     
  16. Offline

    desht

    Going to agree with RawCode Syd and mkremins here - there is one and only one safe way of using CraftBukkit/NMS methods, and that is to write your own API translation layer (like mbaxter did, and I did too) and manually validate and update it for each major (obfuscation-changing) release of CraftBukkit. It means you need to update and re-release plugins for each major CB release, and that is a pain, yes (but hardly impossible - I have two plugins that I do this for); but that's still better than introducing subtle (or devastating) bugs.

    While using reflection to get inside org.bukkit.craftbukkit code is likely to be less dangerous than reflecting NMS, it's still not risk-free, since there is precisely 0% guarantee that the meaning (or indeed existence) of these methods will remain stable. OBC is not an API, it's an implementation and your plugins depend on that implementation at their peril (or, more accurately, at the peril of those server admins who use them).

    "hardly ever" is just another way of saying "not never".
     
    mkremins and CaptainBern like this.
  17. Okay, in that case its very powerful. Good job mate!

    Also a potential way to fix this would be for a new field to be taken in the method, the expected amount of fields that it would return. If it's not the expected amount then something would be done, for example an exception thrown. Even if @Bigteddyd98 doesn't implement this into the above method then developers using it could implement it.

    The code would turn into something like this:

    Code:java
    1. public static List<Field> getFieldUsingType(Object yourClass, Class<?> clazz){
    2. getFieldUsingType(yourClass, clazz, -1);
    3. }
    4.  
    5. public static List<Field> getFieldUsingType(Object yourClass, Class<?> clazz, int expected){
    6. List<Field> tempList = new ArrayList<Field>();
    7. for(Field f : yourClass.getClass().getDeclaredFields()){
    8. if(f.getType().getName().equals(clazz.getName)){
    9. f.setAccesible(true);
    10. tempList.add(f);
    11. }
    12.  
    13. if (expected != -1 && tempList.size() != expected){
    14. throw new RuntimeException("Field count does not match expected value: expected = " + expected + ", actual = " + tempList.size()); // maybe a better exception type & better message?
    15. }
    16.  
    17. return tempList;
    18. }


    Again this is not a complete fix as something could still go wrong, but it helps to greatly minimize it.

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Jun 8, 2016
    bigteddy98 likes this.
  18. Offline

    lenis0012

    This makes no sense.
    Lets say i have 2 classes:
    Code:java
    1. public class A {
    2. private Channel k; //I WANT THIS
    3. }
    4.  
    5. public class B extends A {
    6. private boolean blabla;
    7. }


    I have an instance of B.
    And i want k.

    What do i do?
    Loop through all fields in B.class?
     
  19. Even though that is true, Bukkit does not always provide an API for things you need. For instance I wanted rollbacks in my anti grief plugin to be really fast. I found a way to set blocks way faster than can be done through the Bukkit API in a forum post. So I'm stuck with using NMS now...
     
  20. Offline

    bigteddy98

    Yep I get what you mean, that's my fault. You will have to add another parameter which specifies the class your field is in.
     
  21. Offline

    lenis0012

    bigteddy98 Or you loop through all super classes

    bigteddy98
    Code:java
    1. Class<?> sClass = yourClass.getClass();
    2. while(sClass != null) {
    3. for(Field f : sClass.getDeclaredFields()) {
    4. //Field check code, add to list etc.
    5. }
    6. sClass = sClass.getSuperClass();
    7. }


    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Jun 8, 2016
  22. Offline

    xTrollxDudex

    iKeirNez
    May want to change the clazz parameter to a String instead since you want to avoid using NMS imports in the first place right? Also, the type may be different from the instance provided, it's best to use a separate parameter for the class to get the field list from.
     
Thread Status:
Not open for further replies.

Share This Page