1.15.2 How to get started in NMS?

Discussion in 'Spigot Plugin Development' started by FullPotato, Jan 11, 2020.

  1. Hey everyone, been trying to start developing plugins, and a lot of things that I want to do involve diving into NMS. Are there any good up to date resources, videos, or guides on how to get started? Do you have any tips or tricks for a beginner in general? Anything and everything would be greatly appreciated.
     
  2. md_5

    Administrator Developer

    http://xyproblem.info/

    What do you want to do exactly?

    Probably about half of things which "involve diving into NMS" are people not realising an API exists for it
     
    • Agree Agree x 2
    • Like Like x 1
  3. You generally only use NMS if there is no other way to achieve your goals with the server API or you have a very explicit idea in mind.
    If you don't have a specific problem then we cant really give you advice other then:
    1) Google if someone had the same problem as you
    2) Build the spigot jar -> decompile it (with bytecodeviewer for example) and play around until you know what "b.s(a, b, c, d)" does

    PS
    Maintaining NMS over multiple versions is a pain in the a** unless you know how to use maven modules and properly use interfaces and other abstraction.
     
    • Informative Informative x 1
  4. The only two I have on mind right now:
    • Make custom mobs with custom items, AI, etc. (Like a modified boss-zombie, for example)
    • Have client-side glowing (So, like one player can see other players / entities through walls, but the other players can't see it)
     
    • Creative Creative x 1
  5. That NMS versioning was made by bukkit to prevent you from using it. In the original minecraft jar there's only net.minecraft.server
     
  6. Optic_Fusion1

    Resource Staff

    This is has been the case since 1.4.5 as well, anything below that is the same as the original server jar when it comes to class paths
     
  7. Client-side glowing could probably be done easier with ProtocolLib instead of NMS.

    For custom entities extend the entity type you want (EntityAnimal for animals, EntityMonster for monsters, etc...). Register a custom EntityTypes and register a custom data watcher for the entity you want it to be modeled after. Use GoalSelector to set movement goals and TargetSelector (or something like that) for combat goals. Look at vanilla goal classes for examples. Make sure to set the correct mutex flags or the entity will act weirdly.
    Use datawatcher to sync client-side data for that model (like collar color for wolfs, limb position for armorstands, etc...). All data must be the data of the entity model you are using or mc will drop it.
     
    • Informative Informative x 1
  8. I agree you should avoid using NMS as much as possible. But if you find the need (or are just really wanting to experiment so when you DO have a real need you know how) it's generally better, though more challenging, to use reflection instead of directly "importing" NMS classes. If you directly import the NMS classes you WILL have to modify your code with EVERY major minecraft version. Where as, when you use reflection you have a good chance that you will only need to sanity test things and make minimal, if any, changes.

    So, here's some info to get you started on using reflection & NMS...

    To help with the actual reflection part of the task I've used this library's code https://github.com/sainttx/Auctions...com/sainttx/auctions/util/ReflectionUtil.java and recently I shared some code to add a cancellable VillagerTradeEvent where I came up with an interesting pattern that I really liked (see https://www.spigotmc.org/threads/adding-a-cancellable-villagertradeevent.411963/).

    You will need to dig through the decompile/partially-deobfuscaed and patched source code. For that use the spigot buildtools (https://www.spigotmc.org/wiki/buildtools/) and build spigot locally. Then you can look in/search the .../Spigot/Spigot-Server and .../Spigot/Spigot-API directories (once you've run the build tool) to explore what is available and how to get at it (which is not an easy task at first!). You'll find the actual NMS source at .../Spigot/Spigot-Server/src/main/java/net/minecraft/server BUT you will also have to traipse through OCB (Spigot\Spigot-Server\src\main\java\org\bukkit\craftbukkit) code to figure out how to convert a "normal" .../Spigot/Spigot-API object into an NMS object (look for how to get at the 'handle' which is usually an NMS object). Then you get to reflect out the needed classes and methods or fields to do the job (again, see my VillagerTradeEvent contribution or search for other examples using reflection).

    Finally, now that Mojang is releasing the deobfuscation map, I've used this fork of the Enigma decompiler/deobfuscator (https://github.com/FabricMC/Enigma) to decompile the Mojang jar myself. This source code WILL NOT align perfectly with what you find in NMS - but it will be more complete (everything will have reasonable names) and you can compare code structure between the Spigot and "real" decompilations to figure out what that "a", "b", "c", ... field means). I couldn't decompile the server.jar for some reason (Enigma errored out) but really the client contains an internal server and so far I've found this adequate. Of course, you'll have to figure out how to build Enigma but it's reasonably strait forward (on windows run gradlew.bat build) then run the generated jar (in .../build/libs/), decompile your target jar, then Open Mappings > Proguard and select the deobfuscation map text file.

    Mojang publishes the jar download and deobfuscation map locations in the %appdata%/Roaming/.minecraft/versions/<VERSON>/<VERSION>.json file. I like this tool (http://jsonviewer.stack.hu/) for formatting the json - search for "client.jar" to get you to the right location.


    Enjoy drinking from the fire hose ;)
     
    • Informative Informative x 1
  9. wouldnt use reflection. its heavier and unnecessary. use abstraction to implement several versions of nms.
     
    • Agree Agree x 3
  10. Well, feel free to provide the OP with some useful examples.
     
    • Agree Agree x 1
    • Like Like x 1
    • Informative Informative x 1
  11. FrostedSnowman

    Resource Staff

    Well, you should note that not everything can be accessed across the nms implementations, reflection will be needed for some operations.
     
  12. Thanks everyone for your replies. It looks like I should try learning ProtocolLib for what I'm trying to do. NMS seems very complicated and I thank Ross for your mini-guide. I'll look into all of this in a bit.
     
  13. thats a given. i was simply stating not to use reflection to support multiple versions. ofc its necessary to access fields/methods/others that are otherwise not accessible or changeable.
     
  14. Choco

    Moderator

    There are cases where it's outright stupid not to. My VeinMiner plugin for instance accesses just one public and mapped NMS method. That's it. So I reflectively access it. So long as you're caching properly, there's a negligible performance impact. Abstraction is not a blanket solution to everything and sometimes reflection just makes more sense. I can assure you that I do not want to be releasing a new version every single update just to create a new abstraction implementation.
     
  15. thats fair. but to combat what seems to be the general premise of reflection on these forums, large projects spreading across many versions using many nms methods shouldnt use reflection, especially when abstraction makes a ton of sense for the case. its backbreaking and needlessly more difficult. but its the go to because its easier to follow for those who dont understand what oop is. sort of like static abuse. yes there are very special cases static should be used, including even as an access modifier (static util classes for example)

    @op a good tl;dr, it depends which is better. usually anything sizable youd want to use abstraction. but there are harmless or important exceptions where reflection is fine or necessary.