Networking
Dokumentace k síťové komunikaci v Hytale.
Obsah
| Soubor | Popis |
|--------|-------|
| PACKETS.md | PacketRegistry, PacketHandler, CachedPacket, GamePacketHandler, SubPacketHandler |
| SYNCHRONIZATION.md | NetworkId, EntityViewer, Visible, ComponentUpdateType, EntityTrackerSystems |
---
Přehled
Hytale používá vlastní síťový protokol pro komunikaci mezi serverem a klientem. Server běží na více vláknech:
Main Thread
├── World Thread (default)
├── World Thread (nether)
├── Scheduler Thread
└── Network Thread <- Zpracování paketů
---
Entity Synchronizace
NetworkId Komponenta
Pro síťovou synchronizaci entity:
// Přidej NetworkId ke každé entitě kterou chceš synchronizovat
holder.addComponent(
NetworkId.getComponentType(),
new NetworkId(store.getExternalData().takeNextNetworkId())
);
ComponentUpdateType
Typy synchronizovaných komponent:
| Typ | Popis |
|-----|-------|
| Transform | Pozice a rotace |
| Model | 3D model |
| PlayerSkin | Skin hráče |
| Item | Item v ruce |
| Block | Block data |
| Equipment | Vybavení |
| EntityStats | Statistiky |
| Nameplate | Jmenovka |
| UIComponents | UI komponenty |
| CombatText | Bojový text |
| MovementStates | Stav pohybu |
| EntityEffects | Efekty |
| DynamicLight | Dynamické světlo |
| Audio | Zvuky |
| ActiveAnimations | Animace |
---
Pakety
EntityUpdates
Pro hromadnou aktualizaci entit:
// Z dekompilovaného kódu:
// Limit: 4,096,000 entit na paket
MapMarker
Pro world map markery:
// Vytvoření markeru
new MapMarker(
id, // Unikátní ID
name, // Zobrazený název
"Icon.png", // Ikona
transformPacket, // Pozice
null // Extra data
);
---
Odesílání Zpráv
Player.sendMessage()
// Odeslání zprávy hráči
player.sendMessage(Message.raw("Hello!"));// S překladem
player.sendMessage(
Message.translation("server.welcome")
.param("name", player.getName())
);
PlayerRef.sendMessage()
// Přes PlayerRef
playerRef.sendMessage(Message.raw("Message via ref"));
CommandContext.sendMessage()
// V příkazu
context.sendMessage(Message.raw("Command response"));
---
Multi-Server Architektura
Universe
// Získání universe instance
Universe universe = Universe.get();// Všichni online hráči
Collection players = universe.getPlayers();
// Hráč podle UUID
Player player = universe.getPlayer(uuid);
// Svět podle jména
World world = universe.getWorld("default");
// Cesta k datům
Path universePath = universe.getPath();
World
// Získání světa
World world = player.getWorld();// Jméno světa
String name = world.getName();
// Konfigurace
WorldConfig config = world.getWorldConfig();
// Entity store
EntityStore entityStore = world.getEntityStore();
// Spuštění na world threadu
world.execute(() -> {
// Bezpečné operace
});
---
Thread Safety v Síťování
Network Thread → World Thread
// Paket přijde na Network threadu
// Pro přístup ke komponentám potřebuješ world.execute()onPacketReceived(packet -> {
Player player = getPlayerFromPacket(packet);
World world = player.getWorld();
world.execute(() -> {
// Bezpečný přístup ke komponentám
Ref ref = player.getRef();
Store store = ref.getStore();
// ...
});
});
World Thread → Network Thread
// Odesílání paketů je bezpečné z jakéhokoliv vlákna
// Hytale interně zajišťuje thread-safe frontuplayer.sendMessage(Message.raw("Safe from any thread"));
---
Tracker System
WorldMapTracker
// Sledování markerů na mapě
tracker.trySendMarker(
chunkViewRadius,
playerChunkX,
playerChunkZ,
position,
yaw,
markerId,
markerName,
dataObject,
markerFactory
);
Entity Tracking
// Entity jsou automaticky trackované podle:
// - Vzdálenosti od hráče
// - Chunk visibility
// - ComponentUpdateType
---
Chunk Networking
ChunkUtil
// Kontrola zda je pozice v chunku
boolean inside = ChunkUtil.isInsideChunk(
chunkX, chunkZ,
MathUtil.floor(position.x),
MathUtil.floor(position.z)
);
Chunk Loading
// Event při načítání chunku
getEventRegistry().registerGlobal(ChunkPreLoadProcessEvent.class, event -> {
WorldChunk chunk = event.getChunk();
BlockChunk blockChunk = chunk.getBlockChunk(); if (blockChunk != null) {
int chunkX = blockChunk.getX();
int chunkZ = blockChunk.getZ();
// ...
}
});
---
Best Practices
1. Minimalizuj Síťový Traffic
// Špatně - posílá se příliš často
for (Player player : allPlayers) {
player.sendMessage(Message.raw("Update!"));
}// Lépe - batching
Message batchedMessage = buildBatchedMessage(updates);
for (Player player : relevantPlayers) {
player.sendMessage(batchedMessage);
}
2. Validuj Data ze Sítě
// Vždy validuj příchozí data
public void handleClientRequest(Player player, RequestData data) {
// Kontrola oprávnění
if (!canPerformAction(player, data.action)) {
return;
} // Validace dat
if (!isValidRequest(data)) {
return;
}
// Zpracování
processRequest(player, data);
}
3. Používej Async pro I/O
// Async operace mimo hlavní vlákna
CompletableFuture.runAsync(() -> {
// Network I/O, databáze, soubory
}).thenRun(() -> {
// Callback po dokončení
});
---
Shrnutí
| Komponenta | Účel |
|------------|------|
| NetworkId | Síťová identifikace entity |
| Universe | Globální server state |
| World | Jednotlivý svět |
| WorldMapTracker | Sledování map markerů |
| ChunkUtil | Chunk operace |
| Operace | Thread |
|---------|--------|
| Příjem paketů | Network Thread |
| Přístup ke komponentám | World Thread |
| Odesílání zpráv | Jakýkoliv |
| Odesílání paketů | Jakýkoliv (interně queued) |