Troubleshooting¶
Soluciones a problemas comunes en el desarrollo de plugins.
Problemas de Carga¶
Plugin no aparece en los logs¶
Síntomas:
- No aparece mensaje [EarlyPlugin] Found: mi-plugin.jar
- El servidor inicia sin errores
Causas:
1. JAR no está en earlyplugins/
2. Nombre de directorio incorrecto
Solución:
# Verificar ubicación
ls earlyplugins/
# Debe mostrar: mi-plugin.jar
# Verificar que es el directorio correcto
pwd
# Debe estar en la raíz del servidor
Transformer no se registra¶
Síntomas: - JAR aparece en logs pero no el transformer - No se ejecuta la transformación
Causas: 1. Archivo de servicio faltante o mal ubicado 2. Nombre de clase incorrecto en el archivo de servicio
Solución:
# Verificar contenido del JAR
jar tf mi-plugin.jar | grep META-INF
# Debe mostrar:
# META-INF/services/com.hypixel.hytale.plugin.early.ClassTransformer
# Verificar contenido del archivo de servicio
unzip -p mi-plugin.jar META-INF/services/com.hypixel.hytale.plugin.early.ClassTransformer
# Debe mostrar el nombre completo de tu clase
Errores de Compilación¶
ClassNotFoundException durante compilación¶
Error:
Solución:
Dependencia no encontrada¶
Error:
Solución:
Errores de Ejecución¶
ClassNotFoundException en runtime¶
Error:
Causa: Dependencias no incluidas en el JAR
Solución:
jar {
from {
configurations.runtimeClasspath.collect {
it.isDirectory() ? it : zipTree(it)
}
}
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}
VerifyError¶
Error:
Causa: Bytecode transformado es inválido
Solución:
// Usar COMPUTE_FRAMES
ClassWriter writer = new ClassWriter(
reader,
ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS
);
// Verificar bytecode antes de retornar
CheckClassAdapter.verify(
new ClassReader(transformed),
false,
new PrintWriter(System.err)
);
NoSuchMethodError¶
Error:
Causa: Incompatibilidad de versiones o método no existe
Solución: 1. Verificar versión de Hytale 2. Verificar que el método existe en la clase objetivo 3. Revisar firma del método (descriptor)
Problemas de Transformación¶
Transformación no tiene efecto¶
Síntomas: - El código de transformación se ejecuta - Pero no hay cambios visibles en el juego
Diagnóstico:
@Override
public byte[] transform(String className, String classPath, byte[] bytecode) {
System.out.println("[Debug] Evaluando: " + className);
if (shouldTransform(className)) {
System.out.println("[Debug] Transformando: " + className);
byte[] result = doTransform(bytecode);
System.out.println("[Debug] Bytecode modificado: " + (result != bytecode));
return result;
}
return null;
}
Soluciones: 1. Verificar que retornas el bytecode modificado (no null) 2. Verificar que la clase objetivo es correcta 3. Verificar que el método objetivo existe y tiene el descriptor correcto
Clase ya cargada antes de transformación¶
Síntomas: - El transformer se ejecuta - Pero la clase no se transforma
Causa: La clase se cargó antes de que el transformer estuviera activo
Solución: - Aumentar la prioridad del transformer - Verificar que no hay referencias tempranas a la clase
Problemas de Rendimiento¶
Servidor tarda mucho en iniciar¶
Causa: Transformación de muchas clases
Solución:
// Filtrar agresivamente
if (!className.startsWith("com.hypixel.hytale.")) {
return null; // Ignorar clases externas
}
// Usar Set para búsqueda O(1)
private static final Set<String> TARGET_CLASSES = Set.of(
"com.hypixel.hytale.server.core.HytaleServer",
"com.hypixel.hytale.server.core.entity.LivingEntity"
);
if (!TARGET_CLASSES.contains(className)) {
return null;
}
Alto uso de memoria¶
Causa: Muchos metadatos almacenados
Solución:
// Limpiar metadatos no usados
entity.removeMetaObject(TEMP_DATA);
// Usar datos temporales en lugar de persistentes
MetaKey<Object> TEMP = registry.registerMetaObject(
e -> null // No persistente
);
Problemas de Meta System¶
Datos no persisten¶
Síntomas: - Datos se pierden al reiniciar servidor
Causa: MetaKey no es persistente
Solución:
// Cambiar a persistente
MetaKey<Integer> SCORE = registry.registerMetaObject(
p -> 0,
true, // ← Persistente
"player_score", // ← Nombre único
Codec.INT // ← Codec
);
NullPointerException al obtener metadato¶
Error:
Causa: Usar getIfPresentMetaObject sin verificar null
Solución:
// Opción 1: Usar getMetaObject (nunca null)
int value = entity.getMetaObject(MY_KEY);
// Opción 2: Verificar null con getIfPresentMetaObject
Integer value = entity.getIfPresentMetaObject(MY_KEY);
if (value != null) {
// Usar value
}
Debugging Tips¶
Habilitar Logging Detallado¶
public class DebugTransformer implements ClassTransformer {
private static final boolean DEBUG = true;
private void log(String message) {
if (DEBUG) {
System.out.println("[Debug] " + message);
}
}
@Override
public byte[] transform(String className, String classPath, byte[] bytecode) {
log("Evaluando: " + className);
if (shouldTransform(className)) {
log("Transformando: " + className);
log("Bytecode size: " + bytecode.length);
byte[] result = doTransform(bytecode);
log("Transformación completa");
log("New bytecode size: " + result.length);
return result;
}
return null;
}
}
Imprimir Bytecode Transformado¶
import org.objectweb.asm.util.TraceClassVisitor;
import java.io.PrintWriter;
byte[] transformed = transform(bytecode);
// Imprimir bytecode legible
ClassReader reader = new ClassReader(transformed);
TraceClassVisitor printer = new TraceClassVisitor(new PrintWriter(System.out));
reader.accept(printer, 0);
Verificar Bytecode Válido¶
import org.objectweb.asm.util.CheckClassAdapter;
byte[] transformed = transform(bytecode);
try {
CheckClassAdapter.verify(
new ClassReader(transformed),
false,
new PrintWriter(System.err)
);
System.out.println("[Debug] Bytecode válido");
} catch (Exception e) {
System.err.println("[Error] Bytecode inválido: " + e.getMessage());
return null; // Retornar original
}
return transformed;
Obtener Ayuda¶
Si los problemas persisten:
- Revisar logs completos del servidor
- Buscar el error específico en la documentación
- Crear caso de prueba mínimo que reproduzca el problema
- Revisar ejemplos en la documentación
Recursos Adicionales¶
¿Encontraste otro problema? Contribuye a esta documentación agregándolo.