From 32c5a9bf9c7633b9c5dfe17e7dc1a1ab74b4c5c5 Mon Sep 17 00:00:00 2001 From: Houmgaor Date: Mon, 23 Feb 2026 23:44:05 +0100 Subject: [PATCH] docs: add CLAUDE.md with project-specific guidance --- CLAUDE.md | 135 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 000000000..bd092d652 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,135 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +Erupe is a Go server emulator for Monster Hunter Frontier, a shut-down MMORPG. It handles authentication, world selection, and gameplay in a single binary running four TCP/HTTP servers. Go 1.25+ required. + +## Build & Test Commands + +```bash +go build -o erupe-ce # Build server +go build -o protbot ./cmd/protbot/ # Build protocol bot +go test -race ./... -timeout=10m # Run tests (race detection mandatory) +go test -v ./server/channelserver/... # Test one package +go test -run TestHandleMsg ./server/channelserver/... # Single test +go test -coverprofile=coverage.out ./... && go tool cover -func=coverage.out # Coverage (CI requires ≥50%) +gofmt -w . # Format +golangci-lint run ./... # Lint (v2 standard preset, must pass CI) +``` + +Docker (from `docker/`): +```bash +docker compose up db pgadmin # PostgreSQL + pgAdmin (port 5050) +docker compose up server # Erupe (after DB is healthy) +``` + +## Architecture + +### Four-Server Model (single binary, orchestrated from `main.go`) + +``` +Client ←[Blowfish TCP]→ Sign Server (53312) → Authentication, sessions + → Entrance Server (53310) → Server list, character select + → Channel Servers (54001+) → Gameplay, quests, multiplayer + → API Server (8080) → REST API (/health, /version, V2 sign) +``` + +Each server is in its own package under `server/`. The channel server is by far the largest (~200 files). + +### Channel Server Packet Flow + +1. `network/crypt_conn.go` decrypts TCP stream (Blowfish) +2. `network/mhfpacket/` deserializes binary packet into typed struct (~453 packet types, one file each) +3. `handlers_table.go` dispatches via `buildHandlerTable()` (~200+ `PacketID → handlerFunc` entries) +4. Handler in appropriate `handlers_*.go` processes it (organized by game system) + +Handler signature: `func(s *Session, p mhfpacket.MHFPacket)` + +### Layered Architecture + +``` +handlers_*.go → svc_*.go (service layer) → repo_*.go (data access) + ↓ + repo_interfaces.go (21 interfaces) + ↓ + repo_mocks_test.go (test doubles) +``` + +- **Handlers**: Parse packets, call services/repos, build responses. Must always send ACK (see Error Handling below). +- **Services** (`svc_guild.go`, etc.): Business logic extracted from handlers. New domain logic should go here. +- **Repositories**: All SQL lives in `repo_*.go` files behind interfaces in `repo_interfaces.go`. The `Server` struct holds interface types, not concrete implementations. Handler code must never contain inline SQL. +- **Sign server** has its own repo pattern: 3 interfaces in `server/signserver/repo_interfaces.go`. + +### Key Subsystems + +| File(s) | Purpose | +|---------|---------| +| `sys_session.go` | Per-connection state: character, stage, semaphores, send queue | +| `sys_stage.go` | `StageMap` (`sync.Map`-backed), multiplayer rooms/lobbies | +| `sys_channel_server.go` | Server lifecycle, Raviente shared state, world management | +| `sys_semaphore.go` | Distributed locks for events (Raviente siege, guild ops) | +| `channel_registry.go` | Cross-channel operations (worldcast, session lookup, mail) | +| `handlers_cast_binary.go` | Binary state relay between clients (position, animation) | +| `handlers_helpers.go` | `loadCharacterData`/`saveCharacterData` shared helpers | +| `guild_model.go` | Guild data structures | + +### Binary Serialization + +`common/byteframe.ByteFrame` — sequential big-endian reads/writes with sticky error pattern (`bf.Err()`). Used for all packet parsing, response building, and save data manipulation. Use `encoding/binary` only for random-access reads at computed offsets on existing `[]byte` slices. + +### Database + +PostgreSQL with embedded auto-migrating schema in `server/migrations/`: +- `sql/0001_init.sql` — consolidated baseline +- `seed/*.sql` — demo data (applied via `migrations.ApplySeedData()` on fresh DB) +- New migrations: `sql/0002_description.sql`, etc. (each runs in its own transaction) + +The server runs `migrations.Migrate()` automatically on startup. + +### Configuration + +Two reference files: `config.example.json` (minimal) and `config.reference.json` (all options). Loaded via Viper in `config/config.go`. All defaults registered in code. Supports 40 client versions (S1.0 → ZZ) via `ClientMode`. If `config.json` is missing, an interactive setup wizard launches at `http://localhost:8080`. + +### Protocol Bot (`cmd/protbot/`) + +Headless MHF client implementing the complete sign → entrance → channel flow. Shares `common/` and `network/crypto` but avoids `config` dependency via its own `conn/` package. + +## Concurrency + +Lock ordering: `Server.Mutex → Stage.RWMutex → semaphoreLock`. Stage map uses `sync.Map`; individual `Stage` structs have `sync.RWMutex`. Cross-channel operations go exclusively through `ChannelRegistry` — never access other servers' state directly. + +## Error Handling in Handlers + +The MHF client expects `MsgSysAck` for most requests. Missing ACKs cause client softlocks. On error paths, always send `doAckBufFail`/`doAckSimpleFail` before returning. + +## Testing + +- **Mock repos**: Handler tests use `repo_mocks_test.go` — no database needed +- **Table-driven tests**: Standard pattern (see `handlers_achievement_test.go`) +- **Race detection**: `go test -race` is mandatory in CI +- **Coverage floor**: CI enforces ≥50% total coverage + +## Adding a New Packet + +1. Define struct in `network/mhfpacket/msg_*.go` (implements `MHFPacket` interface: `Parse`, `Build`, `Opcode`) +2. Add packet ID constant in `network/packetid.go` +3. Register handler in `server/channelserver/handlers_table.go` +4. Implement handler in appropriate `handlers_*.go` file + +## Adding a Database Query + +1. Add method signature to the relevant interface in `repo_interfaces.go` +2. Implement in the corresponding `repo_*.go` file +3. Add mock implementation in `repo_mocks_test.go` + +## Known Issues + +See `docs/anti-patterns.md` for structural patterns and `docs/technical-debt.md` for specific fixable items with file paths and line numbers. + +## Contributing + +- Branch naming: `feature/`, `fix/`, `refactor/`, `docs/` +- Commit messages: conventional commits (`feat:`, `fix:`, `refactor:`, `docs:`) +- Update `CHANGELOG.md` under "Unreleased" for all changes