mirror of
https://github.com/Mezeporta/Erupe.git
synced 2026-03-26 09:33:02 +01:00
docs: adds documentation files for the major configurable options.
This commit is contained in:
356
CLAUDE.md
Normal file
356
CLAUDE.md
Normal file
@@ -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.
|
||||||
249
docs/README.md
Normal file
249
docs/README.md
Normal file
@@ -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.
|
||||||
89
docs/basic-settings.md
Normal file
89
docs/basic-settings.md
Normal file
@@ -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": [
|
||||||
|
"<BODY><CENTER><SIZE_3><C_4>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
|
||||||
|
<BODY><CENTER><SIZE_3><C_4>Large Centered Red Text<BR>
|
||||||
|
<BODY><LEFT><SIZE_2><C_5>Normal Left-Aligned Yellow Text<BR>
|
||||||
|
<BODY><C_7>White Text
|
||||||
|
```
|
||||||
|
|
||||||
|
**Common MHFML Tags:**
|
||||||
|
|
||||||
|
- `<BODY>` - Start new line
|
||||||
|
- `<BR>` - Line break
|
||||||
|
- `<CENTER>`, `<LEFT>`, `<RIGHT>` - Text alignment
|
||||||
|
- `<SIZE_2>`, `<SIZE_3>` - Text size
|
||||||
|
- `<C_4>` (Red), `<C_5>` (Yellow), `<C_7>` (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": [
|
||||||
|
"<BODY><CENTER><SIZE_3><C_4>Welcome to Our Server!<BR><BODY><LEFT><SIZE_2><C_5>Join our Discord: discord.gg/example"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Related Documentation
|
||||||
|
|
||||||
|
- [Server Configuration](server-configuration.md) - Server types and ports
|
||||||
|
- [Configuration Overview](README.md) - All configuration options
|
||||||
335
docs/commands.md
Normal file
335
docs/commands.md
Normal file
@@ -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 <subcommand>`
|
||||||
|
|
||||||
|
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 <course_name>`
|
||||||
|
|
||||||
|
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 <hex>`
|
||||||
|
|
||||||
|
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 <number>`
|
||||||
|
|
||||||
|
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 <number>"
|
||||||
|
```
|
||||||
|
|
||||||
|
**⚠️ 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 <location>`
|
||||||
|
|
||||||
|
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
|
||||||
610
docs/configuration.md
Normal file
610
docs/configuration.md
Normal file
@@ -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 <number>` |
|
||||||
|
| **Raviente** | `!ravi` | Control Raviente event | `!ravi start`, `!ravi cm` (check multiplier) |
|
||||||
|
| **Teleport** | `!tele` | Teleport to locations | `!tele <location>` |
|
||||||
|
| **Reload** | `!reload` | Reload all players and objects in current stage | `!reload` |
|
||||||
|
| **KeyQuest** | `!kqf` | Get/set Key Quest flags | `!kqf get`, `!kqf set <hex>` |
|
||||||
|
| **Course** | `!course` | Enable/disable subscription courses | `!course <course_name>` |
|
||||||
|
|
||||||
|
### 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
|
||||||
219
docs/courses.md
Normal file
219
docs/courses.md
Normal file
@@ -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
|
||||||
409
docs/database.md
Normal file
409
docs/database.md
Normal file
@@ -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
|
||||||
166
docs/development-mode.md
Normal file
166
docs/development-mode.md
Normal file
@@ -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
|
||||||
199
docs/discord-integration.md
Normal file
199
docs/discord-integration.md
Normal file
@@ -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
|
||||||
161
docs/gameplay-options.md
Normal file
161
docs/gameplay-options.md
Normal file
@@ -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
|
||||||
201
docs/logging.md
Normal file
201
docs/logging.md
Normal file
@@ -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
|
||||||
445
docs/server-configuration.md
Normal file
445
docs/server-configuration.md
Normal file
@@ -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
|
||||||
Reference in New Issue
Block a user