Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
package me.tofaa.entitylib.spigot;

import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
import me.tofaa.entitylib.EntityIdProvider;
import me.tofaa.entitylib.Platform;
import org.bukkit.Bukkit;
import org.bukkit.UnsafeValues;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Supplier;
import java.util.stream.Stream;

import org.bukkit.Bukkit;
import org.bukkit.UnsafeValues;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;

import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.entity.type.EntityType;

import me.tofaa.entitylib.EntityIdProvider;
import me.tofaa.entitylib.Platform;

/**
* Internal {@link EntityIdProvider} for Spigot servers, handling version and platform differences.
*/
Expand Down Expand Up @@ -63,37 +66,49 @@ private Supplier<Integer> detectIdSupplier() {

final Class<?> entityClass = getEntityClass();
if (serverVersion.isNewerThanOrEquals(ServerVersion.V_1_14)) {
final Field entityAtomicField = getField(entityClass, "entityCount", "d", "c"); // Obfuscated names
if (entityAtomicField == null) {
throw new IllegalStateException("Could not find entity counter field");
final Supplier<Integer> modernSupplier = resolveAtomicSupplier(entityClass);
if (modernSupplier != null) {
return modernSupplier;
}
try {
entityAtomicField.setAccessible(true);
final AtomicInteger counter = (AtomicInteger) entityAtomicField.get(null);
return counter::incrementAndGet;
} catch (final Exception exception) {
throw new IllegalStateException("Failed to access entity counter", exception);
}

return resolveLegacySupplier(entityClass);
}

private Supplier<Integer> resolveAtomicSupplier(final Class<?> entityClass) {
final Field entityAtomicField = getStaticFieldOfType(entityClass, AtomicInteger.class,
"entityCount", "d", "c", "counter", "nextEntityId");
if (entityAtomicField == null) {
return null;
}
try {
entityAtomicField.setAccessible(true);
final Object fieldValue = entityAtomicField.get(null);
if (!(fieldValue instanceof AtomicInteger)) {
return null; // incompatible type, fall back to legacy strategy
}
final AtomicInteger counter = (AtomicInteger) fieldValue;
return counter::incrementAndGet;
} catch (final IllegalAccessException exception) {
throw new IllegalStateException("Failed to access entity counter", exception);
}
}

final Field entityLegacyField = getField(entityClass, "entityCount");
private Supplier<Integer> resolveLegacySupplier(final Class<?> entityClass) {
final Field entityLegacyField = getStaticFieldOfType(entityClass, Integer.TYPE, "entityCount", "b");
if (entityLegacyField == null) {
throw new IllegalStateException("Could not find legacy entity counter field");
}
try {
entityLegacyField.setAccessible(true);
return () -> {
try {
final int entityId = entityLegacyField.getInt(null);
entityLegacyField.setInt(null, entityId + 1);
return entityId;
} catch (final Exception exception) {
throw new IllegalStateException("Failed to modify entity counter", exception);
}
};
} catch (final Exception exception) {
throw new IllegalStateException("Failed to access legacy entity counter", exception);
}
entityLegacyField.setAccessible(true);
return () -> {
try {
final int entityId = entityLegacyField.getInt(null);
entityLegacyField.setInt(null, entityId + 1);
return entityId;
} catch (final IllegalAccessException exception) {
throw new IllegalStateException("Failed to modify entity counter", exception);
}
};
}

/**
Expand Down Expand Up @@ -135,6 +150,24 @@ private static Field getField(final Class<?> clazz, final String... possibleName
return null;
}

private static Field getStaticFieldOfType(final Class<?> clazz, final Class<?> desiredType,
final String... possibleNames) {
for (final String name : possibleNames) {
final Field field = getField(clazz, name);
if (field != null && desiredType.isAssignableFrom(field.getType())
&& Modifier.isStatic(field.getModifiers())) {
return field;
}
}

for (final Field field : clazz.getDeclaredFields()) {
if (Modifier.isStatic(field.getModifiers()) && desiredType.isAssignableFrom(field.getType())) {
return field;
}
}
return null;
}

/**
* Determines if the server environment is Paper by checking for Paper-specific classes.
* @return true if Paper is detected.
Expand Down