GRPG Architecture
GRPG is built around a traditional MMO client-server architecture with custom networking, binary serialization, and a tick-based game loop. This guide explores the core architectural decisions and how they work together.System Overview
Client-Server Architecture
Server (server-go/)
The server is the authoritative source of truth for all game state. It handles:- Player authentication and session management
- Game loop running at 60ms tick intervals
- World state including chunk loading, object states, and NPC positions
- Packet processing from connected clients
- Database persistence for player data, inventories, and skills
- Content scripting via the ScriptManager
Game State Structure
server-go/main.go
RWMutex to safely handle concurrent access from multiple goroutines (connection handlers, game loop, etc.).
Client (client-go/)
The client is a thin rendering layer that:- Connects to the server via TCP
- Sends player input (movement, interactions)
- Receives world updates and renders them
- Manages local UI state (inventory screen, dialogue boxes)
- Uses Ebiten v2 for cross-platform rendering
Client State Structure
client-go/main.go
Networking Protocol
Custom Binary Protocol
GRPG uses a custom binary protocol built on TCP for reliable, ordered delivery. The protocol is defined using the GBuf library for efficient serialization.Packet Structure
Every packet follows this structure:- Opcode: Identifies the packet type (login, movement, object interaction, etc.)
- Length: Defined per-packet type in the protocol definition
- Payload: Binary-encoded data using GBuf
GBuf Serialization
GBuf provides convenience methods for reading/writing binary data in big-endian format:data-go/gbuf/gbuf.go
- Big-endian encoding for network byte order
- Length-prefixed strings (uint32 length + UTF-8 bytes)
- Error handling for buffer overruns
- Zero-copy reading (slices into backing array)
Connection Handling
The server accepts connections and spawns a goroutine per client:server-go/main.go
- Buffered reading: Uses
bufio.Readerto reduce syscalls - Graceful disconnect: Saves player data on connection loss
- Lock minimization: Only holds locks during map access, not I/O
- Packet queuing: Sends packets to game loop channel for deterministic processing
Login Flow
server-go/main.go
- Reads username from client
- Checks for duplicate usernames
- Loads player from database (or creates new)
- Adds player to game state
- Sends initial world state to client
Game Loop (Tick System)
The server runs a deterministic tick-based game loop at 60ms intervals (~16.67 ticks/second):server-go/main.go
- Determinism: All game logic executes in a single thread, eliminating race conditions
- Replay capability: Can record and replay ticks for debugging
- Predictable timing: Timed events (respawns, cooldowns) are tick-based, not wall-clock
- Synchronization: All clients advance at the same logical time
Data Formats
GRPG uses custom binary formats for game assets, optimized for fast loading and minimal disk space.GRPGTEX (Textures)
Stores textures with JPEG XL compression and metadata:- String ID: Human-readable identifier (e.g., “grass_tile”)
- Numeric ID: uint16 for fast lookups in other formats
- Image Data: JPEG XL compressed PNG (significantly smaller than PNG)
- Type Info: Additional metadata (tile type, collision, etc.)
data-go/grpgtex/
GRPGMAP (Maps)
Chunk-based map format:- Chunk Size: 16x16 tiles
- Tile Data: uint16 array referencing texture IDs
- Collision Map: Bitfield for walkable tiles
- Object Positions: Sparse array of object placements
GRPGNPC (NPCs)
NPC definitions:- Numeric ID: uint16 identifier
- Texture Reference: ID from GRPGTEX
- Base Stats: Health, movement speed, etc.
- Script Reference: Links to GRPGScript behaviors
GRPGOBJ (Objects)
Interactive objects (doors, chests, bushes):- Numeric ID: uint16 identifier
- Texture Reference: ID from GRPGTEX
- State Count: Number of visual states (e.g., 2 for depleted/full berry bush)
- Collision: Whether the object blocks movement
- Script Reference: Links to interaction scripts
GRPGITEM (Items)
Inventory items:- Numeric ID: uint16 identifier
- Texture Reference: Icon from GRPGTEX
- Stackable: Boolean
- Max Stack: uint16
Data Packer Pipeline
The data-packer CLI converts human-readable manifests (GCFG format) into optimized binary formats:Content Scripting System
GRPG uses a Go-based content scripting system (not to be confused with GRPGScript, the standalone scripting language).Object Interactions
Example fromserver-go/content/berry_bush.go:
GetObjState()/SetObjState(): Object state managementPlayerInvAdd(itemID): Add item to player inventoryPlayerAddXp(skill, amount): Award skill XPAddTimer(ticks, callback): Schedule future execution
NPC Dialogues
Example fromserver-go/content/test_npc.go:
Database Schema & Persistence
GRPG uses SQLite with golang-migrate for versioned schema management.Initial Schema
db/migrations/000001_initial.up.sql
Auto-Save on Disconnect
When a player disconnects, their state is automatically saved:Map Editor
The map editor (map-editor/) is a GUI tool built with giu (Dear ImGui for Go):
- Chunk-based editing: 16x16 tile chunks
- Tile palette: Select from loaded GRPGTEX textures
- Collision painting: Mark walkable/unwalkable tiles
- Object placement: Drag-and-drop objects onto map
- Export to GRPGMAP: Save directly to binary format
Performance Considerations
Why Custom Binary Formats?
- Fast loading: No parsing overhead (JSON/XML/TOML parsing is slow)
- Small file size: JPEG XL provides 60-80% smaller textures than PNG
- Memory efficiency: Direct memory mapping possible
- Type safety: Versioned formats prevent data corruption
Why Tick-Based Game Loop?
- Deterministic: Eliminates timing bugs and race conditions
- Testable: Can unit test game logic with simulated ticks
- Networked: Easy to synchronize clients (“apply this at tick N”)
- Replay-friendly: Record inputs and ticks for debugging
Why Go?
- Goroutines: Handle thousands of concurrent connections easily
- Static binary: Single executable deployment
- Memory safety: No segfaults or buffer overruns
- Fast compilation: Rapid iteration during development
- Cross-platform: Same codebase for Linux/Windows/macOS
Architecture Diagrams
Packet Flow
Asset Pipeline
Summary
GRPG’s architecture prioritizes:- Performance: Binary protocols, custom formats, tick-based determinism
- Developer Experience: Type-safe Go, hot-reloadable content, visual tooling
- Simplicity: SQLite for persistence, TCP for networking, no external dependencies
- Control: Every system is custom-built and fully understood