Tutorial [INFO]Packets/NMS Explained

Discussion in 'Resources' started by xTrollxDudex, Sep 27, 2013.

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

    xTrollxDudex

    Hey guys, I'm back with another post in the resources section!

    This time it's all about packets and NMS and how to use them. Packets are relatively simple to use so that won't be too difficult. NMS is well, a bit harder but at the same time extremely difficult so most of this thread will be devoted to that.


    PACKETS
    Now, lets start with packets.
    1) Wtf is a packet?
    A packet is a bit of data (hence the name packet) sent from the server (Bukkit) to client (The person playing minecraft on the server) or vice versa. Some even can go both ways. But either way, they do specific things with minecraft and the client, like potions, teleports, stuff like that. But like bukkit, it has limitations to exactly (no more no less) what you can do with minecraft.

    2) HEY! Y U NO DO DIS FO ME??
    That's because there are certain functions packets can't do, like you can't make a new block in minecraft like instantly, you need to modify the client code or texture pack used (in the server.properties)

    3) Soo. How do I use this stuff?
    First, we have a full list of packets here: http://wiki.vg/Protocol
    Choose one from that list you would want for an effect (Some packets may confuse you a bit, for example if you want fake potions particles, you would use the metadata packet :p)
    You may need to look around a bit on https://github.com/Bukkit/mc-dev/blob/master/net/minecraft/server/ in order to match the packet with the one you found on wiki.vg.

    Say we have an imaginary character Player player and build on CraftBukkit (Use Bukkit too) and want to have an imaginary player like out character:
    PHP:
    CraftPlayer p = (CraftPlayerplayer;
    PacketPlayOutNamedEntitySpawn npc = new PacketPlayOutNamedEntitySpawn(p.getHandle());
     
    //the a field used to be public, we'll need to use reflection to access:
    try {
        
    Field field npc.getClass().getDeclaredField("a");
        
    field.setAccessable(true);// allows us to access the field
     
        
    field.setInt(npc123);// sets the field to an integer
        
    field.setAccessable(!field.isAccessable());//we want to stop accessing this now
    } catch(Exception x) {
        
    x.printStackTrace();
    }
     
    //now comes the sending
    p.getHandle().playerConnection.sendPacket(npc);
    You would import something like net.minecraft.server.v1_6_4.PacketPlayOutNamedEntitySpawn and CraftPlayer from CraftBukkit. (Will change each version, needs constant updating)

    There! Simple isn't it?

    4) This isn't working...
    Sometimes, packets can be very obscure by making the fields in the packet class private or not make a proper constructor, you can either access with reflection (which I won't outline) or just use the instance of the class and modify the field directly like in the example on step 3.

    There are sometimes, also packets that need to use PlayerConnection#a(Packet)
    A few of these packets that require they use of "a" instead of sendPacket can be found in the PlayerConnection class: https://github.com/Bukkit/mc-dev/blob/master/net/minecraft/server/PlayerConnection.java

    5) Then what's ProtocolLib for?
    The main difference between ProtocolLib and direct packet use is ProtocolLib deals with incoming packet streams and intercepting them, and packet injection, in a safe, reliable manner. As long as you have an updated version of ProtocolLib, you shouldn't need to worry about imports, but each version on minecraft has a different protocol so you will need to directly change the imports in your code.

    EDIT: okay thanks to Cirno, you don't need to scroll down to learn reflection :D
    6) Basic reflection
    6) Still not working. I don't understand this!
    It doesn't take too much java knowledge to figure out what each field and method does in the packet class. Even though each field is like, a, b, c, d and stuff, visit the protocol listing to figure out which field corresponds with the function. You can also figure out the usage of the field by seeing how it is initialized in the constructor. Don't copy paste the code from step 3, the packet.a sets a value within the class before being sent. Looking in the source, this is the entity id:
    PHP:
    package net.minecraft.server;
     
    import java.util.List;
     
    import net.minecraft.util.com.mojang.authlib.GameProfile;
     
    public class 
    PacketPlayOutNamedEntitySpawn extends Packet {
     
        private 
    int a// here
        
    private GameProfile b;
        private 
    int c;
        private 
    int d;
        private 
    int e;
        private 
    byte f;
        private 
    byte g;
        private 
    int h;
        private 
    DataWatcher i;
        private List 
    j;
     
        public 
    PacketPlayOutNamedEntitySpawn() {}
     
        public 
    PacketPlayOutNamedEntitySpawn(EntityHuman entityhuman) {
            
    this.entityhuman.getId(); // and here
            
    this.entityhuman.getProfile();
            
    this.MathHelper.floor(entityhuman.locX 32.0D);
            
    this.MathHelper.floor(entityhuman.locY 32.0D);
            
    this.MathHelper.floor(entityhuman.locZ 32.0D);
            
    this.= (byte) ((int) (entityhuman.yaw 256.0F 360.0F));
            
    this.= (byte) ((int) (entityhuman.pitch 256.0F 360.0F));
            
    ItemStack itemstack entityhuman.inventory.getItemInHand();
     
            
    this.itemstack == null Item.b(itemstack.getItem());
            
    this.entityhuman.getDataWatcher();
        }
     
        public 
    void a(PacketDataSerializer packetdataserializer) {
            
    this.packetdataserializer.a();
            
    this.= new GameProfile(packetdataserializer.c(36), packetdataserializer.c(16));
            
    this.packetdataserializer.readInt();
            
    this.packetdataserializer.readInt();
            
    this.packetdataserializer.readInt();
            
    this.packetdataserializer.readByte();
            
    this.packetdataserializer.readByte();
            
    this.packetdataserializer.readShort();
            
    this.DataWatcher.b(packetdataserializer);
        }
     
        public 
    void b(PacketDataSerializer packetdataserializer) {
            
    packetdataserializer.b(this.a);
            
    packetdataserializer.a(this.b.getId());
            
    packetdataserializer.a(this.b.getName());
            
    packetdataserializer.writeInt(this.c);
            
    packetdataserializer.writeInt(this.d);
            
    packetdataserializer.writeInt(this.e);
            
    packetdataserializer.writeByte(this.f);
            
    packetdataserializer.writeByte(this.g);
            
    packetdataserializer.writeShort(this.h);
            
    this.i.a(packetdataserializer);
        }
     
        public 
    void a(PacketPlayOutListener packetplayoutlistener) {
            
    packetplayoutlistener.a(this);
        }
     
        public 
    String b() {
            return 
    String.format("id=%d, gameProfile=\'%s\', x=%.2f, y=%.2f, z=%.2f, carried=%d", new Object[] { Integer.valueOf(this.a), this.bFloat.valueOf((float) this.32.0F), Float.valueOf((float) this.32.0F), Float.valueOf((float) this.32.0F), Integer.valueOf(this.h)});
        }
    }
    As you can see, it is initialized to the player's ID, which we don't want as it conflicts with an existing entity. Therefore, I use packet.a = 123; to change the entity I'd manually so no conflicts happen.

    Don't change the field manually unless you happen to know exactly what you are doing and how changing the field affects the client and server.

    NMS
    Onto NMS!
    1) Wtf is NMS, this even sounds fancier than Packets!
    NMS stands for net.minecraft.server, the DNA(You have to know what that stands for) of CraftBukkit. It's the core of a minecraft server, it runs Packets, provides the basis for the minecraft client to interact with the server. Without it, there would be no server.

    2) Sounds good to me. How do I take advantage of this?
    Compared to packets, this is wayyyy harder if you don't already know how to use it. Navigate to
    https://github.com/Bukkit/mc-dev/blob/master/net/minecraft/server/ and see how many classes there are. Each class represents an element to the console or the server version of minecraft. Furthermore, there is no javadoc, AND it's obfuscated(most methods/fields are renamed to protect from people stealing minecraft) but is relatively easy to figure out from the method body. NMS can be used for various things such as finding villages, send packets, control entities, creating customized (NOT new) entites/blocks, and among several other things the normal Bukkit API doesn't do.

    Then there are limitations, of course starting with non-minecraft elements, and you need to update NMS imports every version. Ex:
    PHP:
    //1.4.7 CraftPlayer
    import net.minecraft.server.v1_4_R1.CraftPlayer;
     
    //1.6.4 CraftPlayer
    import net.minecraft.server.v1_6_R3.CraftPlayer;
    Then there's how to use them... Jacek made a nice tutorial heavily using NMS in resources too, it involves overriding normal methods of an entity to make it harder to fight with (new navigation, skeletons shoot 2 arrows :p ect...). This depends a lot on what you are trying to do, as there is no "specific" way to use NMS.

    3) HOW TO USE
    There are too many examples of NMS for me to list, so here's a small sample of what can be done:
    • Packets
    • Entity behavior
    • Navigation
    • Finding specific things in a world, villages for example
    • Biome control
    There are 2 of he most often used ways to use NMS: Extending the class, and taking the connection/properties/fields/attributes of a class and modifying them.

    Again, the best example of the first method is Jacek's custom mob tutorial.

    Modifying the properties of the class is a bit different, you can also call the various private/unavailable methods to the Bukkit API such as in the navigation class. This can be taken from any Entity that is has an EntityInsentient superclass by using the getNavigation() method. From here, you can use Navigation.a(x, y, z, speed) to make the entity move to the location a specific speed.

    Often, you can spend a few hours looking at all the obfuscated methods and fields trying to find the usage of the method. Just look at the body and see what it does. If you want take n specific field that's private, use reflection. If you want to call a private method, use reflection.

    Protip: anything with this.(something) most likely means that it is a method taken from a superclass of a superclass, as super means it's taken from the direct superclass.

    4) Last thing
    I can only outline what little I can about the vast field of NMS and Packets usages and applications. If you would like to suggest something, please post!

    TO BE CONTINUED
     
  2. Offline

    T0pAz7

    I learned 2% today.
     
    candyfloss20 likes this.
  3. Offline

    Garris0n

    That signature got me for a second...
     
  4. Offline

    xTrollxDudex

  5. Offline

    xxNightlordx

    Haha, that's smart :D
     
  6. xTrollxDudex I also wanted to write a packets tutorial, but you ninja'd me :( ; gj tho...
     
  7. Offline

    xTrollxDudex

    CaptainBern likes this.
  8. Offline

    Cirno

    I'll just outline how to use Reflection because without Reflection, some packets would just crash the player.
    Show Spoiler

    1) Reflection, what is it, what does it allow you to do?
    Ever coded something that says "protected", "private", or just no modifier at all and thought "Boy, this will never be changed outside of this class/package!" You're wrong. Horribly wrong.

    A real life situation is like this:
    You have a friend (representing something that has access).
    You give your car keys to him. (Your car keys represent something unobtainable outside of a class)
    Sounds great right? You gave your keys to a friend. Now big ole' Reflection comes around, and steals it from him.
    Wait, what?

    This is Reflection; it's a wonderful thing, but also a dangerous thing. It allows you to access every variable and class you can think of. Protected? Private? Nope. Reflection will get it for you.

    2) So now that a thug has stolen my keys, how do I steal them back? (How to use Reflection)
    Simple, yet difficult. Reflection's nature isn't exactly the safest, or easiest. Let's say you have these classes:

    Code:java
    1. public class Me {
    2. private CarKeys carkeys;
    3. public static void Me instance;
    4. public Thug stealer;
    5.  
    6. public Me(){
    7. instance = this;
    8. }
    9.  
    10. public void stealCarKeys(){
    11. //Input reflection stuffys.
    12. }
    13.  
    14. public void setCarkeys(CarKeys keys){
    15. this.carkeys = keys;
    16. }
    17. }


    Code:java
    1. public class Thug {
    2. private CarKey stolenCarkeys;
    3. public static void Thug instance;
    4.  
    5. public Thug(){
    6. instance = this;
    7. }
    8. }


    Now, being the stealee, you want to steal your keys back. Obviously, we can't just do:
    Code:java
    1. myCarkeys = anInstanceOfThug.stolenCarkeys;

    because class "Me" doesn't have access to stolenCarkeys; it's private. Only code within Thug can use it.
    Until you get Reflection. It's a bit knarly, but here's how to start.

    Code:java
    1.  
    2. public void stealCarKeys(){
    3. Field carkeysField;
    4.  
    5. try {
    6. carkeysField = Thug.getClass().getDeclaredField("stolenCarkeys");
    7. e.printStackTrace();
    8. }
    9. }


    Great. Now we know where the car keys are. Now we need to get access to it. How? Simple. Under carkeysField, put in this code:
    Code:java
    1. carkeysField.setAccessible(true);


    setAccessiable basically means that we request permission to access this field. Note that in the try-catch, we can get a SecurityException. Normally, we don't need to worry about this, since most Java installations don't have security managers installed.

    Hooray! We can now access it! Now let's get() it.

    Code:java
    1. CarKeys keys = (CarKeys)carkeysField.get(Me.instance.getStealer());

    Note that we have to cast CarKeys to the get() method, because when you do Field.get(), it returns an Object.
    Then we can finally do:
    Code:java
    1. Me.instance.setCarkeys(keys);
    2. carkeysField.set(Thug.instance, null);


    So what did we just do?
    • We got a Field object by the name of "carkeysField".
    • We used said Field object to basically get the keys object and set the Thug's keys to nothing.


    This probably doesn't make much sense. The reason I'm posting it here is because it's a basic outline of it; I feel it's too short to put it into it's own "tutorial" thread. However, you're free to yell/tell me to move it into my own thread :p

    A tutortial that probably makes more sense:
    http://docs.oracle.com/javase/tutorial/reflect/
     
    xTrollxDudex and Ultimate_n00b like this.
  9. Offline

    xTrollxDudex

    That's and understatement. Feel free to tell/yell at me to remove this from OP :3
     
  10. Offline

    ducky299

    Great tutorial/explanation, I got your example working but I cannot get other packets working :S

    Is there any chance someone could provide me with another packet example like creating block break particles (http://wiki.vg/Protocol#Effect ?). It would be a great help!
     
  11. Offline

    xTrollxDudex

    ducky299
    Often it would be much easier to use a lib such as DarkBladee12 's to spawn particles. However, if you are able to do so, use reflection to access each of the private property fields in Packet63WorldParticles.

    Or if you would like to use block break particles, you can just use the World#playEffect(...) method.
     
  12. Offline

    ducky299

    xTrollxDudex

    I get ultra scared about depending on libraries sometimes, and I also like to be able to say that I made something that is independent.

    I was using World.playEffect, but it seams to come up with a sound for block break particles, plus once I found out about all the things I thought I couldn't I could do with Packets I didn't want to stick to .playEffect. Basically this Lava block thing is a starter to get me going.

    Already I have crashed my client. A lot.
     
  13. Offline

    xTrollxDudex

    ducky299
    It shouldn't be a scary thing, just copy paste the class into your own package, lots of professional coders do that. It's perfectly fine.
     
  14. Offline

    DevRosemberg

    CaptainBern You can also write a Packets tutorial. You and xTrollxDudex are the best Packet and Reflection guys i know on the forums. Or maybe you should create a Tutorial Together.
     
  15. Offline

    xTrollxDudex

    Yeah. We can be competitors CaptainBern
     
  16. Offline

    DevRosemberg

  17. Offline

    amhokies

    Since when can you use void in anything other than a method? 0.0
     
    afistofirony likes this.
  18. Offline

    Cirno

    oopse; I was copy+pasting some of my code when I was making it lol. I'll start writing a better one now.

    edit: later. i need to get my degree in procrastination, but i think i'll do that later.
     
    amhokies likes this.
  19. Offline

    xTrollxDudex

    What happened to your plugins?
     
  20. Offline

    DevRosemberg

  21. DevRosemberg I would love too, but at the moment my internet is as good as dead. (It takes up to ten minutes to load a page, and the layout hasnt been rendered then). Thats also the reason why I'm not that much online this week...
     
  22. Offline

    DevRosemberg

  23. Offline

    xTrollxDudex

    Ya good yet? Let's see that packet tutorial.

    Nvm, I think I'll just look at AnimationLib :p
     
  24. Offline

    xTrollxDudex

    Will update to 1.7.2 soon.
     
  25. Offline

    BungeeTheCookie

    Sooooon. GG
     
    xTrollxDudex likes this.
  26. Offline

    xTrollxDudex

  27. Offline

    BungeeTheCookie

  28. Offline

    AzubuSan

  29. Offline

    xTrollxDudex

    Glad to see some activity in this thread for once, you're welcome :)
     
Thread Status:
Not open for further replies.

Share This Page