General Introduction of Packets & NMS
I saw so many devs trying to use nms and packets and ask me how to do, why should I use this ?
So in this tutorial I will explain why would you use packets ? How ? And avoid different versions issues.
Of course, you need a good knowledge of the bukkit/spigot api to use packets. Let's start...
I) Why should I use packets ?
What is a packet ? You probably have already heard about it during your life but the packet is the life itself !
When you are connected to a minecraft server, you can enjoy playing with thousand of players, you can actually see them thanks to the server which is sending you packets.
Magic.. Isn't it ?
There is one packet that every minecraft player knows:
This packet is named 'keep alive', the server send you each x seconds a packet that contains a unique identifier. The client must send a keep alive packet too, with the same identifier. If this is not the same: "TIMED OUT"
So why would you use a packet for ?
Personally, I am using it to display some things that I could not simply display without packets for example npcs.
Or to display only something to a unique player, a group of players...
For example if you want to give a unicorn horn to your friend, however you do not want unicorn visible for your friend but only for other players, you must use packets...
Don't be afraid, nms for net minecraft server.
This is one of the most important part of spigot, this is where everything is happening, entities, players, packets and so on. This is where you can find which packets to spawn and how.
You must decompile spigot to work on it ! (use jd-gui java 7 or luyten java 8)
You can find some examples:
As you can see something is wrong:
C) Incompatibility Issue
Here you can only use nms&packets for the version 1_9R1 or minecraft: 1.9.0
1_9R2 is 1.9.2
Check out this: https://www.spigotmc.org/wiki/spigot-nms-and-minecraft-versions/
In fact, the main issue by using nms is that after each minecraft update your code will no longer work and you must start everything over..
What ? start all over ??
Yes package name net.minecraft.server.v1_8_R1 can change its name.
net.minecraft.server.v1_8_R2 , net.minecraft.server.v1_9_R1, ect...
So every imports you made on your ide will change
When you are using Player p = (Player) sender;
You call import : org.bukkit.entity.Player;
However it will never change, this is why your plugin is still compatible.
Moreover, the code is obfuscated, it means that name of methods and variable could be modified.
For example if you would like to avoid entities hitbox with blocks you will use:
nmsEntity.noclip = true;
But sometimes it could be:
nmsEntity.a = true;
Your question is: how do I know which variable to use ? You must decompile and see it by yourself.
D) Incompatibility issue: solutions
Do not worry, you have 2 way for solving it.
First one, my favorite: you can use Reflection.
Second one, nms interfaces.
The reflection can be very scary at first but with the right tools it's great.
Which tools ?
I love using the reflection util class made by the author of procotollib
What reflection is ?
the main goal is to avoid calling the imports,
it allows to make code without taking up too much space
The problem are the performances because reflection does not know where to find what you would like to call, it has to go through all the classes of the code...
that's why it will be necessary to use special techniques to improve this !
It's fine if you do not want to come back and rework your reflection code you made.
You just need to create 1 class per nms version. You should check out this tutorial:
A) Entity Packet
1) Spawning entity with packet
2) Setting entity features
3) Update metadata
B) Other packets
III) Listening packets