|
1 | 1 | package me.tofaa.entitylib.spigot; |
2 | 2 |
|
3 | | -import com.github.retrooper.packetevents.manager.server.ServerVersion; |
4 | | -import com.github.retrooper.packetevents.protocol.entity.type.EntityType; |
5 | | -import me.tofaa.entitylib.EntityIdProvider; |
6 | | -import me.tofaa.entitylib.Platform; |
7 | | -import org.bukkit.Bukkit; |
8 | | -import org.bukkit.UnsafeValues; |
9 | | -import org.bukkit.plugin.java.JavaPlugin; |
10 | | -import org.jetbrains.annotations.NotNull; |
11 | | - |
12 | 3 | import java.lang.reflect.Field; |
| 4 | +import java.lang.reflect.Modifier; |
13 | 5 | import java.util.UUID; |
14 | 6 | import java.util.concurrent.atomic.AtomicInteger; |
15 | 7 | import java.util.function.Supplier; |
16 | 8 | import java.util.stream.Stream; |
17 | 9 |
|
| 10 | +import org.bukkit.Bukkit; |
| 11 | +import org.bukkit.UnsafeValues; |
| 12 | +import org.bukkit.plugin.java.JavaPlugin; |
| 13 | +import org.jetbrains.annotations.NotNull; |
| 14 | + |
| 15 | +import com.github.retrooper.packetevents.manager.server.ServerVersion; |
| 16 | +import com.github.retrooper.packetevents.protocol.entity.type.EntityType; |
| 17 | + |
| 18 | +import me.tofaa.entitylib.EntityIdProvider; |
| 19 | +import me.tofaa.entitylib.Platform; |
| 20 | + |
18 | 21 | /** |
19 | 22 | * Internal {@link EntityIdProvider} for Spigot servers, handling version and platform differences. |
20 | 23 | */ |
@@ -63,37 +66,49 @@ private Supplier<Integer> detectIdSupplier() { |
63 | 66 |
|
64 | 67 | final Class<?> entityClass = getEntityClass(); |
65 | 68 | if (serverVersion.isNewerThanOrEquals(ServerVersion.V_1_14)) { |
66 | | - final Field entityAtomicField = getField(entityClass, "entityCount", "d", "c"); // Obfuscated names |
67 | | - if (entityAtomicField == null) { |
68 | | - throw new IllegalStateException("Could not find entity counter field"); |
| 69 | + final Supplier<Integer> modernSupplier = resolveAtomicSupplier(entityClass); |
| 70 | + if (modernSupplier != null) { |
| 71 | + return modernSupplier; |
69 | 72 | } |
70 | | - try { |
71 | | - entityAtomicField.setAccessible(true); |
72 | | - final AtomicInteger counter = (AtomicInteger) entityAtomicField.get(null); |
73 | | - return counter::incrementAndGet; |
74 | | - } catch (final Exception exception) { |
75 | | - throw new IllegalStateException("Failed to access entity counter", exception); |
| 73 | + } |
| 74 | + |
| 75 | + return resolveLegacySupplier(entityClass); |
| 76 | + } |
| 77 | + |
| 78 | + private Supplier<Integer> resolveAtomicSupplier(final Class<?> entityClass) { |
| 79 | + final Field entityAtomicField = getStaticFieldOfType(entityClass, AtomicInteger.class, |
| 80 | + "entityCount", "d", "c", "counter", "nextEntityId"); |
| 81 | + if (entityAtomicField == null) { |
| 82 | + return null; |
| 83 | + } |
| 84 | + try { |
| 85 | + entityAtomicField.setAccessible(true); |
| 86 | + final Object fieldValue = entityAtomicField.get(null); |
| 87 | + if (!(fieldValue instanceof AtomicInteger)) { |
| 88 | + return null; // incompatible type, fall back to legacy strategy |
76 | 89 | } |
| 90 | + final AtomicInteger counter = (AtomicInteger) fieldValue; |
| 91 | + return counter::incrementAndGet; |
| 92 | + } catch (final IllegalAccessException exception) { |
| 93 | + throw new IllegalStateException("Failed to access entity counter", exception); |
77 | 94 | } |
| 95 | + } |
78 | 96 |
|
79 | | - final Field entityLegacyField = getField(entityClass, "entityCount"); |
| 97 | + private Supplier<Integer> resolveLegacySupplier(final Class<?> entityClass) { |
| 98 | + final Field entityLegacyField = getStaticFieldOfType(entityClass, Integer.TYPE, "entityCount", "b"); |
80 | 99 | if (entityLegacyField == null) { |
81 | 100 | throw new IllegalStateException("Could not find legacy entity counter field"); |
82 | 101 | } |
83 | | - try { |
84 | | - entityLegacyField.setAccessible(true); |
85 | | - return () -> { |
86 | | - try { |
87 | | - final int entityId = entityLegacyField.getInt(null); |
88 | | - entityLegacyField.setInt(null, entityId + 1); |
89 | | - return entityId; |
90 | | - } catch (final Exception exception) { |
91 | | - throw new IllegalStateException("Failed to modify entity counter", exception); |
92 | | - } |
93 | | - }; |
94 | | - } catch (final Exception exception) { |
95 | | - throw new IllegalStateException("Failed to access legacy entity counter", exception); |
96 | | - } |
| 102 | + entityLegacyField.setAccessible(true); |
| 103 | + return () -> { |
| 104 | + try { |
| 105 | + final int entityId = entityLegacyField.getInt(null); |
| 106 | + entityLegacyField.setInt(null, entityId + 1); |
| 107 | + return entityId; |
| 108 | + } catch (final IllegalAccessException exception) { |
| 109 | + throw new IllegalStateException("Failed to modify entity counter", exception); |
| 110 | + } |
| 111 | + }; |
97 | 112 | } |
98 | 113 |
|
99 | 114 | /** |
@@ -135,6 +150,24 @@ private static Field getField(final Class<?> clazz, final String... possibleName |
135 | 150 | return null; |
136 | 151 | } |
137 | 152 |
|
| 153 | + private static Field getStaticFieldOfType(final Class<?> clazz, final Class<?> desiredType, |
| 154 | + final String... possibleNames) { |
| 155 | + for (final String name : possibleNames) { |
| 156 | + final Field field = getField(clazz, name); |
| 157 | + if (field != null && desiredType.isAssignableFrom(field.getType()) |
| 158 | + && Modifier.isStatic(field.getModifiers())) { |
| 159 | + return field; |
| 160 | + } |
| 161 | + } |
| 162 | + |
| 163 | + for (final Field field : clazz.getDeclaredFields()) { |
| 164 | + if (Modifier.isStatic(field.getModifiers()) && desiredType.isAssignableFrom(field.getType())) { |
| 165 | + return field; |
| 166 | + } |
| 167 | + } |
| 168 | + return null; |
| 169 | + } |
| 170 | + |
138 | 171 | /** |
139 | 172 | * Determines if the server environment is Paper by checking for Paper-specific classes. |
140 | 173 | * @return true if Paper is detected. |
|
0 commit comments