-
-
Notifications
You must be signed in to change notification settings - Fork 87
/
SentinelNMSHelper.java
128 lines (119 loc) · 6.7 KB
/
SentinelNMSHelper.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package org.mcmonkey.sentinel.utilities;
import net.citizensnpcs.util.NMS;
import org.bukkit.Bukkit;
import org.bukkit.entity.Enderman;
import org.bukkit.entity.IronGolem;
import java.lang.invoke.MethodHandle;
import java.lang.reflect.Field;
/**
* Helper for NMS-based actions.
*/
public class SentinelNMSHelper {
public static MethodHandle CRAFTENTITY_GETHANDLE, NMSENTITY_WORLDGETTER, NMSWORLD_BROADCASTENTITYEFFECT, NMSENTITY_GETDATAWATCHER, DATWATCHER_SET, LIVINGENTITY_ATTACKSTRENGTHTICKS;
public static Object ENTITYENDERMAN_DATAWATCHER_ANGRY;
private static boolean nmsWorks = true, endermanValid = false;
public static void init() {
try {
if (!SentinelVersionCompat.v1_12) {
nmsWorks = false;
return;
}
// Will be like "org.bukkit.craftbukkit.v1_16_R3"
String bukkitPackageName = Bukkit.getServer().getClass().getPackage().getName();
// Should be like "v1_16_R3"
String packageVersion = bukkitPackageName.substring(bukkitPackageName.lastIndexOf('.') + 1);
Class craftEntity = Class.forName(bukkitPackageName + ".entity.CraftEntity");
CRAFTENTITY_GETHANDLE = NMS.getMethodHandle(craftEntity, "getHandle", true);
Class nmsEntity, nmsWorld, nmsDataWatcher, nmsDataWatcherObject, nmsEntityEnderman, nmsHuman, nmsLivingEntity;
String endermanAngryField = null;
String broadcastEffectMethod = "broadcastEntityEffect", dataWatcherSet = "set";
if (SentinelVersionCompat.v1_17) { // 1.17+ - Mojang mappings update
nmsEntity = Class.forName("net.minecraft.world.entity.Entity");
nmsWorld = Class.forName("net.minecraft.world.level.World"); // Level
nmsDataWatcher = Class.forName("net.minecraft.network.syncher.DataWatcher"); // SynchedEntityData
nmsDataWatcherObject = Class.forName("net.minecraft.network.syncher.DataWatcherObject"); // EntityDataAccessor
nmsEntityEnderman = Class.forName("net.minecraft.world.entity.monster.EntityEnderman");
nmsLivingEntity = Class.forName("net.minecraft.world.entity.EntityLiving");
String attackStrengthField = null;
boolean isCompat = false;
if (SentinelVersionCompat.v1_19 && !SentinelVersionCompat.vFuture) { // 1.19.4 names
// https://minidigger.github.io/MiniMappingViewer/#/mojang/server/1.19.4
endermanAngryField = "bU"; // net.minecraft.world.entity.monster.EnderMan#DATA_CREEPY
attackStrengthField = "aO"; // net.minecraft.world.entity.LivingEntity#attackStrengthTicker
broadcastEffectMethod = "a"; // net.minecraft.world.level.Level#broadcastEntityEvent(Entity,byte)
dataWatcherSet = "b"; // net.minecraft.network.syncher.SynchedEntityData#set
isCompat = true;
}
else if (SentinelVersionCompat.v1_18 && !SentinelVersionCompat.v1_19) { // 1.18 names
// https://minidigger.github.io/MiniMappingViewer/#/mojang/server/1.18.2
endermanAngryField = "bX"; // net.minecraft.world.entity.monster.EnderMan#DATA_CREEPY
attackStrengthField = "aQ"; // net.minecraft.world.entity.LivingEntity#attackStrengthTicker
broadcastEffectMethod = "a"; // net.minecraft.world.level.Level#broadcastEntityEvent(Entity,byte)
dataWatcherSet = "b"; // net.minecraft.network.syncher.SynchedEntityData#set
isCompat = true;
}
else if (!SentinelVersionCompat.v1_18) { // 1.17 names
endermanAngryField = "bV"; // EnderMan#DATA_CREEPY
attackStrengthField = "aQ"; // LivingEntity#attackStrengthTicker
isCompat = true;
}
if (isCompat) {
LIVINGENTITY_ATTACKSTRENGTHTICKS = NMS.getSetter(nmsLivingEntity, attackStrengthField);
}
}
else { // 1.12 through 1.16 - Original Spigot NMS versioned mappings
String nmsPackageName = "net.minecraft.server." + packageVersion;
nmsEntity = Class.forName(nmsPackageName + ".Entity");
nmsWorld = Class.forName(nmsPackageName + ".World");
nmsDataWatcher = Class.forName(nmsPackageName + ".DataWatcher");
nmsDataWatcherObject = Class.forName(nmsPackageName + ".DataWatcherObject");
nmsEntityEnderman = Class.forName(nmsPackageName + ".EntityEnderman");
if (SentinelVersionCompat.v1_16) {
endermanAngryField = "bo";
}
}
NMSENTITY_WORLDGETTER = NMS.getFirstGetter(nmsEntity, nmsWorld);
NMSENTITY_GETDATAWATCHER = NMS.getFirstGetter(nmsEntity, nmsDataWatcher);
NMSWORLD_BROADCASTENTITYEFFECT = NMS.getMethodHandle(nmsWorld, broadcastEffectMethod, true, nmsEntity, byte.class);
DATWATCHER_SET = NMS.getMethodHandle(nmsDataWatcher, dataWatcherSet, true, nmsDataWatcherObject, Object.class);
if (endermanAngryField != null && nmsEntityEnderman != null) {
Field dataWatcherAngryField = NMS.getField(nmsEntityEnderman, endermanAngryField);
dataWatcherAngryField.setAccessible(true);
ENTITYENDERMAN_DATAWATCHER_ANGRY = dataWatcherAngryField.get(null);
endermanValid = true;
}
}
catch (Throwable ex) {
ex.printStackTrace();
nmsWorks = false;
endermanValid = false;
}
}
public static void animateIronGolemSwing(IronGolem entity) {
if (!nmsWorks) {
return;
}
try {
Object nmsHandle = CRAFTENTITY_GETHANDLE.invoke(entity);
Object world = NMSENTITY_WORLDGETTER.invoke(nmsHandle);
NMSWORLD_BROADCASTENTITYEFFECT.invoke(world, nmsHandle, (byte) 4);
}
catch (Throwable ex) {
nmsWorks = false;
ex.printStackTrace();
}
}
public static void setEndermanAngry(Enderman entity, boolean angry) {
if (!nmsWorks || !endermanValid) {
return;
}
try {
Object nmsHandle = CRAFTENTITY_GETHANDLE.invoke(entity);
Object dataWatcher = NMSENTITY_GETDATAWATCHER.invoke(nmsHandle);
DATWATCHER_SET.invoke(dataWatcher, ENTITYENDERMAN_DATAWATCHER_ANGRY, angry);
}
catch (Throwable ex) {
endermanValid = false;
}
}
}