Skip to content

Latest commit

 

History

History
272 lines (210 loc) · 10.4 KB

File metadata and controls

272 lines (210 loc) · 10.4 KB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project Overview

Reldens is an MMORPG Platform (v4.0.0-beta.39) built on Node.js, designed for developers to create multiplayer games. The platform integrates:

  • Server: Colyseus 0.16 for multiplayer game server
  • Client: Phaser 3 for game engine, Parcel for bundling
  • Database: Supports multiple storage drivers (objection-js, mikro-orm, prisma)
  • Architecture: Client-server with authoritative server, real-time synchronization via WebSockets

Node Version: >= 20.0.0

Sub-Packages

  • @reldens/utils - Core utilities, Shortcuts class (imported as sc), EventsManagerSingleton, Logger
  • @reldens/server-utils - Server utilities, FileHandler, configuration helpers
  • @reldens/storage - Multi-ORM database layer (ObjectionJS, MikroORM, Prisma)
  • @reldens/cms - Content management system and admin panel
  • @reldens/items-system - Items and inventory system
  • @reldens/modifiers - Stats and modifiers system
  • @reldens/skills - Skills and abilities system

Essential Commands

# Testing
npm test
node tests/manager.js --filter="test-name" --break-on-error

# Building
reldens buildSkeleton                   # Build both styles and client
reldens fullRebuild                     # Complete rebuild from scratch

# Database
reldens generateEntities [--override]   # Generate entities from database schema

# User management
reldens createAdmin --user=username --pass=password --email=email@example.com
reldens resetPassword --user=username --pass=newpassword

Full command reference: See .claude/commands-reference.md

Architecture Overview

Client-Server Organization

The codebase follows a client/server split architecture within each feature module:

lib/
  ├── {feature}/
  │   ├── client/           # Client-side code (Phaser, UI, rendering)
  │   ├── server/           # Server-side code (Colyseus rooms, logic)
  │   ├── constants.js      # Shared constants
  │   └── schemas/          # Colyseus state schemas (if applicable)

Core Entry Points

  • Server: server.jslib/game/server/manager.js (ServerManager)
  • Client: client.jslib/game/client/game-manager.js (GameManager)
  • Theme: theme/default/index.js initializes client with custom plugins

Feature Modules (23 Total)

The platform includes 23 feature modules: Game, Rooms, World, Config, Features, Actions, Inventory, Respawn, Rewards, Scores, Teams, Users, Chat, Audio, Prediction, Admin, Firebase, Ads, Import, Objects, Snippets, Bundlers.

Detailed list: See .claude/feature-modules.md

Configuration System

Reldens uses a database-driven configuration with runtime overrides:

  1. Database Config (config table): Path-based keys, scoped by scope field
  2. Environment Variables (.env): Prefix RELDENS_* for all settings
  3. Custom Classes: Passed via customClasses to override defaults

Key Environment Variables:

  • RELDENS_STORAGE_DRIVER - Storage driver (objection-js, mikro-orm, prisma)
  • RELDENS_DB_HOST, RELDENS_DB_PORT, RELDENS_DB_NAME, RELDENS_DB_USER, RELDENS_DB_PASSWORD
  • RELDENS_HOT_PLUG - Enable hot-plug configuration updates (0/1)

Full environment variables list: See .claude/environment-variables.md

Events System

The platform uses @reldens/utils EventsManagerSingleton for extensibility:

Common Event Patterns:

  • reldens.{action}Before - Hook before operation
  • reldens.{action}After - Hook after operation
  • Events are synchronous (emitSync) or async (emit)

Key Events:

  • reldens.serverConfigFeaturesReady - Features loaded
  • reldens.beforeJoinGame - Before player joins
  • reldens.startGameAfter - Game initialized
  • reldens.roomLoginOnAuth - Custom authentication logic

Plugin Pattern:

class ServerPlugin {
    setup({events}) {
        events.on('reldens.serverConfigFeaturesReady', (props) => {
            // Custom logic here
        });
    }
}

Storage & Entity Management

CRITICAL: Understanding getEntity()

dataServer.getEntity() returns a BaseDriver instance from @reldens/storage, NOT an Entity or Model class.

// Correct - returns BaseDriver
let statsRepository = this.dataServer.getEntity('stats');

// BaseDriver provides unified interface:
await statsRepository.create({key: 'hp', label: 'Health Points'});
await statsRepository.loadAll();
await statsRepository.loadOneBy('key', 'hp');
await statsRepository.updateById(1, {label: 'HP'});

Type Annotation:

/** @type {import('@reldens/storage').BaseDriver} */
this.statsRepository = this.dataServer.getEntity('stats');

Storage Drivers:

  • prisma (current default): Modern ORM with type safety, custom validation
  • objection-js: Uses Knex.js, direct SQL, no validation
  • mikro-orm: ORM with decorators, supports MongoDB

Detailed architecture: See .claude/storage-architecture.md Entity list: See .claude/entities-reference.md

Theme & Customization

