Skip to content

Commit ff09932

Browse files
committed
Fix NMS reflection for Mojang-mapped servers
1 parent c943fca commit ff09932

1 file changed

Lines changed: 38 additions & 6 deletions

File tree

src/main/java/org/mcmonkey/sentinel/utilities/SentinelNMSHelper.java

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import org.bukkit.event.inventory.InventoryEvent;
88

99
import java.lang.invoke.MethodHandle;
10-
import java.lang.reflect.Field;
1110

1211
/**
1312
* Helper for NMS-based actions.
@@ -29,6 +28,34 @@ public static Class<?> getOptionalFieldType(Class<?> clazz, String fieldName) {
2928
}
3029
}
3130

31+
/**
32+
* Returns the first of the given class names that exists (multi-mapping support: Mojang-mapped vs legacy Spigot-remapped NMS).
33+
*/
34+
private static Class<?> classForFirst(String... classNames) throws ClassNotFoundException {
35+
for (String name : classNames) {
36+
try {
37+
return Class.forName(name);
38+
}
39+
catch (ClassNotFoundException ex) {
40+
// Try the next candidate name.
41+
}
42+
}
43+
throw new ClassNotFoundException("None of the candidate NMS classes exist: " + String.join(", ", classNames));
44+
}
45+
46+
/**
47+
* Returns a handle for the first of the given method names that exists on the class (multi-mapping support: Mojang names vs obfuscated/Spigot names).
48+
*/
49+
private static MethodHandle methodHandleForFirst(Class<?> clazz, Class<?>[] params, String... methodNames) {
50+
for (String name : methodNames) {
51+
MethodHandle handle = NMS.getMethodHandle(clazz, name, false, params); // log=false: missing candidates are expected, don't spam the console
52+
if (handle != null) {
53+
return handle;
54+
}
55+
}
56+
return null;
57+
}
58+
3259
public static void init() {
3360
try {
3461
if (SentinelVersionCompat.v1_10) {
@@ -47,9 +74,10 @@ public static void init() {
4774
String broadcastEffectMethod = "broadcastEntityEffect", dataWatcherSet = "set";
4875
if (SentinelVersionCompat.v1_17) { // 1.17+ - Mojang mappings update
4976
nmsEntity = Class.forName("net.minecraft.world.entity.Entity");
50-
nmsWorld = Class.forName("net.minecraft.world.level.World"); // Level
51-
nmsDataWatcher = Class.forName("net.minecraft.network.syncher.DataWatcher"); // SynchedEntityData
52-
nmsDataWatcherObject = Class.forName("net.minecraft.network.syncher.DataWatcherObject"); // EntityDataAccessor
77+
// Try Mojang-mapped names first (server runtime mappings since 1.20.5+, including 26.1), then the legacy Spigot-remapped names (1.17-1.21).
78+
nmsWorld = classForFirst("net.minecraft.world.level.Level", "net.minecraft.world.level.World");
79+
nmsDataWatcher = classForFirst("net.minecraft.network.syncher.SynchedEntityData", "net.minecraft.network.syncher.DataWatcher");
80+
nmsDataWatcherObject = classForFirst("net.minecraft.network.syncher.EntityDataAccessor", "net.minecraft.network.syncher.DataWatcherObject");
5381
if (SentinelVersionCompat.v1_21 && !SentinelVersionCompat.vFuture) { // 1.21 names
5482
broadcastEffectMethod = "a"; // net.minecraft.world.level.Level#broadcastEntityEvent(Entity,byte)
5583
dataWatcherSet = "a"; // net.minecraft.network.syncher.SynchedEntityData#set
@@ -80,8 +108,12 @@ else if (SentinelVersionCompat.v1_18 && !SentinelVersionCompat.v1_19) { // 1.18
80108
}
81109
NMSENTITY_WORLDGETTER = NMS.getFirstGetter(nmsEntity, nmsWorld);
82110
NMSENTITY_GETDATAWATCHER = NMS.getFirstGetter(nmsEntity, nmsDataWatcher);
83-
NMSWORLD_BROADCASTENTITYEFFECT = NMS.getMethodHandle(nmsWorld, broadcastEffectMethod, true, nmsEntity, byte.class);
84-
DATWATCHER_SET = NMS.getMethodHandle(nmsDataWatcher, dataWatcherSet, true, nmsDataWatcherObject, Object.class);
111+
// Try the Mojang-mapped method name first (26.1+ runs on Mojang mappings), then fall back to the per-version Spigot/obfuscated name selected above.
112+
NMSWORLD_BROADCASTENTITYEFFECT = methodHandleForFirst(nmsWorld, new Class<?>[]{nmsEntity, byte.class}, "broadcastEntityEvent", broadcastEffectMethod);
113+
DATWATCHER_SET = methodHandleForFirst(nmsDataWatcher, new Class<?>[]{nmsDataWatcherObject, Object.class}, "set", dataWatcherSet);
114+
if (NMSWORLD_BROADCASTENTITYEFFECT == null || DATWATCHER_SET == null) {
115+
nmsWorks = false; // Couldn't resolve the NMS methods on this version; cosmetic NMS effects will be skipped (plugin otherwise functions normally).
116+
}
85117
}
86118
catch (Throwable ex) {
87119
ex.printStackTrace();

0 commit comments

Comments
 (0)