273 lines
5.4 KiB
Markdown
273 lines
5.4 KiB
Markdown
# tic-tac-toe — Authoritative Multiplayer Game Server (Nakama + Go)
|
|
|
|
A production-grade, server-authoritative multiplayer backend built using **Nakama 3**, **Go plugins**, and **PostgreSQL**, deployed via **Drone CI/CD** and exposed securely through **Traefik**.
|
|
|
|
---
|
|
|
|
## 🚀 Overview
|
|
|
|
This repository contains a fully authoritative Tic-Tac-Toe backend built on **Nakama 3.21.0 ARM**, using a custom **Go plugin** to implement game logic, matchmaking, validation, leaderboards, and session management.
|
|
|
|
The server ensures:
|
|
|
|
* **Zero client trust**
|
|
* **Deterministic gameplay**
|
|
* **Secure matchmaking**
|
|
* **Validated moves**
|
|
* **Authoritative outcomes**
|
|
|
|
Designed for scalability, extensibility, and cloud deployment (GCP, AWS, or ARM homelab environments).
|
|
|
|
---
|
|
|
|
## ⭐ Key Features
|
|
|
|
* **Authoritative Go match handler** (`tictactoe`)
|
|
* Device-ID authentication + JWT session
|
|
* Matchmaking queue support
|
|
* Deterministic game validation
|
|
* Match lifecycle handling
|
|
* Disconnect handling & forfeit detection
|
|
* Leaderboards creation + scoring
|
|
* Production-grade CI/CD with Drone
|
|
* Automated ARM Docker builds
|
|
* Full Traefik routing (HTTP + WebSocket)
|
|
* Compatible with x86/ARM/GCP
|
|
|
|
---
|
|
|
|
## 🧩 Architecture
|
|
|
|
### High-Level System Diagram
|
|
|
|
```mermaid
|
|
flowchart LR
|
|
UI[Frontend (React + Vite)] -->|WebSocket / REST| Traefik
|
|
Traefik --> Nakama[Nakama 3.21.0 ARM]
|
|
Nakama --> Plugin[Go Plugin main.so]
|
|
Nakama --> Postgres[(PostgreSQL)]
|
|
DroneCI --> Registry[Private Docker Registry]
|
|
Registry --> Nakama
|
|
```
|
|
|
|
---
|
|
|
|
## 🛠 Tech Stack
|
|
|
|
**Backend**
|
|
|
|
* Nakama 3.21.0 ARM
|
|
* Go 1.21.6 (plugin ABI compatible)
|
|
* PostgreSQL 16
|
|
* Docker / multi-stage builds
|
|
* Drone CI/CD
|
|
* Traefik reverse proxy
|
|
|
|
**Cloud/Infra**
|
|
|
|
* GCP-ready
|
|
* ARM homelab deployments
|
|
* Private registry support
|
|
|
|
---
|
|
|
|
## 📦 Repository Structure
|
|
|
|
```
|
|
tic-tac-toe/
|
|
│── plugins/
|
|
│ ├── match.go
|
|
│ ├── matchmaking.go
|
|
│ └── leaderboard.go
|
|
│
|
|
│── Dockerfile
|
|
│── go.mod
|
|
│── go.sum
|
|
│── README.md
|
|
```
|
|
|
|
---
|
|
|
|
## 🔌 Registered Server Components
|
|
|
|
### 📌 Match Handler
|
|
|
|
Name: **`tictactoe`**
|
|
|
|
Handles:
|
|
|
|
* Turn validation
|
|
* State updates
|
|
* Win/loss/draw
|
|
* Disconnect forfeit
|
|
* Broadcasting authoritative state
|
|
|
|
### 📌 RPCs
|
|
|
|
| RPC Name | Purpose |
|
|
| ----------------------- | ---------------------------------------- |
|
|
| **`leave_matchmaking`** | Allows clients to exit matchmaking queue |
|
|
|
|
### 📌 Matchmaker Hook
|
|
|
|
| Hook | Purpose |
|
|
| ----------------------- | --------------------------------------------------------- |
|
|
| **`MatchmakerMatched`** | Validates matchmaker tickets and instantiates a new match |
|
|
|
|
---
|
|
|
|
## 🎮 Gameplay Protocol
|
|
|
|
### OpCodes
|
|
|
|
| OpCode | Direction | Meaning |
|
|
| ------ | --------------- | ----------------------------- |
|
|
| **1** | Client → Server | Submit move `{x, y}` |
|
|
| **2** | Server → Client | Full authoritative game state |
|
|
|
|
---
|
|
|
|
## 🧠 Authoritative Flow Diagram
|
|
|
|
```mermaid
|
|
sequenceDiagram
|
|
participant C1 as Client 1
|
|
participant C2 as Client 2
|
|
participant S as Nakama + Go Plugin
|
|
|
|
C1->>S: Matchmaker Join
|
|
C2->>S: Matchmaker Join
|
|
S->>S: MatchmakerMatched()
|
|
S-->>C1: Matched
|
|
S-->>C2: Matched
|
|
|
|
C1->>S: OpCode 1 (Move)
|
|
S->>S: Validate Move
|
|
S-->>C1: OpCode 2 (Updated State)
|
|
S-->>C2: OpCode 2 (Updated State)
|
|
```
|
|
|
|
---
|
|
|
|
## ⚙️ Build & Development
|
|
|
|
### Build Go Plugin
|
|
|
|
```
|
|
CGO_ENABLED=1 go build \
|
|
--trimpath \
|
|
--buildmode=plugin \
|
|
-o build/main.so \
|
|
./plugins
|
|
```
|
|
|
|
### Run Nakama Locally
|
|
|
|
```
|
|
nakama migrate up --database.address "$DB_ADDR"
|
|
nakama \
|
|
--database.address "$DB_ADDR" \
|
|
--socket.server_key="$SERVER_KEY"
|
|
```
|
|
|
|
---
|
|
|
|
## 🐳 Docker Build (Multi-Stage)
|
|
|
|
```dockerfile
|
|
FROM --platform=linux/arm64 golang:1.21.6 AS plugin_builder
|
|
|
|
RUN go mod download
|
|
COPY . .
|
|
RUN CGO_ENABLED=1 go build --buildmode=plugin -o build/main.so ./plugins
|
|
|
|
FROM heroiclabs/nakama:3.21.0-arm
|
|
COPY --from=plugin_builder /workspace/build/main.so /nakama/data/modules/main.so
|
|
ENTRYPOINT ...
|
|
```
|
|
|
|
---
|
|
|
|
## 🤖 CI/CD — Drone Pipeline
|
|
|
|
Drone performs:
|
|
|
|
1. Fetch latest Git tag
|
|
2. Check if Docker image already exists
|
|
3. Build Nakama + plugin
|
|
4. Push to private registry
|
|
5. Stop old container
|
|
6. Deploy new Nakama server automatically
|
|
|
|
Full pipeline included in repository (`.drone.yml`).
|
|
|
|
---
|
|
|
|
## 🌐 Traefik Routing
|
|
|
|
### HTTPS
|
|
|
|
```
|
|
nakama.aetoskia.com
|
|
/ → HTTP API
|
|
/ws → WebSocket (real-time)
|
|
```
|
|
|
|
Includes:
|
|
|
|
* CORS rules
|
|
* WebSocket upgrade headers
|
|
* Certificate resolver
|
|
* Secure default middlewares
|
|
|
|
---
|
|
|
|
## 🔧 Environment Variables
|
|
|
|
| Variable | Description |
|
|
| --------------- | ---------------------------- |
|
|
| `DB_ADDR` | PostgreSQL connection string |
|
|
| `SERVER_KEY` | Nakama server key |
|
|
| `REGISTRY_HOST` | Private registry |
|
|
|
|
---
|
|
|
|
## 📊 Leaderboards
|
|
|
|
* Created during server start
|
|
* Score: `+1` on win
|
|
* Metadata logged (mode, player IDs)
|
|
|
|
---
|
|
|
|
## 🧪 Testing
|
|
|
|
* Win/loss/draw simulation
|
|
* Invalid move rejection
|
|
* Disconnect → forfeit
|
|
* Load testing matchmaking
|
|
|
|
---
|
|
|
|
## 📈 Production Deployment
|
|
|
|
Supported on:
|
|
|
|
* ARM homelabs (Raspberry Pi)
|
|
* Google Cloud (Compute Engine + Cloud SQL)
|
|
* AWS EC2
|
|
* Kubernetes (optional)
|
|
|
|
---
|
|
|
|
## 🤝 Contributing
|
|
|
|
1. Fork repo
|
|
2. Create feature branch
|
|
3. Write tests
|
|
4. Submit PR
|
|
|
|
Coding style: Go fmt + idiomatic Go; follow Nakama plugin constraints.
|
|
|
|
---
|