HyCodeYourTale

Debugging

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?
  • Event Nefunguje

  • [ ] 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?
  • Thread Error

  • [ ] Přistupuješ ke komponentám z async kontextu?

  • [ ] Používáš CommandBase místo AbstractPlayerCommand?

  • [ ] Chybí world.execute()?
  • Komponenta je Null

  • [ ] Je komponenta registrována?

  • [ ] Je komponenta přidána k entitě?

  • [ ] Kontroluješ null před použitím?

---

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í |

Last updated: 20. ledna 2026