[Tutorial] Class Mapping: How to CORRECTLY Use NMS Without Your Plugins Breaking

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

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

    BungeeTheCookie

    WARNING: If You Do Not Read My Post About The "Using NMS and OBC Without Your Plugins Breaking", half of this post will probably not make any sense.

    Hello people of the Bukkit Forums! On my last resource thread I created a resource called the Version Handler, but I have been notified of people getting a NoClassDefFoundError. This is because an NMS class is being initialized even though it doesn't even exist, still causing a breakage.

    For Example, if you do
    Code:java
    1. if(VersionHandler.is1_6_4()){
    2. net.minecraft.server.v1_6_R3.MinecraftServer.getServer().stop();
    3. }else if(VersionHandler.is1_7_2()){
    4. net.minecraft.server.v1_7_R1.MinecraftServer.getServer().stop();
    5. }

    your plugin will still break, because the class is being initialized before it even gets used. When I made this utility, I never knew that. So basically, what you do to fix this is a little trick called Class Mapping. What you do is have a separate class that stores all the NMS you want to use for a specific version. For example, if you have a plugin based on entirely NMS, you would take all of your classes that have NMS (except for the JavaPlugin, if that has NMS just move it to a separate class,) create a package called nms.v1_7_1R, nms.v1_6_R3, etc. and put all of your NMS in there. Now create all of your new NMS classes for another version you want to support, and put them in another package. Now you can access them. (I typed this up in the morning and I probably did a poor job explaining it. Here is what I mean)

    NMS Class 1: Version 1.6.4
    Code:
    package bungeecookie.mineworks.nms.v1_6_R3;
     
    public class AutoRespawn{
     
      public static void autoRespawn(Player p){
                try {
                    Object nmsPlayer = p.getClass().getMethod("getHandle").invoke(p);
                    Object packet = Class.forName(nmsPlayer.getClass().getPackage().getName() + ".Packet205ClientCommand").newInstance();
                    packet.getClass().getField("a").set(packet, 1);
                    Object con = nmsPlayer.getClass().getField("playerConnection").get(nmsPlayer);
                    con.getClass().getMethod("a", packet.getClass()).invoke(con, packet);
                } catch (Throwable ex) {
                    ex.printStackTrace();
                }
            }
      }
    }
    NMS Class 2: Version 1.7.2
    Code:
    package bungeecookie.mineworks.nms.v1_7_1R;
     
    public class AutoRespawn{
     
      public static void autoRespawn(Player p){
          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
      }
    }

    The Actual AutoRespawn Class That Handles All Of This
    PHP:
    public class AutoRespawn implements Listener{
     
      @
    EventHandler(EventPriority.HIGHEST)
      public 
    void performAutoRespawn(PlayerDeathEvent e){
          if(
    VersionHandler.is1_6_4()){
            
    bungeecookie.mineworks.nms.v1_6_R3.AutoRespawn.performRespawn(e.getPlayer);
          }else if(
    VersionHandler.is1_7_2()){
            
    bungeecookie.mineworks.nms.1_7_R1.AutoRespawn.performRespawn(e.getPlayer); 
          }
    }
    By using this quick and efficient method, you are able to use NMS and OBC without your plugins breaking without reflection! Even though you need to add a few extra classes and multiple craftbukkit versions to your build path, it will benefit you in the long run. If you have any questions, tag me using BungeeTheCookie. I hope you enjoyed this tutorial!
     
  2. Offline

    TigerHix

    Well, I would still use Reflections instead.
     
  3. Offline

    bigteddy98

    You are doing:
    Code:java
    1. else if(VersionHandler.is1_7_2()){
    2. net.minecraft.server.v1_7_R1.MinecraftServer.getServer().stop();
    3. }

    Where you still don't know if it's a 1.7.2, 1.7.5 or a 1.7.9 build, you should change is to is1_7_2_R1 etc.

    -BigTeddy98, Sander.
     
    TigerHix likes this.
  4. Offline

    BungeeTheCookie

    :mad:

    bigteddy98
    All in good time, my good teddybear.
     
    TigerHix and bigteddy98 like this.
  5. Offline

    BungeeTheCookie

    bigteddy98
    I added more checks so it should work now. See my original post.
     
  6. Offline

    bigteddy98

    Great, looks nice now ;)
     
  7. Offline

    BungeeTheCookie

    :p Thanks!
     
Thread Status:
Not open for further replies.

Share This Page