Game loop — tick sequence¶
The server runs at 20 tps (50 ms/tick). Each tick drives player input, physics, automatic world managers, and periodic housekeeping.
flowchart TD
GL(["GameLoop.tick()\n50 ms · 20 tps"])
GL --> SESS
subgraph SESS ["Per connected player"]
direction LR
IC["IntentCollector\nMoveIntent · BlockBreak\nBlockPlace · Command"]
BRK["BlockBreaker\nbreak progress + drops"]
MOV["MovementProcessor\nAABB physics · gravity\nclient-side prediction"]
STR["ChunkStreamer\ndeliver ready chunks"]
IC --> BRK --> MOV --> STR
end
SESS --> WIT["WorldItemManager\nitem proximity pickup"]
WIT --> NPC["NpcManager\nwander · pathfind · interact"]
NPC --> WEA["WeatherManager\nzone drift · expiry"]
WEA --> LIQ
LIQ --> VEG_M
subgraph AUTO ["Automatic world managers — broadcast WorldUpdate on change"]
direction TB
LIQ["LiquidManager — every tick\ncheck activeLiquids, flow down, spread horizontally (max 7)"]
VEG_M["VegetationManager — every 40 ticks\nverify block, accumulate ticks, SEED→SPROUT→SAPLING→tree"]
end
GL -->|"every 20 ticks"| T1["TimeUpdate broadcast"]
GL -->|"every 100 ticks"| T2["NpcSpawner.trySpawn"]
GL -->|"every 600 ticks"| T3["flushDirty chunks + player/NPC/vegetation state"]
Combat runs its own processors alongside this loop (SpellProcessor,
StatusEffectProcessor, RegenProcessor, ExperienceProcessor).