[NOW WORKING] Using NMS and OBC Without Your Plugins Breaking [No Reflection Involved]

Discussion in 'Resources' started by BungeeTheCookie, Apr 18, 2014.

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

    BungeeTheCookie

    The Version Checker
    WARNING: I HAVE BEEN NOTIFIED THAT IF YOU USE THIS CLASS, SOMETIMES YOU WILL GET A NoClassDefFoundException. SEE MY THREAD ABOUT CLASS MAPPING TO FIX THIS.

    Introduction
    Haven't you always wanted to tap into the secret sauce of Minecraft and use it to your own benefit without having your plugins break on every update? Sure you have! Luckily, we have reflection, which is a pain-in-the-butt and takes valuable time to learn, but that reflection isn't always reliable as well (for example, it broke all NMS-related plugins in the 1.7 update, even the ones with reflection due to class changes and re-structuring of internal code.) How do we use NMS and OBC without having our plugins break on every update, and without using reflection??? I have come up with a solution. No, it is not a 20 class library. It is not a modification to CraftBukkit. It is only a one class library, very short and sweet. When you see it you will say, "Why the didn't I think of that?"
    Usage
    This little class basically gets the current version of Bukkit that is on the server and sees if it equals another version. It returns a boolean, so it's only value is to use it in an if() or else() statement.

    Example:
    PHP:
    package bungeecookie.mineworks.api.nms;
     
    import net.minecraft.server.v1_7_R1.EntityPlayer;
    import net.minecraft.server.v1_7_R1.EnumClientCommand;
    import net.minecraft.server.v1_7_R1.PacketPlayInClientCommand;
     
    import org.bukkit.craftbukkit.v1_7_R1.entity.CraftPlayer;
    import org.bukkit.entity.Player;
    import org.bukkit.event.EventHandler;
    import org.bukkit.event.EventPriority;
    import org.bukkit.event.Listener;
    import org.bukkit.event.entity.PlayerDeathEvent;
     
    public class 
    AutoRespawn implements Listener {
     
        @
    EventHandler(priority EventPriority.HIGHEST)
        public 
    void onRespawn(PlayerDeathEvent e){
     
            
    Player p e.getEntity();
            if(
    VersionHandler.is1_7_2()){
                
    PacketPlayInClientCommand in = new PacketPlayInClientCommand(EnumClientCommand.PERFORM_RESPAWN); // Gets the packet class
                
    EntityPlayer cPlayer = ((CraftPlayer)p).getHandle(); // Gets the EntityPlayer class
                
    cPlayer.playerConnection.a(in); // Handles the rest of it
            
    }
     
            else if(
    VersionHandler.is1_6_4()){
                try {
                    
    Object nmsPlayer p.getClass().getMethod("getHandle").invoke(p);
                    
    Object packet = Class.forName(nmsPlayer.getClass().getPackage().getName() + ".Packet205ClientCommand").newInstance();
                    
    packet.getClass().getField("a").set(packet1);
                    
    Object con nmsPlayer.getClass().getField("playerConnection").get(nmsPlayer);
                    
    con.getClass().getMethod("a"packet.getClass()).invoke(conpacket);
                } catch (
    Throwable ex) {
                    
    ex.printStackTrace();
                }
            }
        }
     
    }
    Conclusion:
    To end this awesome resource, I am going to post the code. If you need any help, suggestions, or ideas, please tag me using BungeeTheCookie. If you enjoyed it, please take 2 seconds of your time and leave a like or post a comment, just to show that people enjoyed it.
    PHP:
    import org.bukkit.Bukkit;
     
    public class 
    VersionHandler {
     
        public static 
    boolean is1_2_5(){
            if(
    Bukkit.getVersion().contains("1.2.5")){
                return 
    true;
            }
            return 
    false;
        }
        public static 
    boolean is1_3_2(){
            if(
    Bukkit.getVersion().contains("1.3.2")){
                return 
    true;
            }
            return 
    false;
        }
        public static 
    boolean is1_4_7(){
            if(
    Bukkit.getVersion().contains("1.4.7")){
                return 
    true;
            }
            return 
    false;
        }
        public static 
    boolean is1_5_2(){
            if(
    Bukkit.getVersion().contains("1.5.2")){
                return 
    true;
            }
            return 
    false;
        }
        public static 
    boolean is1_6_2(){
            if(
    Bukkit.getVersion().contains("1.6.2")){
                return 
    true;
            }
            return 
    false;
        }
        public static 
    boolean is1_6_4(){
            if(
    Bukkit.getVersion().contains("1.6.4")){
                return 
    true;
            }
            return 
    false;
        }
     
        public static 
    boolean is1_7_2(){
            if(
    Bukkit.getVersion().contains("1.7") && Bukkit.getServer().getClass().getPackage().getName().contains("R1")){
                return 
    true;
            }
            return 
    false;
        }
     
        public static 
    boolean is1_7_9(){
            if(
    Bukkit.getVersion().contains("1.7") && Bukkit.getServer().getClass().getPackage().getName().contains("R3")){
                return 
    true;
            }
            return 
    false;
        }
     
        public static 
    boolean matchesVersion(String s){
            if(
    Bukkit.getVersion().contains(s) || Bukkit.getServer().getClass().getPackage().getName().contains(s)){
                return 
    true;
            }
            return 
    false;
        }
    }
    Reserved.

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

    xTrollxDudex

    BungeeTheCookie
    Well, uh, I kinda overestimated the meaning of "short/sweet" :p
     
    TigerHix and KingFaris11 like this.
  3. Offline

    BungeeTheCookie

    :p
     
  4. Could I just ask - does that code automatically respawn players?
     
  5. Offline

    BungeeTheCookie

    Yes.
     
    KingFaris11 likes this.
  6. You're amazing. =P
     
  7. Offline

    bobacadodl

    Code:
    public static String getPackageVersion() {
            try {
                Class<?> serverClass = plugin.getServer().getClass();
                if (serverClass.getName().contains("CraftServer")) {
                    String packageName = serverClass.getPackage().getName();
                    int dotIndex = packageName.lastIndexOf('.');
                    if (dotIndex != -1) {
                        return packageName.substring(dotIndex + 1);
                    }
                }
            } catch (NoClassDefFoundError e) {
                plugin.getLogger().severe(
                        "You seem to have a pretty modified version of CraftBukkit. " +
                                "This will cause the plugin to fallback to the default implementation, and may not function properly.");
                if(debug)
                    e.printStackTrace();
            }
            return null;
        }
    I personally like using this method instead. It returns the package name, which you can then use in reflection to get nms/cb classes, so its a bit more helpful
     
    Comphenix and KingFaris11 like this.
  8. Offline

    BungeeTheCookie

    Cool! I designed this class so I can avoid using reflection, so I just made a simple is_VERSION() method for people who don't use reflection. But that works too!

    KingFaris11
    Thanks! I try my best.

    For those of you who enjoy the old days of Redpower, Hexxit, Tekkit Classic, or other outdated modpacks (I cannot find any other reason why you would want to play on 1.2.5), I have added support from 1.2.5 up to 1.7.8! I also added a matchesVersion boolean so you can match the version you want to another.

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

    RainoBoy97

    I compressed your VersionHandler to this :p
     
  10. Offline

    BungeeTheCookie

    Thanks! I do enjoy me some HasteBin.
     
  11. Offline

    ccrama

    Instead of EqualsIgnoreCase, many times Bukkit.getVersion() returns something like git-Bukkit-1.7.2-R0.3-b3020jnks (MC: 1.7.2). A better method would be Bukkit.getVersion().contains("1.7.2")!
     
  12. Offline

    TigerHix

    This still breaks when a new version appears..
     
    Ultimate_n00b likes this.
  13. Offline

    BungeeTheCookie

  14. Offline

    TigerHix

    BungeeTheCookie Nope, I mean if someday Bukkit is on 1.8.2 and my plugin which uses your VersionHandler only handles conditions under 1.7.2 and 1.7.8, my plugin still breaks.
     
  15. Offline

    BungeeTheCookie

    TigerHix
    This plugin is intended to allow plugins to be backwards compatible and avoiding using reflection. You can always uses matchesVersion
     
  16. Offline

    RawCode

    without having our plugins break on every update
    +
    import net.minecraft.server.v1_7_R1.PacketPlayInClientCommand;

    you tutorial is invalid.
     
    bigteddy98 likes this.
  17. Offline

    BungeeTheCookie

    Have you even read it? Or did you just simply look at the code? This tutorial prevents plugins from breaking because it uses a boolean that can be used in an if statement..
     
  18. Offline

    TigerHix


    You still don't understand. When Bukkit has a update, server owner updates, the Bukkit version changes, and any plugin using this VersionHandler will be f-ed up.. Instead if we use reflection, at least there's a chance that internal classes are not changed unlike 1.7 huge update, there's a change plugins still run well. So I don't see any reasons that using your class can "use nms and obc without plugins breaking".
     
    bigteddy98 likes this.
  19. Offline

    Ultimate_n00b

    This ^
     
    TigerHix likes this.
  20. Offline

    BungeeTheCookie

    Actually, I completely understand what you are talking about. I am actually very familiar with how NMS and OBC break your plugins. I designed this class to allow plugin devs to make plugins be backwards compatible with other versions. Here is an example. If a server owner designs a plugin to use with 1.7.9 which uses NMS, and a guy wants to use it with 1.6.4 or 1.5.2 (say you are using a multi-version Bungeecord server and are using a backend) you will just put in the if() statement so your plugin can handle 2 - 10 versions.
     
  21. Offline

    awesomelemonade

    Even though I am not familiar with NMS... I see an error with the is1_7_5 method..

    It is checking if it contains 1.7.2, not 1.7.5
     
  22. Offline

    BungeeTheCookie

    Fixed.
     
  23. Offline

    RawCode

    run your "super tutorial code" on 162 and post stacktrace, its not ok to post random tutorials about things you not understand.
     
  24. Offline

    BungeeTheCookie

    What?
     
  25. BungeeTheCookie In your tutorial code you are importing 1.7.x code, so your class wouldn't work on any other version because it would throw a ClassDefNotFoundException. Just change everything to reflection like you did if the version is 1.6.

    Edit: it would be NoClassDefFoundException ofcourse.
     
    TigerHix likes this.
  26. Offline

    bigteddy98

    You might also be able to do something like this (don't import, just type out the whole path for every version), although I am not sure if this does work:
    Code:java
    1. net.minecraft.server.v1_7_R1.PacketPlayInClientCommand in = new net.minecraft.server.v1_7_R1.PacketPlayInClientCommand(net.minecraft.server.v1_7_R1.EnumClientCommand.PERFORM_RESPAWN);
     
  27. Offline

    TigerHix

  28. Offline

    BungeeTheCookie

    You use an if else statement. If a version is 1.7.2, then do 1.7.2 NMS, else use 1.6.4 NMS else do nothing

    You could do that too

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

    ccrama

    BungeeTheCookie bigteddy98 Tried that a few days ago, server kept spitting could not find class, and was trying to call classes based on other versions not specified in the if statement.

    Also, I highly recommend throwing in revision support, as 1.7.2 has three different revisions (for example), and each one has different NMS paths.

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

    bigteddy98

    aah okay, great to know.
     
Thread Status:
Not open for further replies.

Share This Page