A Java library for generating multi-version NMS accessors.
Mappings generated by this library can be browsed here.
Disclaimer
These mappings are provided "AS-IS", with no warranty, so mistakes are possible. We are only solving issues in classes, that we are actively using in ScreamingSandals plugins.
If you want to fix anything, feel free to open a pull request or contact us on our Discord server.
NMSMapper is made for servers! Many client-side mappings are missing.
Warning
Usage of this Gradle plugin requires significant knowledge of Java Reflection!
This project requires Gradle >= 7.0. Maven is not supported. At least JDK 11 is needed for compiling, however the compiled classes use only Java 8 methods.
Download the latest jar file from here and save it in your project.
Create a groovy file (example: nms.groovy). Contents of this file will be similar like when using Gradle, however this time only nmsGen section and its content is present.
Run the generation using: java -jar nms-mapper-standalone.jar -b nms.groovy
/* First add a new source set. Don't use your main source set for generated stuff. */sourceSets.main.java{srcDir'src/generated/java'// adds new directory to the source set}/* All other things will be set inside the nmsGen method. */nmsGen{basePackage="com.example.nms.accessors"// All generated classes will be in this package.sourceSet="src/generated/java"// All generated classes will be part of this source set.minMinecraftVersion="1.8.8"// Optional, default value is 1.9.4maxMinecraftVersion="1.18.2"// Optional, default value is the last known versionnullableAnnotation="org.jetbrains.annotations.Nullable"// Optional, nullable return types or parameters will be annotated with this if presentnotNullAnnotation="org.jetbrains.annotations.NotNull"// (not used yet) Optional, not-null return type or parameters will be annotated with this if presentaddInformationJavadoc=true// Optional, default value is truemapForPlatforms=["searge","spigot"]// Optional, default value is ["searge", "spigot"]/* * This means that the folder will be cleared before generation. * * If this value is false, old no longer used classes won't be removed. */cleanOnRebuild=true}
1 2 3 4 5 6 7 8 91011121314151617181920212223
/* First add a new source set. Don't use your main source set for generated stuff. */sourceSets["main"].java{srcDir("src/generated/java")// adds new directory to the source set}/* All other things will be set inside the nmsGen method. */nmsGen{basePackage="com.example.nms.accessors"// All generated classes will be in this package.sourceSet="src/generated/java"// All generated classes will be part of this source set.minMinecraftVersion="1.8.8"// Optional, default value is 1.9.4maxMinecraftVersion="1.18.2"// Optional, default value is the last known versionnullableAnnotation="org.jetbrains.annotations.Nullable"// Optional, nullable return types or parameters will be annotated with this if presentnotNullAnnotation="org.jetbrains.annotations.NotNull"// (not used yet) Optional, not-null return type or parameters will be annotated with this if presentisAddInformationJavadoc=true// Optional, default value is truemapForPlatforms=listOf("searge","spigot")// Optional, default value is listOf("searge", "spigot")/* * This means that the folder will be cleared before generation. * * If this value is false, old no longer used classes won't be removed. */isCleanOnRebuild=true}
We want to access the net.minecraft.core.Rotations class in our plugin. The following method generates a new class, named RotationsAccessor, which you can use to retrieve the type.
12345
nmsGen{/* Setup, see the chapter before */reqClass('net.minecraft.core.Rotations')}
12345
nmsGen{/* Setup, see the chapter before */reqClass("net.minecraft.core.Rotations")}
The generated code looks like this (without javadocs):
We can see that we got a new static method, named getType(), which returns a class based on the version and platform (Spigot and Forge is supported).
Okay, we have a class. But classes are not all, we also need to access some fields, methods or even constructors.
1 2 3 4 5 6 7 8 910111213
nmsGen{/* Setup, see the chapter before */reqClass('net.minecraft.core.Rotations'){reqConstructor(float,float,float)reqField('x')reqField('y')reqField('z')reqMethod('getX')reqMethod('getY')reqMethod('getZ')}}
1 2 3 4 5 6 7 8 910111213
nmsGen{/* Setup, see the chapter before */reqClass("net.minecraft.core.Rotations"){reqConstructor("float","float","float")reqField("x")reqField("y")reqField("z")reqMethod("getX")reqMethod("getY")reqMethod("getZ")}}
This will generate access methods for one constructor, three fields and three methods.
A generated access method for a field will always be called getField<Name> and will always return Field.
A generated access method for a constructor will always be called getConstructor<Index> and will always return Constructor<?>. This index is generated from the specified order in build.gradle.
A generated access method for a method will always be called getMethod<Name><Index> and will always return Method. Here the index is present, because multiple methods can have other parameters, but the same name.
Info
If a class, a field, a method or a constructor is not found, null is returned.
Maybe you are asking: How to define parameters to methods? It's actually pretty easy, and the same applies to constructors:
1 2 3 4 5 6 7 8 910
nmsGen{/* Setup, see the chapter before */varLevel=reqClass('net.minecraft.world.level.Level')reqClass('net.minecraft.world.entity.decoration.ArmorStand'){reqConstructor(Level,double,double,double)reqMethod('setSmall',boolean)}}
1 2 3 4 5 6 7 8 910
nmsGen{/* Setup, see the chapter before */valLevel=reqClass("net.minecraft.world.level.Level")reqClass("net.minecraft.world.entity.decoration.ArmorStand"){reqConstructor(Level,"double","double","double")reqMethod("setSmall","boolean")}}
Parameters can be classes (e.g. String.class, in Groovy you don't have to specify the .class suffix), strings (java.lang.String) or a requested class (in this example it's Level).
You can also use Kotlin's class reference (e.g. String::class), however for primitives use strings unless the required method/constructor has this parameter boxed!
Arrays of requested classes
You can create an array of a requested class by calling .array() on it, useful for defining parameters of a NMS type.
For requested classes you can also use so-called context. That means you don't have to save it to a variable, but you can use a string prepended with @
1 2 3 4 5 6 7 8 910
nmsGen{/* Setup, see the chapter before */reqClass('net.minecraft.world.level.Level')reqClass('net.minecraft.world.entity.decoration.ArmorStand'){reqConstructor('@Level',double,double,double)reqMethod('setSmall',boolean)}}
1 2 3 4 5 6 7 8 910
nmsGen{/* Setup, see the chapter before */reqClass("net.minecraft.world.level.Level")reqClass("net.minecraft.world.entity.decoration.ArmorStand"){reqConstructor("@Level","double","double","double")reqMethod("setSmall","boolean")}}
Arrays of requested classes in context
You can create an array of a requested class by appending [].
If the class is an enum and we want to retrieve its enum value, we can simply use the reqEnumField method.
1234567
nmsGen{/* Setup, see the chapter before */reqClass('net.minecraft.network.protocol.game.ServerboundClientCommandPacket$Action'){reqEnumField('PERFORM_RESPAWN')}}
1234567
nmsGen{/* Setup, see the chapter before */reqClass("net.minecraft.network.protocol.game.ServerboundClientCommandPacket$Action"){reqEnumField("PERFORM_RESPAWN")}}
In this case, the getField method will be generated again, however it will return directly the Object instead of Field.
12
publicstaticObjectgetFieldPERFORM_RESPAWN(){}
For generating accessor classes, you will have to execute the generateNmsComponents task.
If you want to use alternative mappings or specific versions for generating accessors, prefix the build.gradle declaration with <mappingtype>: and suffix it with :<version>.
Available mapping types are mojang, searge, spigot, obfuscated. Mojang mappings are used by default (if available).