diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 000000000..90894ae23 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,356 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +Erupe is a community-maintained server emulator for Monster Hunter Frontier written in Go. It reverse-engineers the game server protocol to enable self-hosted Monster Hunter Frontier servers, supporting multiple game versions (Season 6.0 through ZZ) and platforms (PC, PS3, PS Vita, Wii U). + +**Module name:** `erupe-ce` +**Go version:** 1.25+ +**Current branch purpose:** Clean transition from 9.2.0 to future 9.3.0 release + +## Build and Development Commands + +### Building and Running + +```bash +# Build the server +go build + +# Build and produce binary +go build -o erupe-ce + +# Run without building +go run . + +# Run with hot reload during development +go run main.go +``` + +### Testing + +```bash +# Run all tests +go test -v ./... + +# Run tests for specific package +go test -v ./server/channelserver/... + +# Run specific test +go test -v ./server/channelserver/... -run TestName + +# Check for race conditions (important!) +go test -v -race ./... + +# Generate test coverage +go test -v -cover ./... +go test ./... -coverprofile=/tmp/coverage.out +go tool cover -html=/tmp/coverage.out -o /tmp/coverage.html +``` + +### Code Quality + +```bash +# Format code (ALWAYS run before committing) +gofmt -w . + +# Lint code +golangci-lint run ./... + +# Fix linting issues automatically +golangci-lint run ./... --fix +``` + +### Database Operations + +```bash +# Connect to PostgreSQL +psql -U postgres -d erupe + +# Apply schema patches (must be done in order) +psql -U postgres -d erupe -f patch-schema/01_patch.sql +psql -U postgres -d erupe -f patch-schema/02_patch.sql +# ... continue in order + +# With password from environment +PGPASSWORD='password' psql -U postgres -d erupe -f schema.sql +``` + +### Docker Development + +```bash +# Start database and pgadmin +docker compose up db pgadmin + +# Start server (after configuring database) +docker compose up server + +# Full stack +docker compose up +``` + +### Log Analysis + +The project includes a comprehensive log analyzer tool in `tools/loganalyzer/`: + +```bash +# Build log analyzer +cd tools/loganalyzer +go build -o loganalyzer + +# Filter logs by level +./loganalyzer filter -f ../../logs/erupe.log -level error + +# Analyze errors with stack traces +./loganalyzer errors -f ../../logs/erupe.log -stack -detailed + +# Track player connections +./loganalyzer connections -f ../../logs/erupe.log -sessions + +# Real-time log monitoring +./loganalyzer tail -f ../../logs/erupe.log -level error + +# Generate statistics +./loganalyzer stats -f ../../logs/erupe.log -detailed +``` + +## Architecture + +### Three-Server Architecture + +Erupe uses a multi-server architecture that mirrors the original Monster Hunter Frontier server design: + +1. **Sign Server** (Port 53312) + - Handles authentication and account management + - Located in `server/signserver/` + - Two versions: legacy (signserver) and modern HTTP-based (signv2server) + - Creates sign sessions with tokens for channel server authentication + +2. **Entrance Server** (Port 53310) + - Manages world/server selection and character list + - Located in `server/entranceserver/` + - Routes players to available channel servers + - Maintains server availability information + +3. **Channel Servers** (Ports 54001+) + - Handle actual gameplay sessions, quests, and player interactions + - Located in `server/channelserver/` + - Multiple instances can run simultaneously + - Organized by world types (Newbie, Normal, Cities, Tavern, Return, MezFes) + +### Channel Server Internal Architecture + +The channel server is the most complex component: + +**Session Management** ([sys_session.go](server/channelserver/sys_session.go)) + +- Each player connection creates a `Session` struct +- Sessions handle packet queuing, encryption, and client state +- Uses goroutines for send/receive loops +- Thread-safe with mutex locks + +**Handler System** ([handlers_table.go](server/channelserver/handlers_table.go)) + +- Packet handlers registered in `handlerTable` map +- Maps `network.PacketID` to `handlerFunc` +- Handlers organized by feature in separate files: + - `handlers_quest.go` - Quest system + - `handlers_guild.go` - Guild operations + - `handlers_stage.go` - Stage/room management + - `handlers_character.go` - Character data + - `handlers_*.go` - Feature-specific handlers + +**Stage System** ([sys_stage.go](server/channelserver/sys_stage.go)) + +- Stages are game rooms/areas where players interact +- Thread-safe stage creation, entry, movement, and destruction +- Stage locking/unlocking for privacy +- Stage binary data for synchronizing state between players + +**Semaphore System** ([sys_semaphore.go](server/channelserver/sys_semaphore.go)) + +- Resource locking mechanism for shared game resources +- Used for quests, events, and multiplayer coordination +- Global and local semaphores + +**Special Event Systems** + +- Raviente: Large-scale raid event (in `Server.raviente`) +- Diva Defense, Hunter's Festa, VS Tournament (handlers in `handlers_event.go`, `handlers_festa.go`, `handlers_tournament.go`) + +### Network Layer + +**Packet Structure** ([network/mhfpacket/](network/mhfpacket/)) + +- Packet definitions in `msg_*.go` files +- Each packet type implements `MHFPacket` interface +- Packets prefixed by type: `MSG_SYS_*`, `MSG_MHF_*`, `MSG_CA_*` +- Binary packet handling in `network/binpacket/` + +**Encryption** ([network/crypt_packet.go](network/crypt_packet.go)) + +- Custom encryption layer wrapping connections +- Different crypto for different server types + +**Compression** ([server/channelserver/compression/](server/channelserver/compression/)) + +- Delta compression (`deltacomp`) for bandwidth optimization +- Null compression (`nullcomp`) for debugging + +### Common Utilities + +**ByteFrame** ([common/byteframe/](common/byteframe/)) + +- Buffer for reading/writing binary data +- Provides methods for reading/writing various data types +- Critical for packet construction and parsing + +**PascalString** ([common/pascalstring/](common/pascalstring/)) + +- Length-prefixed string format used by game protocol +- Different variants for different string types + +**Client Context** ([network/clientctx/](network/clientctx/)) + +- Stores client version and capabilities +- Used for multi-version support + +## Database Schema Management + +**Schema Types:** + +- **Initialization Schema:** Bootstraps database to version 9.1.0 (in `schemas/`) +- **Patch Schemas:** Development updates in `patch-schema/` (numbered, apply in order) +- **Update Schemas:** Production-ready consolidated updates (for releases) +- **Bundled Schemas:** Demo data templates in `schemas/bundled-schema/` (shops, events, gacha) + +**Important:** Patch schemas are subject to change during development. They get consolidated into update schemas on release. Apply patches in numerical order. + +## Configuration System + +Configuration uses Viper and is defined in `config/config.go`. The `ErupeConfig` global variable holds runtime configuration loaded from `config.json`. + +**Key configuration sections:** + +- `DevMode` and `DevModeOptions` - Development flags and debugging +- `GameplayOptions` - Gameplay modifiers (NP/RP caps, boost times, quest allowances) +- `Database` - PostgreSQL connection settings +- `Sign`, `SignV2`, `Entrance`, `Channel` - Server enable/disable and ports +- `Discord` - Discord bot integration +- `Logging` - File logging with rotation (uses lumberjack) + +## Concurrency Patterns + +**Critical:** This codebase heavily uses goroutines and shared state. Always: + +1. Use mutexes when accessing shared state: + - Server-level: `s.server.Lock()` / `s.server.Unlock()` + - Stage-level: `s.server.stagesLock.Lock()` / `s.server.stagesLock.Unlock()` + - Session-level: `s.Lock()` / `s.Unlock()` + +2. Use RWMutex for read-heavy operations: + - `s.server.stagesLock.RLock()` for reads + - `s.server.stagesLock.Lock()` for writes + +3. Test with race detector: + + ```bash + go test -race ./... + ``` + +4. Common concurrency scenarios: + - Stage access: Always lock `s.server.stagesLock` when reading/writing stage map + - Session broadcasts: Iterate sessions under lock + - Database operations: Use transactions for multi-step operations + +## Packet Handler Development + +When adding new packet handlers: + +1. Define packet structure in `network/mhfpacket/msg_*.go` +2. Implement `Build()` and `Parse()` methods +3. Add handler function in appropriate `handlers_*.go` file +4. Register in `handlerTable` map in `handlers_table.go` +5. Use helper functions: + - `doAckBufSucceed(s, ackHandle, data)` - Success response with data + - `doAckBufFail(s, ackHandle, data)` - Failure response + - `stubEnumerateNoResults(s, ackHandle)` - Empty enumerate response + - `stubGetNoResults(s, ackHandle)` - Empty get response + +Example handler pattern: + +```go +func handleMsgMhfYourPacket(s *Session, p mhfpacket.MHFPacket) { + pkt := p.(*mhfpacket.MsgMhfYourPacket) + + // Process packet + resp := byteframe.NewByteFrame() + resp.WriteUint32(someValue) + + doAckBufSucceed(s, pkt.AckHandle, resp.Data()) +} +``` + +## Testing Practices + +- Use table-driven tests for multiple scenarios +- Mock database operations where appropriate +- Test concurrent access patterns with goroutines +- Test both success and error paths +- Add tests in `*_test.go` files next to source files + +## Common Pitfalls + +1. **Thread Safety:** Always consider concurrent access. If unsure, add locks. +2. **Database Queries:** Use parameterized queries (`$1`, `$2`) to prevent SQL injection +3. **Error Handling:** Never ignore errors - log them or handle appropriately +4. **Session State:** Be careful with session state during disconnects +5. **Packet Ordering:** Some packets have ordering requirements - check client expectations +6. **Binary Data:** Always use `byteframe` for binary reads/writes to ensure correct endianness + +## Commit and PR Guidelines + +**Commit message format:** + +- `feat: description` - New features +- `fix: description` - Bug fixes +- `refactor: description` - Code refactoring +- `docs: description` - Documentation +- `chore: description` - Maintenance tasks + +**Before committing:** + +1. Run `gofmt -w .` +2. Run tests: `go test -v ./...` +3. Check for race conditions: `go test -race ./...` +4. Update CHANGELOG.md under "Unreleased" section + +**PR Requirements:** + +- Clear description of changes +- Test coverage for new features +- No race conditions +- Passes all existing tests +- Updated documentation if needed + +## Discord Integration + +Optional Discord bot in `server/discordbot/` provides: + +- Real-time server activity notifications +- Player connection/disconnection events +- Quest completions and event notifications + +Configured via `Discord` section in config.json. + +## Multi-Version Support + +The codebase supports multiple game client versions through: + +- `ClientMode` configuration setting +- Client context detection +- Version-specific packet handling +- Binary file compatibility (quests/scenarios in `bin/`) + +Primary focus: G10-ZZ (ClientMode), with varying support for older versions. diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 000000000..4c29a7bb4 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,249 @@ +# Erupe Configuration Documentation + +Comprehensive configuration documentation for Erupe, the Monster Hunter Frontier server emulator. + +## Quick Start + +1. Copy [config.example.json](../config.example.json) to `config.json` +2. Read [Basic Settings](basic-settings.md) and [Server Configuration](server-configuration.md) +3. Set up [Database](database.md) +4. Adjust [Gameplay Options](gameplay-options.md) to your preference +5. Start the server! + +## Documentation Index + +### Essential Configuration + +- **[Basic Settings](basic-settings.md)** - Host, language, and basic server options +- **[Server Configuration](server-configuration.md)** - Sign, Entrance, and Channel server setup +- **[Database](database.md)** - PostgreSQL configuration and schema management + +### Development + +- **[Development Mode](development-mode.md)** - Debug options, packet logging, and testing tools +- **[Logging](logging.md)** - File logging, rotation, and log analysis + +### Gameplay & Features + +- **[Gameplay Options](gameplay-options.md)** - NP/RP caps, boost times, quest allowances +- **[Courses](courses.md)** - Subscription course configuration +- **[In-Game Commands](commands.md)** - Chat commands for players and admins + +### Optional Features + +- **[Discord Integration](discord-integration.md)** - Real-time Discord bot for server activity + +## Configuration File Structure + +The main configuration file is `config.json` with this structure: + +```json +{ + "Host": "127.0.0.1", + "BinPath": "bin", + "Language": "en", + + "DevMode": false, + "DevModeOptions": { ... }, + + "GameplayOptions": { ... }, + "Logging": { ... }, + "Discord": { ... }, + "Commands": [ ... ], + "Courses": [ ... ], + + "Database": { ... }, + + "Sign": { ... }, + "SignV2": { ... }, + "Channel": { ... }, + "Entrance": { ... } +} +``` + +## Configuration Sections + +| Section | Documentation | Purpose | +|---------|---------------|---------| +| Basic Settings | [basic-settings.md](basic-settings.md) | Host, paths, language, login notices | +| DevMode | [development-mode.md](development-mode.md) | Development and debugging options | +| GameplayOptions | [gameplay-options.md](gameplay-options.md) | Gameplay balance and modifiers | +| Logging | [logging.md](logging.md) | File logging and rotation | +| Discord | [discord-integration.md](discord-integration.md) | Discord bot integration | +| Commands | [commands.md](commands.md) | In-game chat commands | +| Courses | [courses.md](courses.md) | Subscription courses | +| Database | [database.md](database.md) | PostgreSQL connection | +| Sign/SignV2 | [server-configuration.md](server-configuration.md#sign-server) | Authentication servers | +| Channel | [server-configuration.md](server-configuration.md#channel-server) | Gameplay server | +| Entrance | [server-configuration.md](server-configuration.md#entrance-server) | World list server | + +## Common Configuration Scenarios + +### Local Development Server + +Perfect for testing and development: + +```json +{ + "Host": "127.0.0.1", + "DevMode": true, + "DevModeOptions": { + "AutoCreateAccount": true, + "MaxLauncherHR": true + }, + "Database": { + "Host": "localhost", + "User": "postgres", + "Password": "dev", + "Database": "erupe_dev" + } +} +``` + +See: [development-mode.md](development-mode.md) + +### Production Server (Minimal) + +Minimal production-ready configuration: + +```json +{ + "Host": "", + "DevMode": false, + "DisableSoftCrash": true, + "Logging": { + "LogToFile": true, + "LogMaxBackups": 7, + "LogMaxAge": 30 + }, + "Database": { + "Host": "localhost", + "User": "erupe", + "Password": "SECURE_PASSWORD_HERE", + "Database": "erupe" + } +} +``` + +See: [basic-settings.md](basic-settings.md), [logging.md](logging.md) + +### Community Server + +Feature-rich community server: + +```json +{ + "Host": "", + "DevMode": false, + "HideLoginNotice": false, + "LoginNotices": ["Welcome to our server!"], + "GameplayOptions": { + "MaximumNP": 999999, + "BoostTimeDuration": 240 + }, + "Discord": { + "Enabled": true, + "BotToken": "YOUR_TOKEN", + "RealtimeChannelID": "YOUR_CHANNEL_ID" + }, + "Commands": [ + {"Name": "Reload", "Enabled": true, "Prefix": "!reload"}, + {"Name": "Course", "Enabled": true, "Prefix": "!course"} + ] +} +``` + +See: [gameplay-options.md](gameplay-options.md), [discord-integration.md](discord-integration.md), [commands.md](commands.md) + +## Security Checklist + +Before running a public server, verify: + +- [ ] `DevMode: false` - Disable development mode +- [ ] `AutoCreateAccount: false` - Require manual account creation +- [ ] `DisableTokenCheck: false` - Enable token validation +- [ ] `CleanDB: false` - Don't wipe database on startup +- [ ] Strong database password set +- [ ] `Rights` command disabled (or carefully controlled) +- [ ] `KeyQuest` command disabled (unless intentional) +- [ ] Firewall configured for only necessary ports +- [ ] Database not exposed publicly +- [ ] Logging enabled for monitoring + +See: [development-mode.md#security-warnings](development-mode.md#security-warnings) + +## Performance Tuning + +For large servers: + +1. **Increase player limits**: Adjust `MaxPlayers` in channel configuration +2. **Add more channels**: Distribute load across multiple channel servers +3. **Optimize database**: Use connection pooling, increase shared buffers +4. **Increase log rotation**: Larger `LogMaxSize` and `LogMaxBackups` +5. **Monitor resources**: Use log analyzer to track errors and performance + +See: [server-configuration.md](server-configuration.md), [database.md#performance-tuning](database.md#performance-tuning) + +## Configuration Validation + +Erupe validates configuration on startup. Common errors: + +| Error | Cause | Fix | +|-------|-------|-----| +| "Database password is blank" | Empty password field | Set a password in config | +| "Invalid host address" | Malformed Host value | Use valid IP or leave empty for auto-detect | +| "Discord failed" | Invalid Discord config | Check bot token and channel ID | +| Port already in use | Port conflict | Change port or stop conflicting service | + +## Environment-Specific Configuration + +### Docker + +When running in Docker, use service names for hosts: + +```json +{ + "Database": { + "Host": "db", + "Port": 5432 + } +} +``` + +See: [database.md#docker-setup](database.md#docker-setup) + +### Cloud Hosting + +For cloud deployments: + +- Use environment variables for secrets (requires code modification) +- Enable `DisableSoftCrash: true` for auto-restart +- Use absolute paths for logs (`/var/log/erupe/erupe.log`) +- Consider external database (RDS, Cloud SQL) + +## Additional Resources + +- [CLAUDE.md](../CLAUDE.md) - Development guide and architecture +- [config.example.json](../config.example.json) - Full example configuration +- [Log Analyzer](../tools/loganalyzer/) - Log analysis tools +- [GitHub Issues](https://github.com/Andoryuuta/Erupe/issues) - Report bugs and request features + +## Getting Help + +If you need help with configuration: + +1. Check the relevant documentation page above +2. Review [config.example.json](../config.example.json) for examples +3. Check server logs for specific errors +4. Search [GitHub Issues](https://github.com/Andoryuuta/Erupe/issues) +5. Ask in the Erupe Discord community + +## Contributing + +Found an error or want to improve these docs? + +1. Fork the repository +2. Edit the documentation in `docs/` +3. Submit a pull request + +See [CLAUDE.md](../CLAUDE.md#commit-and-pr-guidelines) for contribution guidelines. diff --git a/docs/basic-settings.md b/docs/basic-settings.md new file mode 100644 index 000000000..e5ec5878d --- /dev/null +++ b/docs/basic-settings.md @@ -0,0 +1,89 @@ +# Basic Server Settings + +Basic configuration options for Erupe server hosting. + +## Configuration + +```json +{ + "Host": "127.0.0.1", + "BinPath": "bin", + "Language": "en", + "DisableSoftCrash": false, + "HideLoginNotice": true, + "LoginNotices": [ + "
Welcome to Erupe!" + ], + "PatchServerManifest": "", + "PatchServerFile": "", + "ScreenshotAPIURL": "", + "DeleteOnSaveCorruption": false +} +``` + +## Settings Reference + +| Setting | Type | Default | Description | +|---------|------|---------|-------------| +| `Host` | string | auto-detect | Server IP address. Leave empty to auto-detect. Use `"127.0.0.1"` for local hosting | +| `BinPath` | string | `"bin"` | Path to binary game data (quests, scenarios, etc.) | +| `Language` | string | `"en"` | Server language. `"en"` for English, `"jp"` for Japanese | +| `DisableSoftCrash` | boolean | `false` | When `true`, server exits immediately on crash (useful for auto-restart scripts) | +| `HideLoginNotice` | boolean | `true` | Hide the Erupe welcome notice on login | +| `LoginNotices` | array | `[]` | Custom MHFML-formatted login notices to display to players | +| `PatchServerManifest` | string | `""` | Override URL for patch manifest server (optional) | +| `PatchServerFile` | string | `""` | Override URL for patch file server (optional) | +| `ScreenshotAPIURL` | string | `""` | Destination URL for screenshots uploaded to BBS (optional) | +| `DeleteOnSaveCorruption` | boolean | `false` | If `true`, corrupted save data will be flagged for deletion | + +## Login Notices + +Login notices use MHFML (Monster Hunter Frontier Markup Language) formatting: + +```text +
Large Centered Red Text
+Normal Left-Aligned Yellow Text
+White Text +``` + +**Common MHFML Tags:** + +- `` - Start new line +- `
` - Line break +- `
`, ``, `` - Text alignment +- ``, `` - Text size +- `` (Red), `` (Yellow), `` (White) - Text color + +## Examples + +### Local Development Server + +```json +{ + "Host": "127.0.0.1", + "BinPath": "bin", + "Language": "en", + "DisableSoftCrash": false, + "HideLoginNotice": false +} +``` + +### Production Server with Auto-Restart + +```json +{ + "Host": "", + "BinPath": "bin", + "Language": "en", + "DisableSoftCrash": true, + "HideLoginNotice": false, + "LoginNotices": [ + "
Welcome to Our Server!
Join our Discord: discord.gg/example" + ] +} +``` + +## Related Documentation + +- [Server Configuration](server-configuration.md) - Server types and ports +- [Configuration Overview](README.md) - All configuration options diff --git a/docs/commands.md b/docs/commands.md new file mode 100644 index 000000000..ebbf44f22 --- /dev/null +++ b/docs/commands.md @@ -0,0 +1,335 @@ +# In-Game Commands + +In-game chat commands for players and administrators. + +## Configuration + +```json +{ + "Commands": [ + { + "Name": "Rights", + "Enabled": false, + "Prefix": "!rights" + }, + { + "Name": "Raviente", + "Enabled": true, + "Prefix": "!ravi" + }, + { + "Name": "Teleport", + "Enabled": false, + "Prefix": "!tele" + }, + { + "Name": "Reload", + "Enabled": true, + "Prefix": "!reload" + }, + { + "Name": "KeyQuest", + "Enabled": false, + "Prefix": "!kqf" + }, + { + "Name": "Course", + "Enabled": true, + "Prefix": "!course" + } + ] +} +``` + +## How Commands Work + +1. **Player Types Command**: Player sends a chat message starting with the command prefix +2. **Command Parser**: Server checks if message matches any enabled command prefix +3. **Command Handler**: Executes the command logic +4. **Response**: Server sends feedback message to the player + +Commands are parsed in [handlers_cast_binary.go:90](../server/channelserver/handlers_cast_binary.go#L90). + +## Available Commands + +### Reload + +**Prefix:** `!reload` +**Recommended:** Enabled +**Usage:** `!reload` + +Reloads all players and objects in the current stage: + +1. Removes all other players/objects from view +2. Waits 500ms +3. Re-adds all players/objects with updated data + +**Use Cases:** + +- Visual glitches (players appearing in wrong positions) +- Objects not displaying correctly +- Stage synchronization issues + +**Example:** + +```text +Player types: !reload +Server: "Reloading all players and objects..." +[View refreshes] +``` + +### Raviente + +**Prefix:** `!ravi` +**Recommended:** Enabled +**Usage:** `!ravi ` + +Control Raviente raid event. + +**Subcommands:** + +- `!ravi start` - Start the Raviente event +- `!ravi cm` or `!ravi checkmultiplier` - Check current damage multiplier + +**Examples:** + +```text +Player types: !ravi start +Server: "Raviente event started!" + +Player types: !ravi cm +Server: "Current Raviente multiplier: 2.5x" +``` + +### Course + +**Prefix:** `!course` +**Recommended:** Enabled +**Usage:** `!course ` + +Enable or disable subscription courses for your character. + +**Course Names:** + +- `hunterlife` or `hl` - Hunter Life Course +- `extra` or `ex` - Extra Course +- `premium` - Premium Course +- `assist` - Assist Course +- `n` - N Course +- `hiden` - Hiden Course +- `huntersupport` or `hs` - Hunter Support Course +- `nboost` - N Boost Course +- `netcafe` or `nc` - NetCafe Course +- `hlrenewing` - Hunter Life Renewing Course +- `exrenewing` - Extra Renewing Course + +**Note:** Only courses with `Enabled: true` in the [Courses](courses.md) configuration can be toggled. + +**Examples:** + +```text +Player types: !course premium +Server: "Premium Course enabled!" +[Player's account rights updated] + +Player types: !course premium +Server: "Premium Course disabled!" +[Toggled off] + +Player types: !course hiden +Server: "Hiden Course is locked on this server" +[Course not enabled in config] +``` + +### KeyQuest (KQF) + +**Prefix:** `!kqf` +**Recommended:** Disabled (unless intentional) +**Usage:** `!kqf get` or `!kqf set ` + +Get or set Key Quest flags (unlocks). + +**Subcommands:** + +- `!kqf get` - Display current KQF value +- `!kqf set <16-char hex>` - Set KQF value + +**Examples:** + +```text +Player types: !kqf get +Server: "Your KQF is: 0123456789ABCDEF" + +Player types: !kqf set 0000000000000000 +Server: "KQF set successfully!" +[Quest unlocks updated] + +Player types: !kqf set invalid +Server: "Usage: !kqf set <16 hex characters>" +``` + +**Warning:** This allows players to unlock content. Disable unless you want players to have this power. + +### Rights + +**Prefix:** `!rights` +**Recommended:** Disabled +**Usage:** `!rights ` + +Modify account rights/permissions (bitfield of enabled courses and permissions). + +**Example:** + +```text +Player types: !rights 255 +Server: "Account rights set to: 255" +[All courses/permissions enabled] + +Player types: !rights abc +Server: "Usage: !rights " +``` + +**⚠️ SECURITY WARNING:** This allows players to grant themselves admin privileges and all courses. **Only enable in development or for trusted administrators.** + +### Teleport + +**Prefix:** `!tele` +**Recommended:** Disabled (not yet implemented) +**Usage:** `!tele ` + +Teleport to specific locations. + +**Status:** Command structure exists but handler not fully implemented in the codebase. + +## Command Configuration + +Each command has three properties: + +```json +{ + "Name": "CommandName", + "Enabled": true, + "Prefix": "!prefix" +} +``` + +| Property | Type | Description | +|----------|------|-------------| +| `Name` | string | Command identifier (must match internal name) | +| `Enabled` | boolean | Whether the command is active | +| `Prefix` | string | Chat prefix that triggers the command | + +### Customizing Prefixes + +You can change command prefixes: + +```json +{ + "Name": "Reload", + "Enabled": true, + "Prefix": "/reload" +} +``` + +Now players would type `/reload` instead of `!reload`. + +### Disabling Commands + +Set `Enabled: false` to disable: + +```json +{ + "Name": "Rights", + "Enabled": false, + "Prefix": "!rights" +} +``` + +When disabled, typing the command returns: + +```text +Server: "The Rights command is disabled on this server" +``` + +## Security Considerations + +### High-Risk Commands (Disable in Production) + +- **Rights**: Grants admin privileges and all courses +- **KeyQuest**: Unlocks restricted content + +### Medium-Risk Commands (Use with Caution) + +- **Course**: Allows players to toggle courses without payment + - Mitigate by limiting which courses are `Enabled` in [Courses](courses.md) + +### Safe Commands + +- **Reload**: Only affects visual state, no persistent changes +- **Raviente**: Only affects raid event, no account changes + +## Implementation Details + +Commands are initialized on server startup from the config: + +```go +// handlers_cast_binary.go:40 +func init() { + commands = make(map[string]config.Command) + + for _, cmd := range config.ErupeConfig.Commands { + commands[cmd.Name] = cmd + if cmd.Enabled { + logger.Info(fmt.Sprintf("Command %s: Enabled, prefix: %s", cmd.Name, cmd.Prefix)) + } + } +} +``` + +Each command handler checks if the command is enabled before executing. + +## Examples + +### Minimal Safe Configuration + +```json +{ + "Commands": [ + {"Name": "Reload", "Enabled": true, "Prefix": "!reload"}, + {"Name": "Raviente", "Enabled": true, "Prefix": "!ravi"} + ] +} +``` + +### Full Development Configuration + +```json +{ + "Commands": [ + {"Name": "Rights", "Enabled": true, "Prefix": "!rights"}, + {"Name": "Raviente", "Enabled": true, "Prefix": "!ravi"}, + {"Name": "Teleport", "Enabled": true, "Prefix": "!tele"}, + {"Name": "Reload", "Enabled": true, "Prefix": "!reload"}, + {"Name": "KeyQuest", "Enabled": true, "Prefix": "!kqf"}, + {"Name": "Course", "Enabled": true, "Prefix": "!course"} + ] +} +``` + +### Custom Prefixes + +```json +{ + "Commands": [ + {"Name": "Reload", "Enabled": true, "Prefix": "/refresh"}, + {"Name": "Raviente", "Enabled": true, "Prefix": "/ravi"}, + {"Name": "Course", "Enabled": true, "Prefix": "/sub"} + ] +} +``` + +## Related Documentation + +- [Courses](courses.md) - Course configuration for the `!course` command +- [Discord Integration](discord-integration.md) - Commands may post to Discord +- [Gameplay Options](gameplay-options.md) - Gameplay balance settings diff --git a/docs/configuration.md b/docs/configuration.md new file mode 100644 index 000000000..b116ad2b1 --- /dev/null +++ b/docs/configuration.md @@ -0,0 +1,610 @@ +# Erupe Configuration Guide + +This guide explains the important configuration sections in `config.json`. Use [config.example.json](../config.example.json) as a template. + +## Table of Contents + +- [Basic Settings](#basic-settings) +- [Development Mode](#development-mode) +- [Gameplay Options](#gameplay-options) +- [Logging](#logging) +- [Discord Integration](#discord-integration) +- [In-Game Commands](#in-game-commands) +- [Courses](#courses) +- [Database](#database) +- [Server Configuration](#server-configuration) + +--- + +## Basic Settings + +```json +{ + "Host": "127.0.0.1", + "BinPath": "bin", + "Language": "en", + "DisableSoftCrash": false, + "HideLoginNotice": true +} +``` + +| Setting | Type | Description | +|---------|------|-------------| +| `Host` | string | Server IP address. Leave empty to auto-detect. Use `"127.0.0.1"` for local hosting | +| `BinPath` | string | Path to binary game data (quests, scenarios, etc.) | +| `Language` | string | Server language. `"en"` for English, `"jp"` for Japanese | +| `DisableSoftCrash` | boolean | When `true`, server exits immediately on crash (useful for auto-restart scripts) | +| `HideLoginNotice` | boolean | Hide the Erupe welcome notice on login | +| `LoginNotices` | array | Custom MHFML-formatted login notices to display | + +### Additional Settings + +- **`PatchServerManifest`**: Override URL for patch manifest server +- **`PatchServerFile`**: Override URL for patch file server +- **`ScreenshotAPIURL`**: Destination for screenshots uploaded to BBS +- **`DeleteOnSaveCorruption`**: If `true`, corrupted save data will be flagged for deletion + +--- + +## Development Mode + +```json +{ + "DevMode": true, + "DevModeOptions": { + "AutoCreateAccount": true, + "CleanDB": false, + "MaxLauncherHR": false, + "LogInboundMessages": false, + "LogOutboundMessages": false, + "MaxHexdumpLength": 256, + "DivaEvent": 0, + "FestaEvent": -1, + "TournamentEvent": 0, + "MezFesEvent": true, + "MezFesAlt": false, + "DisableTokenCheck": false, + "QuestDebugTools": false, + "SaveDumps": { + "Enabled": true, + "OutputDir": "savedata" + } + } +} +``` + +| Setting | Type | Description | +|---------|------|-------------| +| `DevMode` | boolean | Enables development mode (more verbose logging, development logger format) | +| `AutoCreateAccount` | boolean | **⚠️ SECURITY RISK**: Auto-create accounts on login (disable in production) | +| `CleanDB` | boolean | **⚠️ DESTRUCTIVE**: Wipes database on server start | +| `MaxLauncherHR` | boolean | Sets launcher HR to HR7 to join non-beginner worlds | +| `LogInboundMessages` | boolean | Log all packets received from clients (very verbose) | +| `LogOutboundMessages` | boolean | Log all packets sent to clients (very verbose) | +| `MaxHexdumpLength` | number | Maximum bytes to display in packet hexdumps | +| `DivaEvent` | number | Diva Defense event status (0 = off, higher = active) | +| `FestaEvent` | number | Hunter's Festa event status (-1 = off, higher = active) | +| `TournamentEvent` | number | VS Tournament event status (0 = off, higher = active) | +| `MezFesEvent` | boolean | Enable/disable MezFes event | +| `MezFesAlt` | boolean | Swap Volpakkun for Tokotoko in MezFes | +| `DisableTokenCheck` | boolean | **⚠️ SECURITY RISK**: Skip login token validation | +| `QuestDebugTools` | boolean | Enable quest debugging logs | +| `SaveDumps.Enabled` | boolean | Enable saving character data dumps | +| `SaveDumps.OutputDir` | string | Directory for save data dumps | + +--- + +## Gameplay Options + +```json +{ + "GameplayOptions": { + "FeaturedWeapons": 1, + "MaximumNP": 100000, + "MaximumRP": 50000, + "DisableLoginBoost": false, + "DisableBoostTime": false, + "BoostTimeDuration": 120, + "GuildMealDuration": 60, + "BonusQuestAllowance": 3, + "DailyQuestAllowance": 1 + } +} +``` + +| Setting | Type | Description | +|---------|------|-------------| +| `FeaturedWeapons` | number | Number of Active Feature weapons generated daily | +| `MaximumNP` | number | Maximum Network Points (NP) a player can hold | +| `MaximumRP` | number | Maximum Road Points (RP) a player can hold | +| `DisableLoginBoost` | boolean | Disable login boost system | +| `DisableBoostTime` | boolean | Disable daily NetCafe boost time | +| `BoostTimeDuration` | number | NetCafe boost time duration in minutes (default: 120) | +| `GuildMealDuration` | number | Guild meal activation duration in minutes (default: 60) | +| `BonusQuestAllowance` | number | Daily Bonus Point Quest allowance | +| `DailyQuestAllowance` | number | Daily Quest allowance | + +--- + +## Logging + +```json +{ + "Logging": { + "LogToFile": true, + "LogFilePath": "logs/erupe.log", + "LogMaxSize": 100, + "LogMaxBackups": 3, + "LogMaxAge": 28, + "LogCompress": true + } +} +``` + +Erupe uses [lumberjack](https://github.com/natefinch/lumberjack) for automatic log rotation and compression. + +| Setting | Type | Description | +|---------|------|-------------| +| `LogToFile` | boolean | Enable file logging (logs to both console and file) | +| `LogFilePath` | string | Path to log file (directory will be created automatically) | +| `LogMaxSize` | number | Maximum log file size in MB before rotation (default: 100) | +| `LogMaxBackups` | number | Number of old log files to keep (default: 3) | +| `LogMaxAge` | number | Maximum days to retain old logs (default: 28) | +| `LogCompress` | boolean | Compress rotated log files with gzip | + +**Log Format:** + +- When `DevMode: true`: Console format (human-readable) +- When `DevMode: false`: JSON format (production) + +**Log Analysis:** +Use the built-in log analyzer tool to analyze logs. See [Log Analysis Guide](../tools/loganalyzer/README.md) or [CLAUDE.md](../CLAUDE.md#log-analysis). + +--- + +## Discord Integration + +```json +{ + "Discord": { + "Enabled": false, + "BotToken": "", + "RealtimeChannelID": "" + } +} +``` + +Erupe includes an optional Discord bot that posts real-time server activity to a Discord channel. + +| Setting | Type | Description | +|---------|------|-------------| +| `Enabled` | boolean | Enable Discord integration | +| `BotToken` | string | Discord bot token from Discord Developer Portal | +| `RealtimeChannelID` | string | Discord channel ID where activity messages will be posted | + +### How Discord Integration Works + +When enabled, the Discord bot: + +1. **Connects on Server Startup**: The bot authenticates using the provided bot token +2. **Monitors Game Activity**: Listens for in-game chat messages and events +3. **Posts to Discord**: Sends formatted messages to the specified channel + +**What Gets Posted:** + +- Player chat messages (when sent to world/server chat) +- Player connection/disconnection events +- Quest completions +- Special event notifications + +### Setup Instructions + +1. **Create a Discord Bot:** + - Go to [Discord Developer Portal](https://discord.com/developers/applications) + - Create a new application + - Go to the "Bot" section and create a bot + - Copy the bot token + +2. **Get Channel ID:** + - Enable Developer Mode in Discord (User Settings → Advanced → Developer Mode) + - Right-click the channel you want to use + - Click "Copy ID" + +3. **Add Bot to Server:** + - Go to OAuth2 → URL Generator in the Developer Portal + - Select scopes: `bot` + - Select permissions: `Send Messages`, `Read Message History` + - Use the generated URL to invite the bot to your server + +4. **Configure Erupe:** + + ```json + { + "Discord": { + "Enabled": true, + "BotToken": "YOUR_BOT_TOKEN_HERE", + "RealtimeChannelID": "YOUR_CHANNEL_ID_HERE" + } + } + ``` + +**Implementation Details:** + +- Bot code: [server/discordbot/discord_bot.go](../server/discordbot/discord_bot.go) +- Uses [discordgo](https://github.com/bwmarrin/discordgo) library +- Message normalization for Discord mentions and emojis +- Non-blocking message sending (errors are logged but don't crash the server) + +--- + +## In-Game Commands + +```json +{ + "Commands": [ + { + "Name": "Rights", + "Enabled": false, + "Prefix": "!rights" + }, + { + "Name": "Raviente", + "Enabled": true, + "Prefix": "!ravi" + }, + { + "Name": "Teleport", + "Enabled": false, + "Prefix": "!tele" + }, + { + "Name": "Reload", + "Enabled": true, + "Prefix": "!reload" + }, + { + "Name": "KeyQuest", + "Enabled": false, + "Prefix": "!kqf" + }, + { + "Name": "Course", + "Enabled": true, + "Prefix": "!course" + } + ] +} +``` + +In-game chat commands allow players to perform various actions by typing commands in the chat. + +### Available Commands + +| Command | Prefix | Description | Usage | +|---------|--------|-------------|-------| +| **Rights** | `!rights` | Modify account rights/permissions | `!rights ` | +| **Raviente** | `!ravi` | Control Raviente event | `!ravi start`, `!ravi cm` (check multiplier) | +| **Teleport** | `!tele` | Teleport to locations | `!tele ` | +| **Reload** | `!reload` | Reload all players and objects in current stage | `!reload` | +| **KeyQuest** | `!kqf` | Get/set Key Quest flags | `!kqf get`, `!kqf set ` | +| **Course** | `!course` | Enable/disable subscription courses | `!course ` | + +### How Commands Work + +1. **Player Types Command**: Player sends a chat message starting with the command prefix +2. **Command Parser**: Server checks if message matches any enabled command prefix +3. **Command Handler**: Executes the command logic +4. **Response**: Server sends feedback message to the player + +**Implementation Details:** + +- Commands are parsed in [handlers_cast_binary.go:90](../server/channelserver/handlers_cast_binary.go#L90) +- Command map is initialized from config on server startup +- Each command has its own handler function +- Disabled commands return a "command disabled" message + +### Example Command Usage + +**Reload Command:** + +```text +Player types: !reload +Server: "Reloading all players and objects..." +Server: Removes all other players/objects from view +Server: Re-adds all players/objects with updated data +``` + +**Course Command:** + +```text +Player types: !course premium +Server: "Premium Course enabled!" +Server: Updates player's account rights in database +Server: Updates player's rights in current session +``` + +**KeyQuest Command:** + +```text +Player types: !kqf get +Server: "Your KQF is: 0123456789ABCDEF" + +Player types: !kqf set 0000000000000000 +Server: "KQF set successfully!" +``` + +### Security Considerations + +- **Rights Command**: Can grant admin privileges - disable in production +- **KeyQuest Command**: Can unlock content - disable if not desired +- Commands are per-server configuration (can be different per channel server) + +--- + +## Courses + +```json +{ + "Courses": [ + {"Name": "HunterLife", "Enabled": true}, + {"Name": "Extra", "Enabled": true}, + {"Name": "Premium", "Enabled": true}, + {"Name": "Assist", "Enabled": false}, + {"Name": "N", "Enabled": false}, + {"Name": "Hiden", "Enabled": false}, + {"Name": "HunterSupport", "Enabled": false}, + {"Name": "NBoost", "Enabled": false}, + {"Name": "NetCafe", "Enabled": true}, + {"Name": "HLRenewing", "Enabled": true}, + {"Name": "EXRenewing", "Enabled": true} + ] +} +``` + +Courses are subscription-based features in Monster Hunter Frontier (similar to premium subscriptions). + +| Course | Description | +|--------|-------------| +| `HunterLife` | Hunter Life Course - Basic subscription benefits | +| `Extra` | Extra Course - Additional benefits | +| `Premium` | Premium Course - Premium features | +| `Assist` | Assist Course - Helper features | +| `N` | N Course | +| `Hiden` | Hiden Course - Secret/hidden features | +| `HunterSupport` | Hunter Support Course | +| `NBoost` | N Boost Course | +| `NetCafe` | NetCafe Course - Internet cafe benefits | +| `HLRenewing` | Hunter Life Renewing Course | +| `EXRenewing` | Extra Renewing Course | + +**Note:** When `Enabled: true`, players can toggle the course on/off using the `!course` command (if enabled). When `Enabled: false`, the course is completely locked and cannot be activated. + +--- + +## Database + +```json +{ + "Database": { + "Host": "localhost", + "Port": 5432, + "User": "postgres", + "Password": "", + "Database": "erupe" + } +} +``` + +PostgreSQL database configuration. + +| Setting | Type | Description | +|---------|------|-------------| +| `Host` | string | Database host (default: `localhost`) | +| `Port` | number | Database port (default: `5432`) | +| `User` | string | Database user | +| `Password` | string | Database password (**required**, must not be empty) | +| `Database` | string | Database name | + +**Setup:** + +1. Install PostgreSQL +2. Create database: `createdb erupe` +3. Apply schema: `psql -U postgres -d erupe -f schema.sql` +4. Apply patches in order: `psql -U postgres -d erupe -f patch-schema/01_patch.sql` + +See [CLAUDE.md](../CLAUDE.md#database-operations) for more details. + +--- + +## Server Configuration + +### Sign Server (Authentication) + +```json +{ + "Sign": { + "Enabled": true, + "Port": 53312 + } +} +``` + +Legacy sign server for authentication and account management. + +| Setting | Type | Description | +|---------|------|-------------| +| `Enabled` | boolean | Enable the sign server | +| `Port` | number | Port number (default: 53312) | + +### SignV2 Server (Modern Authentication) + +```json +{ + "SignV2": { + "Enabled": false, + "Port": 8080 + } +} +``` + +Modern HTTP-based sign server (alternative to legacy sign server). + +| Setting | Type | Description | +|---------|------|-------------| +| `Enabled` | boolean | Enable the modern sign server | +| `Port` | number | Port number (default: 8080) | + +**Note:** Only enable one sign server at a time (Sign OR SignV2, not both). + +### Channel Server + +```json +{ + "Channel": { + "Enabled": true + } +} +``` + +Channel servers handle actual gameplay sessions, quests, and player interactions. + +| Setting | Type | Description | +|---------|------|-------------| +| `Enabled` | boolean | Enable channel servers (required for gameplay) | + +### Entrance Server + +```json +{ + "Entrance": { + "Enabled": true, + "Port": 53310, + "Entries": [ + { + "Name": "Newbie", + "Description": "", + "IP": "", + "Type": 3, + "Recommended": 2, + "AllowedClientFlags": 0, + "Channels": [ + { "Port": 54001, "MaxPlayers": 100 }, + { "Port": 54002, "MaxPlayers": 100 } + ] + } + ] + } +} +``` + +Entrance server manages world/server selection and character lists. + +| Setting | Type | Description | +|---------|------|-------------| +| `Enabled` | boolean | Enable entrance server (required) | +| `Port` | number | Entrance server port (default: 53310) | + +#### Entrance Entries + +Each entry represents a "world" in the server list. + +| Field | Type | Description | +|-------|------|-------------| +| `Name` | string | World name displayed to players | +| `Description` | string | World description (optional) | +| `IP` | string | Override IP (leave empty to use Host setting) | +| `Type` | number | World type: `1`=Normal, `2`=Cities, `3`=Newbie, `4`=Tavern, `5`=Return, `6`=MezFes | +| `Recommended` | number | Recommendation status: `0`=None, `2`=Recommended, `6`=Special | +| `AllowedClientFlags` | number | Client version flags (0 = all allowed) | +| `Channels` | array | List of channel servers in this world | + +#### Channel Configuration + +| Field | Type | Description | +|-------|------|-------------| +| `Port` | number | Channel server port (must be unique) | +| `MaxPlayers` | number | Maximum players per channel | +| `CurrentPlayers` | number | Current player count (auto-updated, can be set to 0) | + +**World Types Explained:** + +- **Newbie (Type 3)**: For new players, typically recommended +- **Normal (Type 1)**: Standard gameplay world +- **Cities (Type 2)**: Social/town areas +- **Tavern (Type 4)**: Bar/tavern areas +- **Return (Type 5)**: For returning players +- **MezFes (Type 6)**: MezFes event world + +--- + +## Complete Example + +Here's a minimal production-ready configuration: + +```json +{ + "Host": "", + "BinPath": "bin", + "Language": "en", + "DisableSoftCrash": true, + "HideLoginNotice": false, + "DevMode": false, + "DevModeOptions": { + "AutoCreateAccount": false + }, + "GameplayOptions": { + "MaximumNP": 100000, + "MaximumRP": 50000 + }, + "Logging": { + "LogToFile": true, + "LogFilePath": "logs/erupe.log", + "LogMaxSize": 100, + "LogMaxBackups": 7, + "LogMaxAge": 30, + "LogCompress": true + }, + "Discord": { + "Enabled": false + }, + "Commands": [ + {"Name": "Reload", "Enabled": true, "Prefix": "!reload"}, + {"Name": "Course", "Enabled": true, "Prefix": "!course"} + ], + "Database": { + "Host": "localhost", + "Port": 5432, + "User": "erupe", + "Password": "CHANGE_ME", + "Database": "erupe" + }, + "Sign": { + "Enabled": true, + "Port": 53312 + }, + "Channel": { + "Enabled": true + }, + "Entrance": { + "Enabled": true, + "Port": 53310, + "Entries": [ + { + "Name": "Main", + "Type": 1, + "Channels": [ + { "Port": 54001, "MaxPlayers": 100 } + ] + } + ] + } +} +``` + +--- + +## Additional Resources + +- [CLAUDE.md](../CLAUDE.md) - Development guide +- [config.example.json](../config.example.json) - Full example configuration +- [Log Analyzer Tool](../tools/loganalyzer/) - Log analysis utilities diff --git a/docs/courses.md b/docs/courses.md new file mode 100644 index 000000000..30d781b3c --- /dev/null +++ b/docs/courses.md @@ -0,0 +1,219 @@ +# Courses + +Subscription course configuration for Monster Hunter Frontier. + +## Configuration + +```json +{ + "Courses": [ + {"Name": "HunterLife", "Enabled": true}, + {"Name": "Extra", "Enabled": true}, + {"Name": "Premium", "Enabled": true}, + {"Name": "Assist", "Enabled": false}, + {"Name": "N", "Enabled": false}, + {"Name": "Hiden", "Enabled": false}, + {"Name": "HunterSupport", "Enabled": false}, + {"Name": "NBoost", "Enabled": false}, + {"Name": "NetCafe", "Enabled": true}, + {"Name": "HLRenewing", "Enabled": true}, + {"Name": "EXRenewing", "Enabled": true} + ] +} +``` + +## What Are Courses? + +Courses are subscription-based premium features in Monster Hunter Frontier, similar to premium subscriptions or season passes. Each course grants different benefits, bonuses, and access to content. + +## Course List + +| Course | Name | Description | +|--------|------|-------------| +| `HunterLife` | Hunter Life Course | Basic subscription with fundamental benefits | +| `Extra` | Extra Course | Additional premium features and bonuses | +| `Premium` | Premium Course | Premium-tier benefits and exclusive content | +| `Assist` | Assist Course | Helper features for newer players | +| `N` | N Course | Special N-series benefits | +| `Hiden` | Hiden Course | Secret/hidden features and content | +| `HunterSupport` | Hunter Support Course | Support features for hunters | +| `NBoost` | N Boost Course | N-series boost benefits | +| `NetCafe` | NetCafe Course | Internet cafe benefits (bonus rewards, boost time) | +| `HLRenewing` | Hunter Life Renewing | Renewed Hunter Life benefits | +| `EXRenewing` | Extra Renewing | Renewed Extra Course benefits | + +## How Courses Work + +### Enabled vs Disabled + +- **`Enabled: true`**: Players can toggle the course on/off using the `!course` command +- **`Enabled: false`**: Course is locked and cannot be activated by players + +### Account Rights + +Courses are stored as a bitfield in the database (`users.rights` column). Each course has a unique bit position: + +```text +Rights Bitfield: +Bit 0: HunterLife +Bit 1: Extra +Bit 2: Premium +... (and so on) +``` + +### Using the !course Command + +When the [!course command](commands.md#course) is enabled, players can toggle courses: + +```text +Player types: !course premium +Server: "Premium Course enabled!" + +Player types: !course premium +Server: "Premium Course disabled!" +``` + +**Important:** Players can only toggle courses that are `Enabled: true` in the configuration. + +## Configuration Examples + +### Open Server (All Courses Available) + +```json +{ + "Courses": [ + {"Name": "HunterLife", "Enabled": true}, + {"Name": "Extra", "Enabled": true}, + {"Name": "Premium", "Enabled": true}, + {"Name": "Assist", "Enabled": true}, + {"Name": "N", "Enabled": true}, + {"Name": "Hiden", "Enabled": true}, + {"Name": "HunterSupport", "Enabled": true}, + {"Name": "NBoost", "Enabled": true}, + {"Name": "NetCafe", "Enabled": true}, + {"Name": "HLRenewing", "Enabled": true}, + {"Name": "EXRenewing", "Enabled": true} + ] +} +``` + +### Restricted Server (Core Courses Only) + +```json +{ + "Courses": [ + {"Name": "HunterLife", "Enabled": true}, + {"Name": "Extra", "Enabled": true}, + {"Name": "Premium", "Enabled": false}, + {"Name": "Assist", "Enabled": false}, + {"Name": "N", "Enabled": false}, + {"Name": "Hiden", "Enabled": false}, + {"Name": "HunterSupport", "Enabled": false}, + {"Name": "NBoost", "Enabled": false}, + {"Name": "NetCafe", "Enabled": true}, + {"Name": "HLRenewing", "Enabled": false}, + {"Name": "EXRenewing", "Enabled": false} + ] +} +``` + +### Free-to-Play Server (NetCafe Only) + +```json +{ + "Courses": [ + {"Name": "HunterLife", "Enabled": false}, + {"Name": "Extra", "Enabled": false}, + {"Name": "Premium", "Enabled": false}, + {"Name": "Assist", "Enabled": false}, + {"Name": "N", "Enabled": false}, + {"Name": "Hiden", "Enabled": false}, + {"Name": "HunterSupport", "Enabled": false}, + {"Name": "NBoost", "Enabled": false}, + {"Name": "NetCafe", "Enabled": true}, + {"Name": "HLRenewing", "Enabled": false}, + {"Name": "EXRenewing", "Enabled": false} + ] +} +``` + +## Course Benefits + +While Erupe emulates the course system, the exact benefits depend on game client implementation. Common benefits include: + +### HunterLife + +- Increased reward multipliers +- Extra item box space +- Access to HunterLife-exclusive quests + +### Extra + +- Additional bonus rewards +- Extra carve/gather attempts +- Special decorations and items + +### Premium + +- All HunterLife + Extra benefits +- Premium-exclusive content +- Enhanced reward rates + +### NetCafe + +- Boost time periods (see [Gameplay Options](gameplay-options.md)) +- Increased reward rates +- NetCafe-exclusive bonuses + +## Setting Courses Manually + +### Via Database + +Directly modify the `users.rights` column: + +```sql +-- Enable all courses for a user +UPDATE users SET rights = 2047 WHERE username = 'player'; + +-- Enable only HunterLife (bit 0 = 2^0 = 1) +UPDATE users SET rights = 1 WHERE username = 'player'; + +-- Enable HunterLife + Extra + NetCafe (bits 0, 1, 8 = 1 + 2 + 256 = 259) +UPDATE users SET rights = 259 WHERE username = 'player'; +``` + +### Via !rights Command + +If the [!rights command](commands.md#rights) is enabled: + +```text +!rights 2047 +``` + +Enables all courses (2047 = all 11 bits set). + +**Bitfield Calculator:** + +- HunterLife: 2^0 = 1 +- Extra: 2^1 = 2 +- Premium: 2^2 = 4 +- NetCafe: 2^8 = 256 +- Total: Add the values together + +## Implementation Details + +Course checking is implemented throughout the codebase: + +```go +// Check if player has a specific course +if mhfcourse.CourseExists(courseID, session.courses) { + // Grant course benefits +} +``` + +Course data is loaded from the database on character login and cached in the session. + +## Related Documentation + +- [In-Game Commands](commands.md) - Using `!course` command +- [Gameplay Options](gameplay-options.md) - NetCafe boost time configuration diff --git a/docs/database.md b/docs/database.md new file mode 100644 index 000000000..73ee0682c --- /dev/null +++ b/docs/database.md @@ -0,0 +1,409 @@ +# Database Configuration + +PostgreSQL database configuration and setup for Erupe. + +## Configuration + +```json +{ + "Database": { + "Host": "localhost", + "Port": 5432, + "User": "postgres", + "Password": "", + "Database": "erupe" + } +} +``` + +## Settings Reference + +| Setting | Type | Default | Description | +|---------|------|---------|-------------| +| `Host` | string | `"localhost"` | Database host address | +| `Port` | number | `5432` | PostgreSQL port | +| `User` | string | `"postgres"` | Database user | +| `Password` | string | *required* | Database password (must not be empty) | +| `Database` | string | `"erupe"` | Database name | + +**Important:** The `Password` field must not be empty. The server will refuse to start if the password is blank. + +## Initial Setup + +### 1. Install PostgreSQL + +**Ubuntu/Debian:** + +```bash +sudo apt update +sudo apt install postgresql postgresql-contrib +``` + +**macOS (Homebrew):** + +```bash +brew install postgresql +brew services start postgresql +``` + +**Windows:** +Download and install from [postgresql.org](https://www.postgresql.org/download/windows/) + +### 2. Create Database User + +```bash +# Switch to postgres user +sudo -u postgres psql + +# Create user with password +CREATE USER erupe WITH PASSWORD 'your_secure_password'; + +# Grant privileges +ALTER USER erupe CREATEDB; + +# Exit psql +\q +``` + +### 3. Create Database + +```bash +# Create database +createdb -U erupe erupe + +# Or via psql +psql -U postgres +CREATE DATABASE erupe OWNER erupe; +\q +``` + +### 4. Apply Schema + +From the Erupe root directory: + +```bash +# Apply initial schema (bootstraps to version 9.1.0) +psql -U erupe -d erupe -f schemas/schema.sql +``` + +### 5. Apply Patches (Development Branch) + +If using the development branch, apply patch schemas in order: + +```bash +# Apply patches sequentially +psql -U erupe -d erupe -f patch-schema/01_patch.sql +psql -U erupe -d erupe -f patch-schema/02_patch.sql +# ... continue in order +``` + +**Note:** Patch schemas are development updates and may change. They get consolidated into update schemas on release. + +### 6. (Optional) Load Bundled Data + +Load demo data for shops, events, and gacha: + +```bash +psql -U erupe -d erupe -f schemas/bundled-schema/shops.sql +psql -U erupe -d erupe -f schemas/bundled-schema/events.sql +psql -U erupe -d erupe -f schemas/bundled-schema/gacha.sql +``` + +## Schema Management + +Erupe uses a multi-tiered schema system: + +### Schema Types + +1. **Initialization Schema** (`schemas/schema.sql`) + - Bootstraps database to version 9.1.0 + - Creates all tables, indexes, and base data + - Use for fresh installations + +2. **Patch Schemas** (`patch-schema/*.sql`) + - Development-time updates + - Numbered sequentially (01, 02, 03...) + - Applied in order during active development + - **May change during development cycle** + +3. **Update Schemas** (for releases) + - Production-ready consolidated updates + - Stable and tested + - Created when patches are finalized for release + +4. **Bundled Schemas** (`schemas/bundled-schema/*.sql`) + - Optional demo/template data + - Shops, events, gacha pools + - Not required but helpful for testing + +### Applying Schemas + +**Fresh Installation:** + +```bash +psql -U erupe -d erupe -f schemas/schema.sql +``` + +**Development (with patches):** + +```bash +# First apply base schema +psql -U erupe -d erupe -f schemas/schema.sql + +# Then apply patches in order +for patch in patch-schema/*.sql; do + psql -U erupe -d erupe -f "$patch" +done +``` + +**With Password:** + +```bash +PGPASSWORD='your_password' psql -U erupe -d erupe -f schema.sql +``` + +## Configuration Examples + +### Local Development + +```json +{ + "Database": { + "Host": "localhost", + "Port": 5432, + "User": "postgres", + "Password": "dev_password", + "Database": "erupe_dev" + } +} +``` + +### Production (Dedicated Database Server) + +```json +{ + "Database": { + "Host": "db.example.com", + "Port": 5432, + "User": "erupe", + "Password": "very_secure_password_here", + "Database": "erupe_production" + } +} +``` + +### Docker Container + +```json +{ + "Database": { + "Host": "db", + "Port": 5432, + "User": "postgres", + "Password": "docker_password", + "Database": "erupe" + } +} +``` + +The `Host: "db"` refers to the Docker Compose service name. + +## Docker Setup + +Using Docker Compose (see `docker-compose.yml`): + +```yaml +services: + db: + image: postgres:13 + environment: + POSTGRES_PASSWORD: test + POSTGRES_DB: erupe + ports: + - "5432:5432" + volumes: + - pgdata:/var/lib/postgresql/data +``` + +Start database: + +```bash +docker compose up db +``` + +Apply schema to Docker database: + +```bash +docker compose exec db psql -U postgres -d erupe -f /path/to/schema.sql +``` + +## Database Maintenance + +### Backup Database + +```bash +# Full backup +pg_dump -U erupe erupe > erupe_backup.sql + +# Compressed backup +pg_dump -U erupe erupe | gzip > erupe_backup.sql.gz + +# With password +PGPASSWORD='password' pg_dump -U erupe erupe > backup.sql +``` + +### Restore Database + +```bash +# Drop and recreate database +dropdb -U erupe erupe +createdb -U erupe erupe + +# Restore from backup +psql -U erupe -d erupe -f erupe_backup.sql + +# From compressed backup +gunzip -c erupe_backup.sql.gz | psql -U erupe -d erupe +``` + +### Clean Database (Development) + +```bash +# Connect to database +psql -U erupe -d erupe + +-- Delete all user data +DELETE FROM guild_characters; +DELETE FROM guilds; +DELETE FROM characters; +DELETE FROM sign_sessions; +DELETE FROM users; + +-- Exit +\q +``` + +Or use `CleanDB: true` in [Development Mode](development-mode.md) (⚠️ destructive!). + +### Check Database Size + +```bash +psql -U erupe -d erupe -c "SELECT pg_size_pretty(pg_database_size('erupe'));" +``` + +### Vacuum Database + +Reclaim space and optimize: + +```bash +psql -U erupe -d erupe -c "VACUUM ANALYZE;" +``` + +## Troubleshooting + +### Connection Refused + +**Error:** `could not connect to server: Connection refused` + +**Solutions:** + +- Verify PostgreSQL is running: `sudo systemctl status postgresql` +- Check port is correct: `5432` (default) +- Verify host is accessible +- Check firewall rules + +### Authentication Failed + +**Error:** `password authentication failed for user "erupe"` + +**Solutions:** + +- Verify password is correct in config +- Check `pg_hba.conf` authentication method +- Ensure user exists: `psql -U postgres -c "\du"` + +### Database Does Not Exist + +**Error:** `database "erupe" does not exist` + +**Solutions:** + +- Create database: `createdb -U erupe erupe` +- Verify database name matches config + +### Permission Denied + +**Error:** `permission denied for table users` + +**Solutions:** + +```sql +-- Grant all privileges on database +GRANT ALL PRIVILEGES ON DATABASE erupe TO erupe; + +-- Grant all privileges on all tables +GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO erupe; +``` + +### Schema Version Mismatch + +**Error:** Server starts but data doesn't load properly + +**Solutions:** + +- Check if all patches were applied in order +- Verify schema version in database +- Re-apply missing patches + +## Security Best Practices + +1. **Use Strong Passwords**: Never use default or weak passwords +2. **Limit Network Access**: Use firewall rules to restrict database access +3. **Don't Expose PostgreSQL Publicly**: Only allow connections from Erupe server +4. **Use SSL/TLS**: Enable SSL for production databases +5. **Regular Backups**: Automate daily backups +6. **Separate Users**: Don't use `postgres` superuser for Erupe + +## Performance Tuning + +For larger servers, optimize PostgreSQL: + +### Connection Pooling + +Consider using PgBouncer for connection pooling: + +```bash +sudo apt install pgbouncer +``` + +### PostgreSQL Configuration + +Edit `/etc/postgresql/13/main/postgresql.conf`: + +```conf +# Increase shared buffers (25% of RAM) +shared_buffers = 2GB + +# Increase work memory +work_mem = 16MB + +# Increase maintenance work memory +maintenance_work_mem = 512MB + +# Enable query logging (development) +log_statement = 'all' +log_duration = on +``` + +Restart PostgreSQL: + +```bash +sudo systemctl restart postgresql +``` + +## Related Documentation + +- [Basic Settings](basic-settings.md) - Basic server configuration +- [Development Mode](development-mode.md) - CleanDB option +- [Server Configuration](server-configuration.md) - Server setup +- [CLAUDE.md](../CLAUDE.md#database-operations) - Database operations guide diff --git a/docs/development-mode.md b/docs/development-mode.md new file mode 100644 index 000000000..ea0469787 --- /dev/null +++ b/docs/development-mode.md @@ -0,0 +1,166 @@ +# Development Mode + +Development mode configuration for testing and debugging Erupe. + +## Configuration + +```json +{ + "DevMode": true, + "DevModeOptions": { + "AutoCreateAccount": true, + "CleanDB": false, + "MaxLauncherHR": false, + "LogInboundMessages": false, + "LogOutboundMessages": false, + "MaxHexdumpLength": 256, + "DivaEvent": 0, + "FestaEvent": -1, + "TournamentEvent": 0, + "MezFesEvent": true, + "MezFesAlt": false, + "DisableTokenCheck": false, + "QuestDebugTools": false, + "SaveDumps": { + "Enabled": true, + "OutputDir": "savedata" + } + } +} +``` + +## Settings Reference + +### DevMode + +| Setting | Type | Default | Description | +|---------|------|---------|-------------| +| `DevMode` | boolean | `false` | Enables development mode (more verbose logging, development logger format) | + +When `DevMode` is enabled: + +- Logging uses console format (human-readable) instead of JSON +- More detailed stack traces on errors +- Development-friendly output + +### DevModeOptions + +| Setting | Type | Default | Description | +|---------|------|---------|-------------| +| `AutoCreateAccount` | boolean | `false` | **⚠️ SECURITY RISK**: Auto-create accounts on login (disable in production) | +| `CleanDB` | boolean | `false` | **⚠️ DESTRUCTIVE**: Wipes database on server start (deletes all users, characters, guilds) | +| `MaxLauncherHR` | boolean | `false` | Sets launcher HR to HR7 to join non-beginner worlds | +| `LogInboundMessages` | boolean | `false` | Log all packets received from clients (very verbose) | +| `LogOutboundMessages` | boolean | `false` | Log all packets sent to clients (very verbose) | +| `MaxHexdumpLength` | number | `256` | Maximum bytes to display in packet hexdumps | +| `DivaEvent` | number | `0` | Diva Defense event status (0 = off, higher = active) | +| `FestaEvent` | number | `-1` | Hunter's Festa event status (-1 = off, higher = active) | +| `TournamentEvent` | number | `0` | VS Tournament event status (0 = off, higher = active) | +| `MezFesEvent` | boolean | `false` | Enable/disable MezFes event | +| `MezFesAlt` | boolean | `false` | Swap Volpakkun for Tokotoko in MezFes | +| `DisableTokenCheck` | boolean | `false` | **⚠️ SECURITY RISK**: Skip login token validation | +| `QuestDebugTools` | boolean | `false` | Enable quest debugging logs | + +### Save Dumps + +| Setting | Type | Default | Description | +|---------|------|---------|-------------| +| `SaveDumps.Enabled` | boolean | `false` | Enable saving character data dumps for analysis | +| `SaveDumps.OutputDir` | string | `"savedata"` | Directory for save data dumps | + +## Security Warnings + +### AutoCreateAccount + +**Never enable in production!** This setting allows anyone to create an account by simply trying to log in with any username. This is convenient for development but a major security risk for public servers. + +### CleanDB + +**Extremely destructive!** This setting wipes all user data from the database on every server restart. Only use for rapid testing cycles in isolated development environments. + +### DisableTokenCheck + +**Security vulnerability!** Bypasses login token validation, allowing unauthorized access. Only use in isolated development environments. + +## Packet Logging + +When debugging network issues, enable packet logging: + +```json +{ + "DevModeOptions": { + "LogInboundMessages": true, + "LogOutboundMessages": true, + "MaxHexdumpLength": 512 + } +} +``` + +**Warning:** This generates **massive** log files very quickly. Only enable when actively debugging specific packet issues. + +## Event Testing + +Test special events by enabling them: + +```json +{ + "DevModeOptions": { + "DivaEvent": 1, + "FestaEvent": 0, + "TournamentEvent": 1, + "MezFesEvent": true, + "MezFesAlt": false + } +} +``` + +## Examples + +### Safe Development Configuration + +```json +{ + "DevMode": true, + "DevModeOptions": { + "AutoCreateAccount": true, + "CleanDB": false, + "MaxLauncherHR": true, + "QuestDebugTools": true, + "SaveDumps": { + "Enabled": true, + "OutputDir": "savedata" + } + } +} +``` + +### Production Configuration + +```json +{ + "DevMode": false, + "DevModeOptions": { + "AutoCreateAccount": false, + "CleanDB": false, + "DisableTokenCheck": false + } +} +``` + +### Packet Debugging Configuration + +```json +{ + "DevMode": true, + "DevModeOptions": { + "LogInboundMessages": true, + "LogOutboundMessages": true, + "MaxHexdumpLength": 1024 + } +} +``` + +## Related Documentation + +- [Logging](logging.md) - Logging configuration +- [Basic Settings](basic-settings.md) - Basic server settings diff --git a/docs/discord-integration.md b/docs/discord-integration.md new file mode 100644 index 000000000..d26d80807 --- /dev/null +++ b/docs/discord-integration.md @@ -0,0 +1,199 @@ +# Discord Integration + +Real-time Discord bot integration for posting server activity to Discord channels. + +## Configuration + +```json +{ + "Discord": { + "Enabled": false, + "BotToken": "", + "RealtimeChannelID": "" + } +} +``` + +## Settings Reference + +| Setting | Type | Description | +|---------|------|-------------| +| `Enabled` | boolean | Enable Discord integration | +| `BotToken` | string | Discord bot token from Discord Developer Portal | +| `RealtimeChannelID` | string | Discord channel ID where activity messages will be posted | + +## How It Works + +When enabled, the Discord bot: + +1. **Connects on Server Startup**: The bot authenticates using the provided bot token +2. **Monitors Game Activity**: Listens for in-game chat messages and events +3. **Posts to Discord**: Sends formatted messages to the specified channel + +### What Gets Posted + +- Player chat messages (when sent to world/server chat) +- Player connection/disconnection events +- Quest completions +- Special event notifications + +### Message Format + +Messages are posted in this format: + +```text +**PlayerName**: Hello everyone! +``` + +Discord mentions and emojis in messages are normalized for proper display. + +## Setup Instructions + +### 1. Create a Discord Bot + +1. Go to [Discord Developer Portal](https://discord.com/developers/applications) +2. Click "New Application" +3. Give your application a name (e.g., "Erupe Server Bot") +4. Go to the "Bot" section in the left sidebar +5. Click "Add Bot" +6. Under the bot's username, click "Reset Token" to reveal your bot token +7. **Copy this token** - you'll need it for the config + +**Important:** Keep your bot token secret! Anyone with this token can control your bot. + +### 2. Get Channel ID + +1. Enable Developer Mode in Discord: + - User Settings → Advanced → Developer Mode (toggle on) +2. Right-click the channel where you want bot messages +3. Click "Copy ID" +4. This is your `RealtimeChannelID` + +### 3. Add Bot to Your Server + +1. In Discord Developer Portal, go to OAuth2 → URL Generator +2. Select scopes: + - `bot` +3. Select bot permissions: + - `Send Messages` + - `Read Message History` +4. Copy the generated URL at the bottom +5. Paste the URL in your browser and select your Discord server +6. Click "Authorize" + +### 4. Configure Erupe + +Edit your `config.json`: + +```json +{ + "Discord": { + "Enabled": true, + "BotToken": "YOUR_BOT_TOKEN_HERE", + "RealtimeChannelID": "YOUR_CHANNEL_ID_HERE" + } +} +``` + +### 5. Start Erupe + +The bot will connect automatically on server startup. You should see: + +```text +INFO Discord bot connected successfully +``` + +## Example Configuration + +```json +{ + "Discord": { + "Enabled": true, + "BotToken": "MTIzNDU2Nzg5MDEyMzQ1Njc4OQ.AbCdEf.GhIjKlMnOpQrStUvWxYz123456789", + "RealtimeChannelID": "987654321098765432" + } +} +``` + +## Implementation Details + +- **Bot Code**: [server/discordbot/discord_bot.go](../server/discordbot/discord_bot.go) +- **Library**: Uses [discordgo](https://github.com/bwmarrin/discordgo) +- **Message Normalization**: Discord mentions (`<@123456>`) and emojis (`:emoji:`) are normalized +- **Error Handling**: Non-blocking - errors are logged but don't crash the server +- **Threading**: Bot runs in a separate goroutine + +## Troubleshooting + +### Bot doesn't connect + +**Error:** `Discord failed to create realtimeChannel` + +**Solutions:** + +- Verify the `RealtimeChannelID` is correct +- Ensure the bot has been added to your server +- Check that the bot has permission to read the channel + +### Bot connects but doesn't post messages + +**Solutions:** + +- Verify the bot has `Send Messages` permission in the channel +- Check channel permissions - the bot's role must have access +- Look for error messages in server logs + +### Invalid token error + +**Error:** `Discord failed: authentication failed` + +**Solutions:** + +- Regenerate the bot token in Discord Developer Portal +- Copy the entire token, including any special characters +- Ensure no extra spaces in the config file + +### Bot posts but messages are blank + +**Issue:** Message normalization may be failing + +**Solution:** + +- Check server logs for Discord-related errors +- Verify game chat is being sent to world/server chat, not private chat + +## Security Considerations + +1. **Never commit your bot token** - Add `config.json` to `.gitignore` +2. **Regenerate compromised tokens** - If your token is exposed, regenerate immediately +3. **Limit bot permissions** - Only grant necessary permissions +4. **Monitor bot activity** - Check for unusual posting patterns + +## Advanced Usage + +### Multiple Channels + +Currently, Erupe supports posting to a single channel. To post to multiple channels, you would need to modify the bot code. + +### Custom Message Formatting + +To customize message formatting, edit [sys_channel_server.go:354](../server/channelserver/sys_channel_server.go#L354): + +```go +func (s *Server) DiscordChannelSend(charName string, content string) { + if s.erupeConfig.Discord.Enabled && s.discordBot != nil { + // Customize this format + message := fmt.Sprintf("**%s**: %s", charName, content) + s.discordBot.RealtimeChannelSend(message) + } +} +``` + +### Webhook Alternative + +For simpler one-way messaging, consider using Discord webhooks instead of a full bot. This would require code modifications but wouldn't need bot creation/permissions. + +## Related Documentation + +- [In-Game Commands](commands.md) - Chat commands that may trigger Discord posts +- [Logging](logging.md) - Server logging configuration diff --git a/docs/gameplay-options.md b/docs/gameplay-options.md new file mode 100644 index 000000000..c7bd2951c --- /dev/null +++ b/docs/gameplay-options.md @@ -0,0 +1,161 @@ +# Gameplay Options + +Gameplay modifiers and balance settings for Erupe. + +## Configuration + +```json +{ + "GameplayOptions": { + "FeaturedWeapons": 1, + "MaximumNP": 100000, + "MaximumRP": 50000, + "DisableLoginBoost": false, + "DisableBoostTime": false, + "BoostTimeDuration": 120, + "GuildMealDuration": 60, + "BonusQuestAllowance": 3, + "DailyQuestAllowance": 1 + } +} +``` + +## Settings Reference + +| Setting | Type | Default | Description | +|---------|------|---------|-------------| +| `FeaturedWeapons` | number | `1` | Number of Active Feature weapons generated daily | +| `MaximumNP` | number | `100000` | Maximum Network Points (NP) a player can hold | +| `MaximumRP` | number | `50000` | Maximum Road Points (RP) a player can hold | +| `DisableLoginBoost` | boolean | `false` | Disable login boost system entirely | +| `DisableBoostTime` | boolean | `false` | Disable daily NetCafe boost time | +| `BoostTimeDuration` | number | `120` | NetCafe boost time duration in minutes | +| `GuildMealDuration` | number | `60` | Guild meal activation duration in minutes | +| `BonusQuestAllowance` | number | `3` | Daily Bonus Point Quest allowance | +| `DailyQuestAllowance` | number | `1` | Daily Quest allowance | + +## Detailed Explanations + +### Featured Weapons + +Featured/Active Feature weapons are special weapon variants with unique properties. This setting controls how many are generated and available each day. + +- Set to `0` to disable featured weapons +- Set to `1`-`3` for normal operation +- Higher values generate more variety + +### Network Points (NP) and Road Points (RP) + +NP and RP are in-game currencies/points used for various purchases and progression: + +- **Network Points (NP)**: Used for purchasing items, materials, and services +- **Road Points (RP)**: Used for unlocking road/progression rewards + +**Default Caps:** + +- NP: `100,000` +- RP: `50,000` + +You can increase these caps for more relaxed gameplay or decrease them to maintain balance. + +### Boost Systems + +Monster Hunter Frontier has several boost systems that increase rewards and experience: + +#### Login Boost + +Automatically granted when logging in. Disable with `DisableLoginBoost: true`. + +#### NetCafe Boost Time + +Daily time-limited boost that simulates NetCafe benefits: + +```json +{ + "DisableBoostTime": false, + "BoostTimeDuration": 120 +} +``` + +- `DisableBoostTime: false` - Boost time is active +- `BoostTimeDuration: 120` - Lasts 120 minutes (2 hours) + +### Guild Meals + +Guild meals are buffs that guild members can activate: + +```json +{ + "GuildMealDuration": 60 +} +``` + +Duration in minutes after cooking before the meal expires. + +### Quest Allowances + +Daily limits for special quest types: + +- **BonusQuestAllowance**: Number of Bonus Point Quests per day +- **DailyQuestAllowance**: Number of Daily Quests per day + +Set to `0` to disable limits entirely. + +## Examples + +### Casual/Relaxed Server + +```json +{ + "GameplayOptions": { + "FeaturedWeapons": 3, + "MaximumNP": 999999, + "MaximumRP": 999999, + "DisableLoginBoost": false, + "DisableBoostTime": false, + "BoostTimeDuration": 240, + "GuildMealDuration": 120, + "BonusQuestAllowance": 10, + "DailyQuestAllowance": 5 + } +} +``` + +### Balanced Server (Default) + +```json +{ + "GameplayOptions": { + "FeaturedWeapons": 1, + "MaximumNP": 100000, + "MaximumRP": 50000, + "DisableLoginBoost": false, + "DisableBoostTime": false, + "BoostTimeDuration": 120, + "GuildMealDuration": 60, + "BonusQuestAllowance": 3, + "DailyQuestAllowance": 1 + } +} +``` + +### Hardcore/Challenge Server + +```json +{ + "GameplayOptions": { + "FeaturedWeapons": 0, + "MaximumNP": 50000, + "MaximumRP": 25000, + "DisableLoginBoost": true, + "DisableBoostTime": true, + "BonusQuestAllowance": 1, + "DailyQuestAllowance": 1 + } +} +``` + +## Related Documentation + +- [Courses](courses.md) - Subscription course configuration +- [In-Game Commands](commands.md) - Player commands diff --git a/docs/logging.md b/docs/logging.md new file mode 100644 index 000000000..7126a5a7f --- /dev/null +++ b/docs/logging.md @@ -0,0 +1,201 @@ +# Logging Configuration + +File logging and log rotation configuration for Erupe. + +## Configuration + +```json +{ + "Logging": { + "LogToFile": true, + "LogFilePath": "logs/erupe.log", + "LogMaxSize": 100, + "LogMaxBackups": 3, + "LogMaxAge": 28, + "LogCompress": true + } +} +``` + +## Settings Reference + +| Setting | Type | Default | Description | +|---------|------|---------|-------------| +| `LogToFile` | boolean | `true` | Enable file logging (logs to both console and file) | +| `LogFilePath` | string | `"logs/erupe.log"` | Path to log file (directory will be created automatically) | +| `LogMaxSize` | number | `100` | Maximum log file size in MB before rotation | +| `LogMaxBackups` | number | `3` | Number of old log files to keep | +| `LogMaxAge` | number | `28` | Maximum days to retain old logs | +| `LogCompress` | boolean | `true` | Compress rotated log files with gzip | + +## How It Works + +Erupe uses [lumberjack](https://github.com/natefinch/lumberjack) for automatic log rotation and compression. + +### Log Rotation + +When the current log file reaches `LogMaxSize` MB: + +1. Current log is closed and renamed to `erupe.log.YYYY-MM-DD-HH-MM-SS` +2. If `LogCompress: true`, the old log is compressed to `.gz` format +3. A new `erupe.log` file is created +4. Old logs beyond `LogMaxBackups` count are deleted +5. Logs older than `LogMaxAge` days are deleted + +### Example Log Files + +```text +logs/ +├── erupe.log (current, 45 MB) +├── erupe.log.2025-11-17-14-23-45.gz (100 MB compressed) +├── erupe.log.2025-11-16-08-15-32.gz (100 MB compressed) +└── erupe.log.2025-11-15-19-42-18.gz (100 MB compressed) +``` + +## Log Format + +Log format depends on `DevMode` setting: + +### Development Mode (DevMode: true) + +Console format (human-readable): + +```text +2025-11-18T10:30:45.123Z INFO channelserver Player connected {"charID": 12345, "ip": "127.0.0.1"} +2025-11-18T10:30:46.456Z ERROR channelserver Failed to load data {"error": "database timeout"} +``` + +### Production Mode (DevMode: false) + +JSON format (machine-parsable): + +```json +{"level":"info","ts":"2025-11-18T10:30:45.123Z","logger":"channelserver","msg":"Player connected","charID":12345,"ip":"127.0.0.1"} +{"level":"error","ts":"2025-11-18T10:30:46.456Z","logger":"channelserver","msg":"Failed to load data","error":"database timeout"} +``` + +## Log Analysis + +Erupe includes a built-in log analyzer tool in `tools/loganalyzer/`: + +```bash +# Filter by log level +./loganalyzer filter -f ../../logs/erupe.log -level error + +# Analyze errors with stack traces +./loganalyzer errors -f ../../logs/erupe.log -stack -detailed + +# Track player connections +./loganalyzer connections -f ../../logs/erupe.log -sessions + +# Real-time monitoring +./loganalyzer tail -f ../../logs/erupe.log -level error + +# Generate statistics +./loganalyzer stats -f ../../logs/erupe.log -detailed +``` + +See [CLAUDE.md](../CLAUDE.md#log-analysis) for more details. + +## Examples + +### Minimal Logging (Development) + +```json +{ + "Logging": { + "LogToFile": false + } +} +``` + +Only logs to console, no file logging. + +### Standard Production Logging + +```json +{ + "Logging": { + "LogToFile": true, + "LogFilePath": "logs/erupe.log", + "LogMaxSize": 100, + "LogMaxBackups": 7, + "LogMaxAge": 30, + "LogCompress": true + } +} +``` + +Keeps up to 7 log files, 30 days maximum, compressed. + +### High-Volume Server + +```json +{ + "Logging": { + "LogToFile": true, + "LogFilePath": "/var/log/erupe/erupe.log", + "LogMaxSize": 500, + "LogMaxBackups": 14, + "LogMaxAge": 60, + "LogCompress": true + } +} +``` + +Larger log files (500 MB), more backups (14), longer retention (60 days). + +### Debug/Testing (No Rotation) + +```json +{ + "Logging": { + "LogToFile": true, + "LogFilePath": "logs/debug.log", + "LogMaxSize": 1000, + "LogMaxBackups": 0, + "LogMaxAge": 0, + "LogCompress": false + } +} +``` + +Single large log file, no rotation, no compression. Useful for debugging sessions. + +## Disk Space Considerations + +Calculate approximate disk usage: + +```text +Total Disk Usage = (LogMaxSize × LogMaxBackups) × CompressionRatio +``` + +**Compression ratios:** + +- Text logs: ~10:1 (100 MB → 10 MB compressed) +- JSON logs: ~8:1 (100 MB → 12.5 MB compressed) + +**Example:** + +```text +LogMaxSize: 100 MB +LogMaxBackups: 7 +Compression: enabled (~10:1 ratio) + +Total: (100 MB × 7) / 10 = 70 MB (approximately) +``` + +## Best Practices + +1. **Enable compression** - Saves significant disk space +2. **Set reasonable MaxSize** - 100-200 MB works well for most servers +3. **Adjust retention** - Keep logs for at least 7 days, preferably 30 +4. **Use absolute paths in production** - `/var/log/erupe/erupe.log` instead of `logs/erupe.log` +5. **Monitor disk space** - Set up alerts if disk usage exceeds 80% +6. **Use JSON format in production** - Easier to parse with log analysis tools + +## Related Documentation + +- [Development Mode](development-mode.md) - DevMode affects log format +- [Basic Settings](basic-settings.md) - Basic server configuration +- [CLAUDE.md](../CLAUDE.md#log-analysis) - Log analyzer tool usage diff --git a/docs/server-configuration.md b/docs/server-configuration.md new file mode 100644 index 000000000..d18bf124f --- /dev/null +++ b/docs/server-configuration.md @@ -0,0 +1,445 @@ +# Server Configuration + +Configuration for Erupe's three-server architecture: Sign, Entrance, and Channel servers. + +## Three-Server Architecture + +Erupe uses a multi-server architecture that mirrors the original Monster Hunter Frontier server design: + +``` +Client → Sign Server (Auth) → Entrance Server (World List) → Channel Server (Gameplay) +``` + +1. **Sign Server**: Authentication and account management +2. **Entrance Server**: World/server selection and character list +3. **Channel Servers**: Actual gameplay sessions, quests, and player interactions + +## Sign Server + +Handles authentication and account management. + +### Configuration + +```json +{ + "Sign": { + "Enabled": true, + "Port": 53312 + } +} +``` + +| Setting | Type | Default | Description | +|---------|------|---------|-------------| +| `Enabled` | boolean | `true` | Enable the legacy sign server | +| `Port` | number | `53312` | Port for sign server (client default: 53312) | + +### Details + +- Located in [server/signserver/](../server/signserver/) +- Creates sign sessions with tokens for channel server authentication +- Legacy TCP-based protocol +- Required unless using SignV2 + +## SignV2 Server + +Modern HTTP-based sign server (alternative to legacy sign server). + +### Configuration + +```json +{ + "SignV2": { + "Enabled": false, + "Port": 8080 + } +} +``` + +| Setting | Type | Default | Description | +|---------|------|---------|-------------| +| `Enabled` | boolean | `false` | Enable the modern HTTP-based sign server | +| `Port` | number | `8080` | Port for SignV2 server | + +### Details + +- Located in [server/signv2server/](../server/signv2server/) +- HTTP-based authentication (easier to proxy/load balance) +- Alternative to legacy sign server +- **Only enable one sign server at a time** (Sign OR SignV2, not both) + +## Channel Server + +Handles actual gameplay sessions, quests, and player interactions. + +### Configuration + +```json +{ + "Channel": { + "Enabled": true + } +} +``` + +| Setting | Type | Default | Description | +|---------|------|---------|-------------| +| `Enabled` | boolean | `true` | Enable channel servers (required for gameplay) | + +### Details + +- Located in [server/channelserver/](../server/channelserver/) +- Most complex component - handles all gameplay logic +- Multiple instances can run simultaneously +- Ports configured in Entrance server entries +- Features: + - Session management + - Packet handling + - Stage/room system + - Quest system + - Guild operations + - Special events (Raviente, Diva Defense, etc.) + +See [CLAUDE.md](../CLAUDE.md#channel-server-internal-architecture) for detailed architecture. + +## Entrance Server + +Manages world/server selection and character lists. + +### Configuration + +```json +{ + "Entrance": { + "Enabled": true, + "Port": 53310, + "Entries": [ + { + "Name": "Newbie", + "Description": "", + "IP": "", + "Type": 3, + "Recommended": 2, + "AllowedClientFlags": 0, + "Channels": [ + { "Port": 54001, "MaxPlayers": 100 }, + { "Port": 54002, "MaxPlayers": 100 } + ] + } + ] + } +} +``` + +### Settings Reference + +| Setting | Type | Description | +|---------|------|-------------| +| `Enabled` | boolean | Enable entrance server (required for server list) | +| `Port` | number | Entrance server port (default: 53310) | +| `Entries` | array | List of worlds/servers shown to players | + +### Entrance Entries + +Each entry represents a "world" in the server list. + +| Field | Type | Description | +|-------|------|-------------| +| `Name` | string | World name displayed to players (e.g., "Newbie", "Normal") | +| `Description` | string | World description (optional, usually empty) | +| `IP` | string | Override IP address (leave empty to use global `Host` setting) | +| `Type` | number | World type (see below) | +| `Recommended` | number | Recommendation badge: `0`=None, `2`=Recommended, `6`=Special | +| `AllowedClientFlags` | number | Client version flags (0 = all versions allowed) | +| `Channels` | array | List of channel servers in this world | + +### World Types + +| Type | Name | Purpose | +|------|------|---------| +| `1` | Normal | Standard gameplay world | +| `2` | Cities | Social/town areas | +| `3` | Newbie | For new players (typically recommended) | +| `4` | Tavern | Bar/tavern areas | +| `5` | Return | For returning players | +| `6` | MezFes | MezFes event world | + +### Channel Configuration + +Each world has multiple channels (like "servers" within a "world"): + +```json +{ + "Channels": [ + { "Port": 54001, "MaxPlayers": 100 }, + { "Port": 54002, "MaxPlayers": 100 } + ] +} +``` + +| Field | Type | Description | +|-------|------|-------------| +| `Port` | number | Channel server port (must be unique across all channels) | +| `MaxPlayers` | number | Maximum players allowed in this channel | +| `CurrentPlayers` | number | Current player count (auto-updated at runtime) | + +## Complete Server Configurations + +### Minimal Setup (Single World, Single Channel) + +```json +{ + "Sign": { + "Enabled": true, + "Port": 53312 + }, + "SignV2": { + "Enabled": false + }, + "Channel": { + "Enabled": true + }, + "Entrance": { + "Enabled": true, + "Port": 53310, + "Entries": [ + { + "Name": "Main", + "Type": 1, + "Recommended": 0, + "AllowedClientFlags": 0, + "Channels": [ + { "Port": 54001, "MaxPlayers": 100 } + ] + } + ] + } +} +``` + +### Standard Setup (Multiple Worlds) + +```json +{ + "Sign": { + "Enabled": true, + "Port": 53312 + }, + "Channel": { + "Enabled": true + }, + "Entrance": { + "Enabled": true, + "Port": 53310, + "Entries": [ + { + "Name": "Newbie", + "Description": "", + "IP": "", + "Type": 3, + "Recommended": 2, + "AllowedClientFlags": 0, + "Channels": [ + { "Port": 54001, "MaxPlayers": 100 }, + { "Port": 54002, "MaxPlayers": 100 } + ] + }, + { + "Name": "Normal", + "Description": "", + "IP": "", + "Type": 1, + "Recommended": 0, + "AllowedClientFlags": 0, + "Channels": [ + { "Port": 54003, "MaxPlayers": 100 }, + { "Port": 54004, "MaxPlayers": 100 } + ] + }, + { + "Name": "Cities", + "Description": "", + "IP": "", + "Type": 2, + "Recommended": 0, + "AllowedClientFlags": 0, + "Channels": [ + { "Port": 54005, "MaxPlayers": 100 } + ] + } + ] + } +} +``` + +### Large-Scale Setup + +```json +{ + "Sign": { + "Enabled": true, + "Port": 53312 + }, + "Channel": { + "Enabled": true + }, + "Entrance": { + "Enabled": true, + "Port": 53310, + "Entries": [ + { + "Name": "Newbie", + "Type": 3, + "Recommended": 2, + "AllowedClientFlags": 0, + "Channels": [ + { "Port": 54001, "MaxPlayers": 150 }, + { "Port": 54002, "MaxPlayers": 150 }, + { "Port": 54003, "MaxPlayers": 150 } + ] + }, + { + "Name": "Normal", + "Type": 1, + "Recommended": 0, + "AllowedClientFlags": 0, + "Channels": [ + { "Port": 54004, "MaxPlayers": 200 }, + { "Port": 54005, "MaxPlayers": 200 }, + { "Port": 54006, "MaxPlayers": 200 }, + { "Port": 54007, "MaxPlayers": 200 } + ] + }, + { + "Name": "Cities", + "Type": 2, + "Recommended": 0, + "AllowedClientFlags": 0, + "Channels": [ + { "Port": 54008, "MaxPlayers": 100 }, + { "Port": 54009, "MaxPlayers": 100 } + ] + }, + { + "Name": "MezFes", + "Type": 6, + "Recommended": 6, + "AllowedClientFlags": 0, + "Channels": [ + { "Port": 54010, "MaxPlayers": 100 } + ] + } + ] + } +} +``` + +## Port Allocation + +Default port assignments: + +| Server | Port | Configurable | +|--------|------|--------------| +| Sign | 53312 | Yes | +| SignV2 | 8080 | Yes | +| Entrance | 53310 | Yes | +| Channels | 54001+ | Yes (per-channel) | + +**Important:** + +- All ports must be unique +- Firewall must allow inbound connections on these ports +- Client expects Sign on 53312 and Entrance on 53310 by default + +## Firewall Configuration + +### Linux (ufw) + +```bash +# Allow sign server +sudo ufw allow 53312/tcp + +# Allow entrance server +sudo ufw allow 53310/tcp + +# Allow channel servers (range) +sudo ufw allow 54001:54010/tcp +``` + +### Linux (iptables) + +```bash +# Sign server +sudo iptables -A INPUT -p tcp --dport 53312 -j ACCEPT + +# Entrance server +sudo iptables -A INPUT -p tcp --dport 53310 -j ACCEPT + +# Channel servers (range) +sudo iptables -A INPUT -p tcp --dport 54001:54010 -j ACCEPT +``` + +### Windows Firewall + +```powershell +# Allow specific ports +New-NetFirewallRule -DisplayName "Erupe Sign" -Direction Inbound -Protocol TCP -LocalPort 53312 -Action Allow +New-NetFirewallRule -DisplayName "Erupe Entrance" -Direction Inbound -Protocol TCP -LocalPort 53310 -Action Allow +New-NetFirewallRule -DisplayName "Erupe Channels" -Direction Inbound -Protocol TCP -LocalPort 54001-54010 -Action Allow +``` + +## Load Balancing + +For high-traffic servers, consider: + +1. **Multiple Entrance Servers**: Run multiple entrance server instances behind a load balancer +2. **Distributed Channels**: Spread channel servers across multiple physical servers +3. **Database Connection Pooling**: Use PgBouncer for database connections +4. **SignV2 with Reverse Proxy**: Use nginx/HAProxy with SignV2 for better scaling + +## Monitoring + +Monitor server health: + +```bash +# Check if servers are listening +netstat -tlnp | grep erupe + +# Check open ports +ss -tlnp | grep -E '(53312|53310|54001)' + +# Monitor connections per channel +watch -n 1 'netstat -an | grep ESTABLISHED | grep 54001 | wc -l' +``` + +## Troubleshooting + +### Can't Connect to Sign Server + +- Verify Sign server is enabled +- Check port 53312 is open +- Verify client is configured for correct IP/port + +### World List Empty + +- Verify Entrance server is enabled +- Check Entrance server port (53310) +- Ensure at least one Entry is configured + +### Can't Enter World + +- Verify Channel server is enabled +- Check channel ports are open +- Verify channel ports in Entrance entries match actual running servers + +### Server Crashes on Startup + +- Check all ports are unique +- Verify database connection (password not empty) +- Check logs for specific errors + +## Related Documentation + +- [Database](database.md) - Database configuration +- [Basic Settings](basic-settings.md) - Host and network settings +- [CLAUDE.md](../CLAUDE.md#architecture) - Detailed architecture overview