Debugging
Dokumentace k debugování a řešení problémů v Hytale pluginech.
Obsah
| Soubor | Popis |
|--------|-------|
| LOGGING.md | HytaleLogger, HytaleLoggerBackend, Log Levels, Sentry integration |
| TROUBLESHOOTING.md | DebugUtils, DebugPlugin, běžné chyby, diagnostika |
---
Přehled
Debugging System
│
├── HytaleLogger
│ ├── Flogger API
│ ├── Configurable levels
│ └── Sentry integration
│
├── DebugPlugin
│ ├── Debug commands
│ └── Visual debug shapes
│
└── Troubleshooting
├── Thread errors
├── Component issues
└── Event problems
---
Logging
Základní Logging
// Info
getLogger().atInfo().log("Plugin started");// S parametry
getLogger().atInfo().log("Loaded %d warps", warpCount);
getLogger().atInfo().log("Player %s joined from %s", playerName, ipAddress);
// Warning
getLogger().atWarning().log("Config file not found, using defaults");
// Error s výjimkou
getLogger().at(Level.SEVERE).withCause(exception).log("Failed to save data:");
// Debug (pokud je povolen)
getLogger().at(Level.FINE).log("Debug: Processing entity %s", entityId);
Log Levels
| Level | Použití |
|-------|---------|
| Level.INFO | Běžné informace |
| Level.WARNING | Varování (ne kritické) |
| Level.SEVERE | Chyby |
| Level.FINE | Debug informace |
| Level.FINER | Detailnější debug |
| Level.FINEST | Nejvíce detailní |
Logging v Produkci vs Development
public class MyPlugin extends JavaPlugin { private boolean debugMode = false;
public void debug(String message, Object... args) {
if (debugMode) {
getLogger().atInfo().log("[DEBUG] " + message, args);
}
}
public void setDebugMode(boolean enabled) {
this.debugMode = enabled;
getLogger().atInfo().log("Debug mode: %s", enabled ? "ENABLED" : "DISABLED");
}
}
---
Thread Debugging
Kontrola Aktuálního Threadu
public void debugThread(String context) {
Thread current = Thread.currentThread();
getLogger().atInfo().log("[%s] Thread: %s (ID: %d)",
context,
current.getName(),
current.getId()
);
}
Kontrola World Threadu
public void ensureWorldThread(World world, String operation) {
if (!world.isInThread()) {
getLogger().atWarning().log(
"WARNING: %s called from wrong thread! Expected: %s, Actual: %s",
operation,
"WorldThread",
Thread.currentThread().getName()
); // Stack trace pro nalezení problému
new Exception("Stack trace").printStackTrace();
}
}
isInThread() Debug Wrapper
public void safeComponentAccess(World world, Runnable action, String description) {
if (world.isInThread()) {
action.run();
} else {
getLogger().atWarning().log(
"Scheduling '%s' to world thread (was on %s)",
description,
Thread.currentThread().getName()
);
world.execute(action);
}
}
---
Common Errors
"Assert not in thread!"
Příčina: Přístup ke komponentám z nesprávného vlákna.
// CHYBA:
java.lang.IllegalStateException: Assert not in thread!
Thread[#108,WorldThread - default,5,...]
but was in Thread[#75,Scheduler,5,main]
Řešení:
// 1. Použij AbstractPlayerCommand místo CommandBase
public class MyCommand extends AbstractPlayerCommand { ... }// 2. Nebo použij world.execute()
world.execute(() -> {
// Teď bezpečné
store.getComponent(ref, Type.getComponentType());
});
NullPointerException u Komponent
Příčina: Komponenta neexistuje na entitě.
// CHYBA:
Player player = store.getComponent(ref, Player.getComponentType());
player.sendMessage(...); // NullPointerException!
Řešení:
// Vždy kontroluj null
Player player = store.getComponent(ref, Player.getComponentType());
if (player != null) {
player.sendMessage(...);
} else {
getLogger().atWarning().log("Player component not found on entity");
}
Event se Nevyvolá
Příčina: Špatný typ registrace.
// PlayerChatEvent je ASYNC - register() nefunguje
getEventRegistry().register(PlayerChatEvent.class, ...); // NEFUNGUJE// Správně:
getEventRegistry().registerAsyncGlobal(PlayerChatEvent.class, ...);
// BreakBlockEvent je ECS - register() nefunguje
getEventRegistry().register(BreakBlockEvent.class, ...); // NEFUNGUJE
// Správně:
getEntityStoreRegistry().registerSystem(new MyBlockSystem());
Plugin se Nenačte
Příčiny a řešení:
| Příčina | Řešení |
|---------|--------|
| Chybí manifest.json | Přidej manifest.json do JAR |
| Špatný EntryPoint | Oprav cestu k hlavní třídě |
| Chybí závislost | Přidej do Dependencies |
| Chyba v setup() | Zkontroluj logy, oprav chybu |
---
Debug Příkazy
Debug Command
public class DebugCommand extends AbstractPlayerCommand { public DebugCommand() {
super("debug", "myplugin.commands.debug.desc");
requirePermission(HytalePermissions.of("myplugin.admin"));
}
@Override
protected void execute(CommandContext context, Store store,
Ref ref, PlayerRef playerRef, World world) {
Player player = store.getComponent(ref, Player.getComponentType());
if (player == null) return;
// Thread info
player.sendMessage(Message.raw("Thread: " + Thread.currentThread().getName()));
// World info
player.sendMessage(Message.raw("World: " + world.getName()));
player.sendMessage(Message.raw("In world thread: " + world.isInThread()));
// Position
TransformComponent transform = store.getComponent(ref, TransformComponent.getComponentType());
if (transform != null) {
Vector3d pos = transform.getPosition();
player.sendMessage(Message.raw(String.format(
"Position: %.2f, %.2f, %.2f",
pos.getX(), pos.getY(), pos.getZ()
)));
}
// Custom components
MyComponent myComp = store.getComponent(ref, MyPlugin.get().getMyComponentType());
player.sendMessage(Message.raw("MyComponent: " + (myComp != null ? "present" : "null")));
}
}
Component Inspector
public class InspectCommand extends AbstractPlayerCommand { public InspectCommand() {
super("inspect", "myplugin.commands.inspect.desc");
}
@Override
protected void execute(CommandContext context, Store store,
Ref ref, PlayerRef playerRef, World world) {
Player player = store.getComponent(ref, Player.getComponentType());
if (player == null) return;
player.sendMessage(Message.raw("=== Component Inspector ==="));
// Vypiš všechny komponenty na entitě
// (implementace závisí na dostupném API)
// Základní komponenty
checkComponent(player, store, ref, "Player", Player.getComponentType());
checkComponent(player, store, ref, "PlayerRef", PlayerRef.getComponentType());
checkComponent(player, store, ref, "Transform", TransformComponent.getComponentType());
checkComponent(player, store, ref, "HeadRotation", HeadRotation.getComponentType());
}
private void checkComponent(Player player, Store store,
Ref ref, String name,
ComponentType type) {
T comp = store.getComponent(ref, type);
String status = comp != null ? "YES" : "NO";
player.sendMessage(Message.raw(name + ": " + status));
}
}
---
Performance Debugging
Měření Času
public void measureOperation(String name, Runnable operation) {
long start = System.nanoTime();
operation.run();
long end = System.nanoTime(); double ms = (end - start) / 1_000_000.0;
getLogger().atInfo().log("%s took %.2f ms", name, ms);
}
// Použití
measureOperation("Save all players", this::saveAllPlayers);
Memory Debugging
public void logMemoryUsage() {
Runtime runtime = Runtime.getRuntime();
long totalMemory = runtime.totalMemory();
long freeMemory = runtime.freeMemory();
long usedMemory = totalMemory - freeMemory; getLogger().atInfo().log("Memory: %d MB used / %d MB total",
usedMemory / (1024 * 1024),
totalMemory / (1024 * 1024)
);
}
---
Checklist pro Debugging
Plugin se Nenačte
- [ ] manifest.json existuje v JAR?
- [ ] EntryPoint je správný?
- [ ] Všechny Dependencies jsou dostupné?
- [ ] Konstruktor přijímá JavaPluginInit?
- [ ] setup() neháže výjimku?
- [ ] Je event registrován v setup()?
- [ ] Správný typ registrace? (register vs registerAsync vs EntityEventSystem)
- [ ] Pro ECS eventy: je systém registrován?
- [ ] Pro async eventy: používáš registerAsync?
- [ ] Přistupuješ ke komponentám z async kontextu?
- [ ] Používáš CommandBase místo AbstractPlayerCommand?
- [ ] Chybí world.execute()?
- [ ] Je komponenta registrována?
- [ ] Je komponenta přidána k entitě?
- [ ] Kontroluješ null před použitím?
Event Nefunguje
Thread Error
Komponenta je Null
---
Shrnutí
| Problém | Debug Postup |
|---------|--------------|
| Plugin nenačten | Zkontroluj logy, manifest, EntryPoint |
| Thread error | Přidej debug logging pro thread name |
| Event nefunguje | Zkontroluj typ registrace |
| Null component | Přidej null check a logging |
| Performance | Měř čas operací |