1.8.8 NMS

Discussion in 'Spigot Plugin Development' started by Wilsoon, Feb 27, 2020.

  1. I've come to realise alot of people use this thing called net.minecraft.server (NMS). i tried searching spigotmc on what it is and found something called "NMS without reflection". However, I totally did not understand what that was. So, I get that NMS is some people's nightmare. However, may I request for anyone who has sufficient time to write for me on what NMS is, what does it mean by reflection of NMS, how would I implement it and how/when it's supposed to be used? I get that it's meant to support different versions, but in what way and how?
     
  2. drives_a_ford

    Moderator

    https://www.spigotmc.org/threads/nms-tutorials-1-introduction-to-nms.204127/
    https://riptutorial.com/bukkit/topic/9576/nms

    In a nutshell, NMS refers to the vanilla MC server software developed by Mojang. That's the "heart" of the server. Spigot builds on this software to create optimizations and allow plugins to hook into the game and change its dynamics.
    Since NMS is developed by Mojang, distribution of the source code is illegal. That's why you won't find many (there are probably a few) places that do that.

    As for reflection, you can just google that (to be honest, you can just google all this information).
     
  3. NMS is an abbreviation for net.minecraft.server like you mentioned. It contains the internal server code, similar to what you'd find in a Vanilla server JAR file (it's slightly modified, but it's generally the same). This is the main thing that operates the server - the API you work with most of the time only acts as a way of interacting with this internal server.

    Now the internal server is made by Mojang and is obfuscated: classes, methods and field names that would normally have 'normal' names, are turned into stuff like 'a', 'b', 'c', etc. Spigot provides mappings for some of these, which turn these names back into a normal human readable name, however not all of them are mapped, so you'll likely still encounter some of these. Interacting with NMS works similarly to how you normally interact with it: you import the class, get an instance of it in some way and then call methods on it.

    NMS however has some slight disadvantages. To start with, the package name contains a version number, which changes - you guessed it - every version. If you interact with NMS normally, you'll run into the issue where your plugin works on, say, 1.14, but not on 1.15, since now the package name has changed to 1.15 as well - your code still contains a reference to 1.14, but that doesn't exist, hence your plugin will break. Apart of that, the names that are not mapped (so the ones that are still obfuscated), can change every version. The obfuscation used doesn't guarantee that a certain field gets the same name next time, so when you refer to 'a' somewhere, on the next version this may very well be called 'c'. Obviously this causes issues, since now you're interacting with the wrong field/method.

    As you can see, just interacting with NMS like you interact with other stuff, isn't ideal. There are pretty much two options at this point, the first one is modularization. In essence, you 'remake' the part that uses NMS for each version. You specify the different package name everytime and change the names of the field and that way each piece of code works on every version you support. The plugin can then figure out which Minecraft version the server is running and call the right code. There are upsides and downsides to this approach: modularization means that you may need to write code for ten different versions, which takes a long time. However, you do get the advantage that your code works on every version you want and does exactly what you want.

    Option two is reflection (the methods above were 'without reflection'). This means that you instruct the server to look up the right class/method/field and then interact with that. Remember how the package name changes every time. So, to avoid that you don't say "I want package x", but you say "Look for package x". There's a subtle difference between those: the first one is the same every time, you cannot ask for package x and then for package y the next time. With the latter, you can. This enables you to say "Look up package x for the version this server is running". This way you get that package, then you can look for the class, then the method, call that and interact with NMS that way. This also has upsides and downsides: the upside is that you don't necessarily have to duplicate code, since you look up the right package, not state the package. The downside is that if the internal name changes, you still have to take that into account; reflection is also not incredibly fast, so if you do it often (especially when you don't cache objects) you may run into performance issues.

    As far your last question, typically you don't need NMS. The API supports most of the things you would want to do in a typical plugin. However, if you want more fine control or the API doesn't have what you want, interacting with NMS can be a good way to still achieve what you want.
     
  4. Thanks. However, there's something I don't seem to understand.

    You know there's stuff like net.minecraft.server.v1_8_R(number)
    Other than 1.8, why is there a R(number) behind?
     
  5. drives_a_ford

    Moderator

     
    • Like Like x 1
  6. NMS is something you will have to explore mostly yourself. There are some good videos on YouTube if you search for them and also there is a very good tutorial here. Also if you want to get into NMS programming you will need this. But one big disadvantage is that it's version dependent because package name changes with (almost) every new major Minecraft release.