Theme Structure (theme/):

  • plugins/ - Custom client/server plugins for game-specific logic
  • default/ - Default theme assets (HTML, CSS, sprites, audio)
  • admin/ - Admin panel customizations

Theme Management: ThemeManager (lib/game/server/theme-manager.js) handles asset copying, bundling, and CSS compilation.

Client Bundling Best Practices

CRITICAL: Always use themeManager.createClientBundle() instead of calling buildClient() or buildCss() directly:

  • createClientBundle() - Wrapper that checks RELDENS_ALLOW_RUN_BUNDLER environment variable (used during server startup)
  • buildClient() - Direct method that checks RELDENS_ALLOW_BUILD_CLIENT environment variable
  • buildCss() - Direct method that checks RELDENS_ALLOW_BUILD_CSS environment variable

Environment Variables:

  • RELDENS_ALLOW_RUN_BUNDLER - Controls createClientBundle() execution (default: 0)
  • RELDENS_ALLOW_BUILD_CLIENT - Controls buildClient() execution (default: 1)
  • RELDENS_ALLOW_BUILD_CSS - Controls buildCss() execution (default: 1)

Why this matters: Production servers can regenerate clients and run Parcel builds for hot-reloading. These environment variables allow you to control when bundling happens, preventing unexpected builds during startup or deployment.

Colyseus 0.16 - CRITICAL State Synchronization

CRITICAL TIMING ISSUE: Colyseus 0.16 state synchronization is asynchronous.

Problem Pattern (WRONG)

listenMessages(room, gameManager) {
    if(!room.state || !room.state.bodies){
        return false;  // ❌ WRONG - callbacks never set up!
    }
    this.setAddBodyCallback(room, gameManager);
}

Correct Pattern (RIGHT)

listenMessages(room, gameManager) {
    if(!room.state || !room.state.bodies){
        room.onStateChange.once((state) => {
            this.setAddBodyCallback(room, gameManager);  // ✅ Wait for state
        });
        return false;
    }
    this.setAddBodyCallback(room, gameManager);
}

Alternative - Use Reactive Patterns:

activateRoom(room) {
    this.playersManager = RoomStateEntitiesManager.onEntityAdd(
        room,
        'players',
        (player, key) => {
            this.handlePlayerAdded(player, key);
        }
    );
}

CRITICAL: Colyseus auto-cleans all listeners. Never store manager references or add manual disposal code unless explicitly needed.

Room Lifecycle

  1. onCreate(options): Initialize world, physics, objects
  2. Player joins → onJoin(client, options)
  3. Message handling → onMessage(client, message)
  4. Player leaves → onLeave(client, consented)
  5. Room disposal → onDispose()

Common Development Patterns

Adding a New Feature

  1. Create feature module in lib/{feature-name}/
  2. Add database table in migrations/
  3. Create client/server subdirectories
  4. Add feature entry to features table
  5. Register in lib/features/server/config-server.js
  6. Implement setup() method to hook events

Modifying Game Logic

  • Combat/Skills: Edit lib/actions/server/battle.js or pve.js
  • Player Stats: Configure via database stats table
  • Room Behavior: Extend RoomScene or hook reldens.createRoomAfter event
  • Client Rendering: Modify Phaser scenes in lib/game/client/scene-*.js

Working with Database

  • Always use entity models via dataServer.getEntity(), never raw SQL
  • Generated entities are read-only; extend in server/models/
  • Use migrations for schema changes
  • Regenerate entities after schema changes: reldens generateEntities --override

Important Notes

  • Authoritative Server: All game logic runs on server; client is display-only
  • Hot Plug: Admin panel changes reload without restart if RELDENS_HOT_PLUG=1
  • Logging: Use @reldens/utils/Logger (configurable via RELDENS_LOG_LEVEL)
  • File Operations: Always use @reldens/server-utils FileHandler (never Node.js fs)
  • Shortcuts Class: Import as sc from @reldens/utils - provides sc.get, sc.hasOwn, sc.isArray, etc.
  • Colyseus 0.16: All client callbacks use StateCallbacksManager and RoomStateEntitiesManager
  • Buffer Polyfill: Required for Parcel bundling with Colyseus 0.16

Analysis Approach

When working on code issues:

  • Always investigate thoroughly before making changes
  • Read related files completely before proposing solutions
  • Trace execution flows and dependencies
  • Provide proof for issues, never guess or assume
  • Verify file contents before creating patches
  • A variable with an unexpected value is not an issue, it is the result of a previous issue

Community & Support

Detailed Reference Documentation

  • Commands: .claude/commands-reference.md - All CLI commands
  • Environment Variables: .claude/environment-variables.md - All RELDENS_* variables
  • Feature Modules: .claude/feature-modules.md - All 23 feature modules
  • Storage Architecture: .claude/storage-architecture.md - Entity management deep dive
  • Entities: .claude/entities-reference.md - All 60+ entity types
  • Installer: .claude/installer-guide.md - Web-based installation wizard guide