MMO RPG Server Development
Expert coding rules and best practices for building high-performance MMO RPG servers using TypeScript, WebAssembly, and Node.js worker threads.
Core Philosophy
Build scalable, maintainable MMO server infrastructure that prioritizes:
**Clarity**: Easy-to-read, self-documenting code**Performance**: CPU-intensive tasks in WASM, I/O on main thread**Scalability**: Worker threads with shared memory, horizontal scaling ready**Modularity**: SOLID principles, TypeScript interfaces, dependency injection**Lean Code**: Minimal duplication, efficient algorithms, token-optimizedPerformance Architecture
1. WebAssembly for Heavy Computation
Offload procedural generation, physics, pathfinding to C++/Rust → WASMUse Emscripten for compilation: `emcc -O3 generator.cpp -o generator.wasm`Batch WASM calls to minimize JS ↔ WASM overheadStore WASM modules in `src/wasm/`, TypeScript wrappers alongside2. Worker Threads with Shared Memory
Concurrent game logic (player updates, regions) in Node.js workersUse `SharedArrayBuffer` + typed arrays (`Int32Array`, `Float32Array`) for stateSynchronize with `Atomics` operations to prevent race conditionsKeep main thread free for WebSocket I/O3. Thread Safety Patterns
```typescript
// Atomic operations for shared state
Atomics.store(sharedArray, index, value);
const current = Atomics.load(sharedArray, index);
Atomics.add(sharedArray, index, delta);
```
4. Performance Monitoring
Profile with `node --prof server.ts` and `node --prof-process isolate-*.log`Monitor memory usage, event loop lag, worker thread utilizationCache frequently accessed data (e.g., map chunks, player stats)TypeScript Best Practices
5. Strict Type Safety
**Mandatory**: All files end in `.ts`, strict mode in `tsconfig.json`No `any` type; use `unknown` + type guards if necessaryLeverage type inference: `const x = 5` not `const x: number = 5`Union types + guards: `if (typeof x === 'string') { ... }`6. Interfaces for Contracts
```typescript
// Define abstractions, not implementations
interface IPlayer {
id: string;
position: Vector3;
move(delta: Vector3): void;
}
// Implement interfaces for modularity
class Player implements IPlayer { ... }
class VIPPlayer implements IPlayer { ... }
```
7. Generic Type-Safe Components
```typescript
class Cache<T> {
private data = new Map<string, T>();
get(key: string): T | undefined { return this.data.get(key); }
set(key: string, value: T): void { this.data.set(key, value); }
}
```
SOLID Principles
8. Single Responsibility (SRP)
One class = one purpose: `LobbyManager` only manages lobbies, not game stateSplit large files: separate I/O handlers from business logicMethods should do one thing: `createLobby()` not `createLobbyAndNotifyPlayers()`9. Open-Closed (OCP)
Extend via inheritance/composition, don't modify base classesExample: Add lobby types via subclasses, not `if (type === 'pvp')`Use abstract classes/interfaces for extension points10. Liskov Substitution (LSP)
Subclasses must honor base class contracts`VIPPlayer` works anywhere `Player` is expectedAvoid overriding methods in breaking ways11. Interface Segregation (ISP)
Small, focused interfaces: `Movable`, `Damageable`, not `Entity`Clients depend only on methods they useSplit fat interfaces into cohesive ones12. Dependency Inversion (DIP)
```typescript
// Depend on abstractions via constructor injection
class GameServer {
constructor(private logger: ILogger, private db: IDatabase) {}
}
// Inject concrete implementations
const server = new GameServer(new ConsoleLogger(), new PostgresDB());
```
Lean Code Practices
13. Minimize Duplication
Extract repeated logic into functions/modulesUse concise syntax: arrow functions, optional chaining `?.`, destructuringRemove unused imports, variables, dead code immediately14. Efficient Algorithms & Data Structures
Use appropriate structures: `Set` for uniqueness, `Map` for lookups, typed arrays for numbersChoose optimal algorithms: binary search over linear, O(1) over O(n)Cache computed results where safe (e.g., map chunks, static data)15. Token Optimization
Short, clear names: `pos` not `playerPosition` (where unambiguous)Comments only for non-obvious logic: `// Init lobby` not paragraph explanationsLet TypeScript infer types: `const x = 5` not `const x: number = 5`Balance brevity with readability: avoid cryptic abbreviationsProject Structure
```
project-root/
├── src/
│ ├── core/
│ │ ├── lobby/
│ │ │ ├── lobbyManager.ts # Lobby lifecycle
│ │ │ └── lobbyWorker.ts # Worker thread logic
│ │ └── game/
│ │ ├── player.ts # Player entity
│ │ └── world.ts # World state
│ ├── utils/
│ │ ├── logger.ts # Centralized logging
│ │ └── helpers.ts # Shared utilities
│ ├── config/
│ │ ├── env.ts # Environment vars
│ │ └── constants.ts # Magic numbers
│ ├── wasm/
│ │ ├── generator.cpp # C++ source
│ │ ├── generator.wasm # Compiled WASM
│ │ └── generator.ts # TS wrapper
│ ├── server/
│ │ └── server.ts # Entry point
│ └── index.ts # Bootstrap
├── tests/ # Unit tests (Jest)
├── scripts/ # Build/deploy scripts
├── docs/ # Architecture docs
├── package.json
├── tsconfig.json
└── yarn.lock # Locked dependencies
```
Naming Conventions
**Files/Folders**: `camelCase` (`lobbyManager.ts`, `core/lobby/`)**Classes**: `PascalCase` (`LobbyManager`, `Player`)**Functions/Variables**: `camelCase` (`createLobby`, `maxPlayers`)**Constants**: `UPPER_CASE` (`MAX_PLAYERS`, `DEFAULT_REGION`)**Interfaces**: `PascalCase` with `I` prefix optional (`IPlayer` or `Player`)Error Handling & Logging
16. Centralized Error Management
```typescript
// utils/logger.ts
export class Logger {
error(msg: string, err: Error): void { /* ... */ }
warn(msg: string): void { /* ... */ }
info(msg: string): void { /* ... */ }
}
// Usage
try {
await riskyOperation();
} catch (err) {
logger.error('Operation failed', err);
throw new GameError('Player action failed', err);
}
```
17. Async Best Practices
Always use `async/await` over raw promises/callbacksWrap async operations in `try-catch`Handle promise rejections: `process.on('unhandledRejection', ...)`Testing & Quality
18. Unit Testing Requirements
Write tests for all modules in `tests/` using JestMinimum 80% code coverageMock external dependencies (DB, network, WASM)Test file naming: `<module>.test.ts`19. Code Quality Tools
**ESLint**: TypeScript support + Airbnb style guide**Prettier**: Auto-format on save**Type Checking**: Run `tsc --noEmit` before commits**Pre-commit Hooks**: Lint, format, type-check via HuskyDependency Management
20. Mandatory Yarn Usage
**Always** use Yarn: `yarn add`, `yarn install`, `yarn upgrade`**Never** use npm or other package managersLock versions in `yarn.lock` for reproducible buildsPin critical dependencies (WASM tools, Node.js LTS)Version Control
21. Git Practices
**Commit Messages**: `feat: add lobby creation`, `fix: race condition in player update`**Branching**: GitFlow (`main`, `develop`, `feature/*`, `hotfix/*`)**Atomic Commits**: One logical change per commit**Code Review**: All merges require review for SOLID complianceKey Implementation Notes
1. **WASM Integration**: Instantiate modules async, cache instances globally
2. **Worker Threads**: Spawn per region/shard, communicate via message passing
3. **Shared Memory Layout**: Document buffer structure (offsets, types) in comments
4. **Scalability Path**: Start with workers, scale to multi-process + Redis if needed
5. **Stability**: Use Node.js LTS, well-tested WASM toolchains, avoid experimental features
Documentation Requirements
JSDoc for all public functions/classes: `@param`, `@returns`, `@throws`File-level comment describing purposeArchitecture diagrams in `docs/` for complex systemsUpdate `docs/architecture.md` when adding major features