eq2go/internal/zone/README.md

372 lines
12 KiB
Markdown

# EverQuest II Zone System
This package implements a comprehensive zone management system for the EverQuest II server emulator, converted from the original C++ implementation while leveraging Go's concurrency and type safety features.
## Overview
The zone system handles:
- **Zone Management**: Loading, initialization, and lifecycle management of game zones
- **Instance Management**: Creating and managing instanced zones for groups, raids, and solo play
- **Spawn Management**: NPCs, objects, widgets, signs, and ground spawns with spatial optimization
- **Movement System**: NPC movement with pathfinding, stuck detection, and multiple movement modes
- **Position System**: 3D position calculations, distance functions, and EQ2-specific heading math
- **Weather System**: Dynamic weather with patterns, severity controls, and client synchronization
- **Database Integration**: Persistent storage of zone configuration, spawns, and player data
- **Client Management**: Player connections, spawn visibility, and packet communication
- **Grid System**: Spatial partitioning for efficient range queries and spawn management
## Architecture
### Core Components
#### ZoneServer (`zone_server.go`)
- Central coordinator for all zone functionality
- Manages clients, spawns, timers, and processing loops
- Handles zone initialization, configuration, and shutdown
- Thread-safe operations using sync.RWMutex and atomic values
- Supports both regular zones and instances
#### ZoneManager (`zone_manager.go`)
- High-level management of multiple zones and instances
- Automatic loading/unloading based on demand
- Instance creation with type-specific player limits
- Statistics collection and monitoring
- Cleanup of inactive instances
#### MobMovementManager (`movement_manager.go`)
- Advanced NPC movement system with command queuing
- Pathfinding integration with multiple backends
- Stuck detection and recovery mechanisms
- Multiple movement modes (walk, run, swim, fly)
- Thread-safe processing with delta time calculations
#### Position System (`position.go`)
- EverQuest II specific 3D math utilities
- Distance calculations (2D, 3D, 4D with heading)
- Heading conversion and normalization (512-unit circle)
- Bounding box and cylinder collision detection
- Interpolation and random position generation
#### Database Layer (`database.go`)
- Complete zone data persistence with prepared statements
- Transaction support for atomic updates
- Efficient loading of zone configuration and spawn data
- Support for spawn locations, groups, and associations
- Thread-safe operations with connection pooling
### Key Features
#### Spatial Optimization
- **Grid System**: Spatial partitioning for efficient spawn queries
- **Range-based Updates**: Only process spawns within client visibility
- **Distance Culling**: Automatic spawn loading/unloading based on distance
- **Grid-based Indexing**: Fast lookup of nearby spawns and objects
#### Instance System
- **Multiple Instance Types**: Group, raid, solo, tradeskill, housing, quest instances
- **Automatic Limits**: Type-specific player count restrictions
- **Lifecycle Management**: Automatic creation and cleanup
- **Persistence Options**: Lockout vs persistent instances
#### Movement System
- **Command Queuing**: Sequential movement command execution
- **Pathfinding Integration**: Multiple pathfinding backends (navmesh, waypoint, null)
- **Stuck Detection**: Position-based stuck detection with recovery strategies
- **Smooth Movement**: Delta-time based position interpolation
- **Multi-mode Support**: Walking, running, swimming, flying
#### Weather System
- **Dynamic Patterns**: Normal, dynamic, random, and chaotic weather types
- **Severity Control**: Min/max bounds with configurable change rates
- **Pattern Support**: Increasing, decreasing, and random severity patterns
- **Client Synchronization**: Automatic weather updates to all clients
## Usage Examples
### Basic Zone Creation and Management
```go
// Create zone server
zoneServer := NewZoneServer("qeynos")
// Configure zone
config := &ZoneServerConfig{
ZoneName: "qeynos",
ZoneFile: "qeynos.zone",
ZoneDescription: "Qeynos: Capitol of Antonica",
ZoneID: 100,
InstanceID: 0,
InstanceType: InstanceTypeNone,
MaxPlayers: 200,
MinLevel: 1,
MaxLevel: 100,
SafeX: 830.0,
SafeY: -25.0,
SafeZ: -394.0,
SafeHeading: 0.0,
LoadMaps: true,
EnableWeather: true,
EnablePathfinding: true,
}
// Initialize zone
err := zoneServer.Initialize(config)
if err != nil {
log.Fatal(err)
}
// Add client to zone
err = zoneServer.AddClient(client)
if err != nil {
log.Printf("Failed to add client: %v", err)
}
```
### Zone Manager Usage
```go
// Create zone manager
config := &ZoneManagerConfig{
MaxZones: 50,
MaxInstanceZones: 500,
ProcessInterval: time.Millisecond * 100,
CleanupInterval: time.Minute * 5,
EnableWeather: true,
EnablePathfinding: true,
}
zoneManager := NewZoneManager(config, database)
// Start zone manager
err := zoneManager.Start()
if err != nil {
log.Fatal(err)
}
// Load a zone
zone, err := zoneManager.LoadZone(100) // Qeynos
if err != nil {
log.Printf("Failed to load zone: %v", err)
}
// Create an instance
instance, err := zoneManager.CreateInstance(100, InstanceTypeGroupLockout, playerID)
if err != nil {
log.Printf("Failed to create instance: %v", err)
}
```
### Movement System Usage
```go
// Get movement manager from zone
movementMgr := zoneServer.movementMgr
// Add NPC to movement tracking
spawnID := int32(1001)
movementMgr.AddMovementSpawn(spawnID)
// Command NPC to move
err := movementMgr.MoveTo(spawnID, 100.0, 200.0, 0.0, DefaultRunSpeed)
if err != nil {
log.Printf("Movement command failed: %v", err)
}
// Queue multiple commands
movementMgr.MoveTo(spawnID, 150.0, 250.0, 0.0, DefaultWalkSpeed)
movementMgr.RotateTo(spawnID, 256.0, 90.0) // Turn around
movementMgr.MoveTo(spawnID, 100.0, 200.0, 0.0, DefaultRunSpeed) // Return
// Check if moving
if movementMgr.IsMoving(spawnID) {
state := movementMgr.GetMovementState(spawnID)
log.Printf("NPC %d is moving at speed %.2f", spawnID, state.Speed)
}
```
### Position Calculations
```go
// Calculate distance between two points
distance := Distance3D(0, 0, 0, 100, 100, 100)
log.Printf("Distance: %.2f", distance)
// Calculate heading from one point to another
heading := CalculateHeading(0, 0, 100, 100)
log.Printf("Heading: %.2f", heading)
// Work with positions
pos1 := NewPosition(10.0, 20.0, 30.0, 128.0)
pos2 := NewPosition(50.0, 60.0, 30.0, 256.0)
distance = pos1.DistanceTo3D(pos2)
log.Printf("Position distance: %.2f", distance)
// Check if positions are within range
if IsWithinRange(pos1, pos2, 100.0) {
log.Println("Positions are within range")
}
// Create bounding box and test containment
bbox := NewBoundingBox(0, 0, 0, 100, 100, 100)
if bbox.ContainsPosition(pos1) {
log.Println("Position is inside bounding box")
}
```
### Weather System
```go
// Set rain level
zoneServer.SetRain(0.8) // Heavy rain
// Weather is processed automatically, but can be triggered manually
zoneServer.ProcessWeather()
// Configure weather (typically done during initialization)
zoneServer.weatherEnabled = true
zoneServer.weatherType = WeatherTypeDynamic
zoneServer.weatherFrequency = 600 // 10 minutes
zoneServer.weatherMinSeverity = 0.0
zoneServer.weatherMaxSeverity = 1.0
zoneServer.weatherChangeAmount = 0.1
zoneServer.weatherChangeChance = 75 // 75% chance of change
```
## Database Schema
The zone system uses several database tables:
### Core Zone Configuration
```sql
CREATE TABLE zones (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
file TEXT,
description TEXT,
safe_x REAL DEFAULT 0,
safe_y REAL DEFAULT 0,
safe_z REAL DEFAULT 0,
safe_heading REAL DEFAULT 0,
underworld REAL DEFAULT -1000,
min_level INTEGER DEFAULT 0,
max_level INTEGER DEFAULT 0,
max_players INTEGER DEFAULT 100,
instance_type INTEGER DEFAULT 0,
expansion_flag INTEGER DEFAULT 0,
weather_allowed INTEGER DEFAULT 1,
-- ... additional fields
);
```
### Spawn Locations
```sql
CREATE TABLE spawn_location_placement (
id INTEGER PRIMARY KEY,
zone_id INTEGER,
x REAL,
y REAL,
z REAL,
heading REAL,
spawn_type INTEGER,
respawn_time INTEGER DEFAULT 600,
conditions INTEGER DEFAULT 0,
spawn_percentage REAL DEFAULT 100.0
);
```
### Spawn Groups
```sql
CREATE TABLE spawn_location_group (
group_id INTEGER,
location_id INTEGER,
zone_id INTEGER
);
```
## Configuration
### Key Constants
- **Distance Constants**: `SendSpawnDistance` (250), `RemoveSpawnDistance` (300)
- **Movement Speeds**: `DefaultWalkSpeed` (2.5), `DefaultRunSpeed` (7.0)
- **Timer Intervals**: Configurable processing intervals for different systems
- **Capacity Limits**: `MaxSpawnsPerGrid` (100), `MaxClientsPerZone` (200)
### Zone Rules
Zones can be configured with various rules:
- Player level restrictions (min/max)
- Client version requirements
- PvP enablement
- Weather settings
- Instance type and capacity
- Expansion and holiday flags
## Thread Safety
All zone operations are designed to be thread-safe:
- **RWMutex Usage**: Separate read/write locks for different data structures
- **Atomic Operations**: For simple flags and counters
- **Channel Communication**: For cross-goroutine messaging
- **Immutable Data**: Where possible, data structures are immutable
- **Copy-on-Read**: Returns copies of data to prevent race conditions
## Performance Considerations
- **Spatial Indexing**: Grid-based partitioning reduces O(n) to O(1) for range queries
- **Prepared Statements**: All database queries use prepared statements
- **Object Pooling**: Reuse of frequently allocated objects
- **Lazy Loading**: Zone data loaded on demand
- **Concurrent Processing**: Multiple goroutines for different subsystems
- **Memory Management**: Regular cleanup of expired objects and timers
## Error Handling
The zone system provides comprehensive error handling:
- **Graceful Degradation**: Systems continue operating when non-critical components fail
- **Detailed Logging**: All errors logged with appropriate prefixes and context
- **Recovery Mechanisms**: Automatic recovery from common error conditions
- **Validation**: Input validation at all API boundaries
- **Timeouts**: All operations have appropriate timeouts
## Testing
Comprehensive test suite includes:
- Unit tests for all major components
- Integration tests for database operations
- Performance benchmarks for critical paths
- Mock implementations for testing isolation
- Property-based testing for mathematical functions
Run tests with:
```bash
go test ./internal/zone/...
go test -race ./internal/zone/... # Race condition detection
go test -bench=. ./internal/zone/ # Performance benchmarks
```
## Migration from C++
This Go implementation maintains compatibility with the original C++ EQ2EMu zone system:
- **Database Schema**: Identical table structure and relationships
- **Protocol Compatibility**: Same client communication protocols
- **Algorithmic Equivalence**: Math functions produce identical results
- **Configuration Format**: Compatible configuration files and settings
- **Performance**: Comparable or improved performance through Go's concurrency
## Dependencies
- **Standard Library**: sync, time, database/sql, math
- **Internal Packages**: database, spawn, common
- **External**: SQLite driver (zombiezen.com/go/sqlite)
## Future Enhancements
Planned improvements include:
- **Advanced Pathfinding**: Integration with Detour navigation mesh
- **Lua Scripting**: Full Lua integration for spawn behaviors
- **Physics Engine**: Advanced collision detection and physics
- **Clustering**: Multi-server zone distribution
- **Hot Reloading**: Dynamic configuration updates without restart