# 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