Server architecture
The Xindeler server is a single process written in Rust. There are no microservices, no separate processes per subsystem. Everything β combat, physics, economy, AI, world simulation β runs in the same binary, sharing memory.
For the full system overview (client + server + FastAPI), see Project architecture.
Internal structureβ
xindeler-server (single process)
β
βββ Network layer (Quinn/QUIC)
β βββ Handles player connections, message serialization
β
βββ ECS dispatcher (specs + rayon)
β βββ PhysicsSystem β movement, collisions, gravity
β βββ CombatSystem β damage, poise, death
β βββ AgentSystem β NPC AI tick by tick (pathfinding, behavior)
β βββ StatSystem β health/energy regeneration, buffs
β βββ InventorySystem β loot, pickup, equip
β βββ ... (~30 more systems)
β
βββ rtsim (separate loop, slow scale)
βββ ORACLE β world director
βββ AURORA β NPC mind
The main loopβ
The server has two main loops running on separate threads:
ECS loop (fast tick)β
Runs the specs dispatcher at a fixed frequency (~30 ticks/second). Each tick:
- Processes incoming messages from all connected clients
- Executes all ECS systems in order (with parallelism where possible)
- Sends updated state to clients (sync of visible entities)
Systems with no dependencies on each other run in parallel thanks to rayon. specs automatically determines which systems can be parallelized based on which components they read and write.
rtsim loop (slow tick)β
Runs on a scale of seconds to minutes. It processes:
- Long-distance NPC movement (routes between sites)
- Faction and relationship updates
- ORACLE ticks (event generation, narrative arc progression)
- AURORA ticks (NPC mind updates, memory decay)
- Periodic serialization of state to
rtsim/data.dat
Connection handlingβ
Each connected player has:
- A QUIC stream (Quinn) for reliable messages (inventory, chat, commands)
- Optionally unreliable channels for frequent position updates
The Client component in the ECS represents a connected player. When a player disconnects, their entity persists in the world for a few seconds (for reconnection) and is then removed. Their state (inventory, position, stats) is saved in rtsim.
Entity synchronizationβ
The server doesn't send the state of every entity to every client β that would use too much bandwidth. Each client has a presence range (a radius of chunks around the player). The server sends only the entities within that range.
When an entity enters or leaves a player's range:
- Enters: the server sends the complete entity to the client
- Leaves: the client removes it from its local ECS
- Visible: the server sends diffs of modified components every tick
Admin commandsβ
Admins control the server via chat commands prefixed with /. See Admin commands for the full reference.
ORACLE and AURORA commands are also executed from the admin chat:
/oracle status
/aurora npc <id> status
/time set noon
/give_item common.items.weapons.sword.iron_sword 1
Scalabilityβ
The current server is designed for one instance per world β there is no sharding or multiple instances of the same world. Vertical scaling (more CPU/RAM on the same server) is the path to supporting more simultaneous players.
The practical limit depends on the hardware and player density. A server with 8 cores can handle hundreds of players without issues if they're spread out across the world.