The server side of Bestia is not Godot — Godot only exists on the client (bestia-client). The backend is two independent Kotlin / Spring Boot JVM services with no shared database, talking to the client and to each other over two very different protocols:

  • login-server — a stateless REST service. Its only job is turning proof of identity (a wallet signature, or a dev static token) into a signed JWT. It never touches game state.
  • zone-server — the actual game: a Netty TCP socket, a hand-rolled ECS running a fixed-tick simulation loop, world generation/streaming, AI, combat, inventory, party and chat.
graph LR
  subgraph Client [bestia-client - Godot]
    C[GDScript + C#]
  end

  subgraph Backend [bestia-behemoth monorepo]
    LOGIN["login-server<br/>Spring Boot REST, issues JWT"]
    ZONE["zone-server<br/>Netty TCP, protobuf Envelope, ECS tick loop"]
  end

  C -- "HTTPS POST /api/v1/auth/..." --> LOGIN
  C <-- "TCP, length-prefixed Envelope frames" --> ZONE

Trust between the two servers is carried entirely in a signed JWT — there is no RPC call, shared database, or service discovery between login-server and zone-server. See Authentication for the full handoff.

Tech stack

ConcernTechnology
Language / runtimeKotlin on the JVM, both servers are Spring Boot applications
Client transportRaw TCP (Netty), length-prefixed Protocol Buffers
Login transportHTTPS REST + JSON
PersistenceH2, in-memory, schema recreated on every boot (ddl-auto: create) — no migration tooling, dev-only today
Game loopCustom ECS, single dedicated tick thread, default 20 Hz
World generationStandalone worldgen Gradle module, invoked at boot — see World Generation
Wire protocol source of truthbnet-messages, a Gradle module generating both the Kotlin (server) and C# (client) protobuf classes from the same .proto files

This corrects an older version of these docs, which described an Akka actor-cluster with a Cassandra/MariaDB backend. That design was abandoned; nothing in the current codebase uses Akka, Cassandra, or a graph database.

Repository layout

The server code lives in the bestia-behemoth monorepo (Gradle multi-module, settings.gradle), alongside the client:

ModuleRole
zone-serverThe game server: sockets, ECS, AI, combat, world
login-serverStateless REST auth service
bnet-messagesProtobuf message contracts — the wire format shared by client and server
sharedA handful of Kotlin types shared by both servers (Role, Authority, EIP-712 DTOs) — not a shared database
worldgenStandalone terrain/world generation pipeline, consumed by zone-server at boot
cli-clientHeadless Kotlin dev/test client — exercises the socket + REST protocol without Godot
bestia-clientThe Godot (C#/GDScript) game client — see the client docs

Subsystems

PageCovers
ArchitectureModule layout, the boot sequence, and how the pieces below fit together
NetworkingThe Netty pipeline, the Envelope protobuf wire format, and inbound/outbound message dispatch
Authenticationlogin-server’s two login paths, JWT issuance, and the zone-side handoff
Entity Component SystemThe hand-rolled ECS: World, component stores, the parallel-wave scheduler, and area-of-interest sync
Artificial IntelligenceThe live Utility AI → GOAP → Behavior Tree pipeline that drives NPCs
Battle SystemAttack resolution, damage calculators, status effects, and the skill/status scripting hooks
QuestingDesign document for a quest system — not implemented in zone-server yet
Economy SimulationDesign document for an NPC-side economy — not implemented yet
Townsfolk & Settlement SimulationDesign document for inhabited settlements: occupations, daily schedules and a damageable economy — not implemented yet
World GenerationThe worldgen pipeline (tectonics through settlements) and chunk streaming to clients
ScriptingThe real skill/status-effect/equipment script registries

A few smaller systems exist and work but don’t have their own page yet: party and chat (zone-server/.../party/, .../chat/) follow the same CMSG/handler pattern as everything else, and items/inventory/equipment/loot (.../item/) back the battle and economy pages without a dedicated write-up.

Known gaps

Worth knowing before you go looking for something that isn’t there:

  • Quests, NPCs and the economy don’t exist in code. The design docs are kept because the design work is good, but there is no quest, no shop, no currency and no town inhabitant in zone-server today — settlements are generated in full and stand empty.
  • AuthenticationSuccess.permissions is defined in the protobuf schema but never populated — there’s an explicit TODO for it in ClientMessageHandler.
  • Account ban status (AccountStatus, bannedUntil on login-server) is modeled but never checked during login.
  • A destroyed building never comes back: no building kind has a regrowth time, so its divergence row is terminal and the loss survives every future boot. Tracked in Townsfolk.
  • Both servers’ JWT secrets (and login-server’s Ethereum RPC/contract config) are still the development placeholder values in application.yml — not a concern for local dev, but not something to carry into a real deployment unexamined.

Last updated 19 Sep 2026, 01:24 +0200 . history