604 lines
16 KiB
Go
604 lines
16 KiB
Go
package zone
|
|
|
|
import (
|
|
"sync"
|
|
"sync/atomic"
|
|
"time"
|
|
|
|
"eq2emu/internal/common"
|
|
"eq2emu/internal/spawn"
|
|
)
|
|
|
|
// Instance types define different zone instance behaviors
|
|
type InstanceType int16
|
|
|
|
const (
|
|
InstanceTypeNone InstanceType = iota
|
|
InstanceTypeGroupLockout
|
|
InstanceTypeGroupPersist
|
|
InstanceTypeRaidLockout
|
|
InstanceTypeRaidPersist
|
|
InstanceTypeSoloLockout
|
|
InstanceTypeSoloPersist
|
|
InstanceTypeTradeskill
|
|
InstanceTypePublic
|
|
InstanceTypePersonalHouse
|
|
InstanceTypeGuildHouse
|
|
InstanceTypeQuest
|
|
)
|
|
|
|
// Core zone server structure - equivalent to C++ ZoneServer class
|
|
type ZoneServer struct {
|
|
// Zone identity and configuration
|
|
zoneID int32
|
|
instanceID int32
|
|
zoneName string
|
|
zoneFile string
|
|
zoneSkyFile string
|
|
zoneDescription string
|
|
|
|
// Zone properties
|
|
cityZone bool
|
|
alwaysLoaded bool
|
|
duplicatedZone bool
|
|
duplicatedID int32
|
|
locked bool
|
|
isInstance bool
|
|
instanceType InstanceType
|
|
|
|
// Safe zone coordinates
|
|
safeX float32
|
|
safeY float32
|
|
safeZ float32
|
|
safeHeading float32
|
|
underworld float32
|
|
|
|
// Zone modifiers and rules
|
|
xpModifier float32
|
|
minimumStatus int16
|
|
minimumLevel int16
|
|
maximumLevel int16
|
|
minimumVersion int16
|
|
expansionFlag int32
|
|
holidayFlag int32
|
|
canBind bool
|
|
canGate bool
|
|
canEvac bool
|
|
|
|
// Zone times and lockouts
|
|
defaultLockoutTime int32
|
|
defaultReenterTime int32
|
|
defaultResetTime int32
|
|
groupZoneOption int8
|
|
|
|
// Player and client management
|
|
clients []Client
|
|
numPlayers int32
|
|
incomingClients int32
|
|
lifetimeClientCount int32
|
|
|
|
// Weather system
|
|
weatherEnabled bool
|
|
weatherAllowed bool
|
|
weatherType int8
|
|
weatherFrequency int32
|
|
weatherMinSeverity float32
|
|
weatherMaxSeverity float32
|
|
weatherChangeAmount float32
|
|
weatherDynamicOffset float32
|
|
weatherChangeChance int8
|
|
weatherCurrentSeverity float32
|
|
weatherPattern int8
|
|
weatherLastChangedTime int32
|
|
weatherSignaled bool
|
|
rain float32
|
|
|
|
// Time system
|
|
isDusk bool
|
|
duskHour int
|
|
duskMinute int
|
|
dawnHour int
|
|
dawnMinute int
|
|
|
|
// Zone message
|
|
zoneMOTD string
|
|
|
|
// Thread and processing state
|
|
spawnThreadActive bool
|
|
combatThreadActive bool
|
|
initialSpawnThreads int8
|
|
clientThreadActive bool
|
|
loadingData bool
|
|
zoneShuttingDown atomic.Bool
|
|
isInitialized atomic.Bool
|
|
finishedDepop bool
|
|
depopZone bool
|
|
repopZone bool
|
|
respawnsAllowed bool
|
|
|
|
// Spawn management
|
|
spawnList map[int32]*spawn.Spawn
|
|
spawnLocationList map[int32]*SpawnLocation
|
|
changedSpawns map[int32]bool
|
|
damagedSpawns []int32
|
|
pendingSpawnList []*spawn.Spawn
|
|
pendingSpawnRemove map[int32]bool
|
|
spawnDeleteList map[*spawn.Spawn]int32
|
|
spawnExpireTimers map[int32]int32
|
|
|
|
// Grid system for spatial optimization
|
|
gridMaps map[int32]*GridMap
|
|
|
|
// Movement and pathfinding
|
|
pathfinder IPathfinder
|
|
movementMgr *MobMovementManager
|
|
|
|
// System components
|
|
spellProcess SpellProcess
|
|
tradeskillMgr TradeskillManager
|
|
|
|
// Timers
|
|
aggroTimer *common.Timer
|
|
charsheetChanges *common.Timer
|
|
clientSave *common.Timer
|
|
locationProxTimer *common.Timer
|
|
movementTimer *common.Timer
|
|
regenTimer *common.Timer
|
|
respawnTimer *common.Timer
|
|
shutdownTimer *common.Timer
|
|
spawnRangeTimer *common.Timer
|
|
spawnUpdateTimer *common.Timer
|
|
syncGameTimer *common.Timer
|
|
trackingTimer *common.Timer
|
|
weatherTimer *common.Timer
|
|
widgetTimer *common.Timer
|
|
|
|
// Proximity systems
|
|
playerProximities map[int32]*PlayerProximity
|
|
locationProximities []*LocationProximity
|
|
locationGrids []*LocationGrid
|
|
|
|
// Faction management
|
|
enemyFactionList map[int32][]int32
|
|
npcFactionList map[int32][]int32
|
|
reverseEnemyFactionList map[int32][]int32
|
|
|
|
// Revive points
|
|
revivePoints []*RevivePoint
|
|
|
|
// Transport system
|
|
transportSpawns []int32
|
|
transportLocations []*LocationTransportDestination
|
|
transporters map[int32][]*TransportDestination
|
|
locationTransporters map[int32][]*LocationTransportDestination
|
|
transportMaps map[int32]string
|
|
|
|
// Flight paths
|
|
flightPaths map[int32]*FlightPathInfo
|
|
flightPathRoutes map[int32][]*FlightPathLocation
|
|
|
|
// Loot system
|
|
lootTables map[int32]*LootTable
|
|
lootDrops map[int32][]*LootDrop
|
|
spawnLootList map[int32][]int32
|
|
levelLootList []*GlobalLoot
|
|
racialLootList map[int16][]*GlobalLoot
|
|
zoneLootList map[int32][]*GlobalLoot
|
|
|
|
// Spawn data caches
|
|
npcList map[int32]*NPC
|
|
objectList map[int32]*Object
|
|
signList map[int32]*Sign
|
|
widgetList map[int32]*Widget
|
|
groundSpawnList map[int32]*GroundSpawn
|
|
|
|
// Entity commands
|
|
entityCommandList map[int32][]*EntityCommand
|
|
|
|
// Spawn groups and locations
|
|
spawnGroupAssociations map[int32][]int32
|
|
spawnGroupChances map[int32]float32
|
|
spawnGroupLocations map[int32]map[int32]int32
|
|
spawnGroupMap map[int32][]int32
|
|
spawnLocationGroups map[int32][]int32
|
|
|
|
// Script timers
|
|
spawnScriptTimers []*SpawnScriptTimer
|
|
|
|
// Widget management
|
|
widgetTimers map[int32]int32
|
|
ignoredWidgets map[int32]bool
|
|
|
|
// House items
|
|
subspawnList map[SubspawnType]map[int32]*spawn.Spawn
|
|
housingSpawnMap map[int32]int32
|
|
|
|
// Respawn management
|
|
respawnTimers map[int32]int32
|
|
|
|
// Zone map
|
|
defaultZoneMap Map
|
|
|
|
// Group/raid level tracking
|
|
groupRaidMinLevel int32
|
|
groupRaidMaxLevel int32
|
|
groupRaidAvgLevel int32
|
|
groupRaidFirstLevel int32
|
|
|
|
// Watchdog
|
|
watchdogTimestamp int32
|
|
|
|
// Lua command queues
|
|
luaQueuedStateCommands map[int32]int32
|
|
luaSpawnUpdateCommands map[int32]map[string]float32
|
|
|
|
// Mutexes for thread safety
|
|
masterZoneLock sync.RWMutex
|
|
masterSpawnLock sync.RWMutex
|
|
spawnListLock sync.RWMutex
|
|
clientListLock sync.RWMutex
|
|
changedSpawnsLock sync.RWMutex
|
|
gridMapsLock sync.RWMutex
|
|
spawnLocationListLock sync.RWMutex
|
|
spawnDeleteListLock sync.RWMutex
|
|
widgetTimersLock sync.RWMutex
|
|
ignoredWidgetsLock sync.RWMutex
|
|
pendingSpawnRemoveLock sync.RWMutex
|
|
luaQueueStateCmdLock sync.Mutex
|
|
transportLock sync.RWMutex
|
|
factionLock sync.RWMutex
|
|
spawnScriptTimersLock sync.RWMutex
|
|
deadSpawnsLock sync.RWMutex
|
|
incomingClientsLock sync.RWMutex
|
|
}
|
|
|
|
// PlayerProximity manages spawn proximity events for Lua scripting
|
|
type PlayerProximity struct {
|
|
Distance float32
|
|
InRangeLuaFunction string
|
|
LeavingRangeLuaFunction string
|
|
ClientsInProximity map[Client]bool
|
|
mutex sync.RWMutex
|
|
}
|
|
|
|
// LocationProximity handles location-based proximity triggers
|
|
type LocationProximity struct {
|
|
X float32
|
|
Y float32
|
|
Z float32
|
|
MaxVariation float32
|
|
InRangeLuaFunction string
|
|
LeavingRangeLuaFunction string
|
|
ClientsInProximity map[Client]bool
|
|
mutex sync.RWMutex
|
|
}
|
|
|
|
// LocationGrid manages discovery grids and player tracking
|
|
type LocationGrid struct {
|
|
ID int32
|
|
GridID int32
|
|
Name string
|
|
IncludeY bool
|
|
Discovery bool
|
|
Locations []*Location
|
|
Players map[Player]bool
|
|
mutex sync.RWMutex
|
|
}
|
|
|
|
// GridMap provides spawn organization by grid for efficient querying
|
|
type GridMap struct {
|
|
GridID int32
|
|
Spawns map[int32]*spawn.Spawn
|
|
mutex sync.RWMutex
|
|
}
|
|
|
|
// TrackedSpawn represents distance-based spawn tracking for clients
|
|
type TrackedSpawn struct {
|
|
Spawn *spawn.Spawn
|
|
Distance float32
|
|
}
|
|
|
|
// HouseItem represents player housing item management
|
|
type HouseItem struct {
|
|
SpawnID int32
|
|
ItemID int32
|
|
UniqueID int64
|
|
Item *Item
|
|
}
|
|
|
|
// RevivePoint represents death recovery locations
|
|
type RevivePoint struct {
|
|
ID int32
|
|
ZoneID int32
|
|
LocationName string
|
|
X float32
|
|
Y float32
|
|
Z float32
|
|
Heading float32
|
|
AlwaysIncluded bool
|
|
}
|
|
|
|
// SpawnScriptTimer represents Lua script timer management
|
|
type SpawnScriptTimer struct {
|
|
Timer int32
|
|
SpawnID int32
|
|
PlayerID int32
|
|
Function string
|
|
CurrentCount int32
|
|
MaxCount int32
|
|
}
|
|
|
|
// FlightPathInfo contains flight path configuration
|
|
type FlightPathInfo struct {
|
|
Speed float32
|
|
Flying bool
|
|
Dismount bool
|
|
}
|
|
|
|
// FlightPathLocation represents a waypoint in a flight path
|
|
type FlightPathLocation struct {
|
|
X float32
|
|
Y float32
|
|
Z float32
|
|
}
|
|
|
|
// ZoneInfoSlideStructInfo represents zone intro slide information
|
|
type ZoneInfoSlideStructInfo struct {
|
|
Unknown1 [2]float32
|
|
Unknown2 [2]int32
|
|
Unknown3 int32
|
|
Unknown4 int32
|
|
Slide string
|
|
Voiceover string
|
|
Key1 int32
|
|
Key2 int32
|
|
}
|
|
|
|
// ZoneInfoSlideStructTransitionInfo represents slide transition data
|
|
type ZoneInfoSlideStructTransitionInfo struct {
|
|
TransitionX int32
|
|
TransitionY int32
|
|
TransitionZoom float32
|
|
TransitionTime float32
|
|
}
|
|
|
|
// ZoneInfoSlideStruct combines slide info and transitions
|
|
type ZoneInfoSlideStruct struct {
|
|
Info *ZoneInfoSlideStructInfo
|
|
SlideTransitionInfo []*ZoneInfoSlideStructTransitionInfo
|
|
}
|
|
|
|
// SubspawnType enumeration for different spawn subtypes
|
|
type SubspawnType int
|
|
|
|
const (
|
|
SubspawnTypeCollector SubspawnType = iota
|
|
SubspawnTypeHouseItem
|
|
SubspawnTypeMax = 20
|
|
)
|
|
|
|
// Expansion flags for client compatibility
|
|
const (
|
|
ExpansionUnknown = 1
|
|
ExpansionUnknown2 = 64
|
|
ExpansionUnknown3 = 128
|
|
ExpansionUnknown4 = 256
|
|
ExpansionUnknown5 = 512
|
|
ExpansionDOF = 1024
|
|
ExpansionKOS = 2048
|
|
ExpansionEOF = 4096
|
|
ExpansionROK = 8192
|
|
ExpansionTSO = 16384
|
|
ExpansionDOV = 65536
|
|
)
|
|
|
|
// Spawn script event types
|
|
const (
|
|
SpawnScriptSpawn = iota
|
|
SpawnScriptRespawn
|
|
SpawnScriptAttacked
|
|
SpawnScriptTargeted
|
|
SpawnScriptHailed
|
|
SpawnScriptDeath
|
|
SpawnScriptKilled
|
|
SpawnScriptAggro
|
|
SpawnScriptHealthChanged
|
|
SpawnScriptRandomChat
|
|
SpawnScriptConversation
|
|
SpawnScriptTimer
|
|
SpawnScriptCustom
|
|
SpawnScriptHailedBusy
|
|
SpawnScriptCastedOn
|
|
SpawnScriptAutoAttackTick
|
|
SpawnScriptCombatReset
|
|
SpawnScriptGroupDead
|
|
SpawnScriptHearSay
|
|
SpawnScriptPrespawn
|
|
SpawnScriptUseDoor
|
|
SpawnScriptBoard
|
|
SpawnScriptDeboard
|
|
)
|
|
|
|
// Spawn conditional flags
|
|
const (
|
|
SpawnConditionalNone = 0
|
|
SpawnConditionalDay = 1
|
|
SpawnConditionalNight = 2
|
|
SpawnConditionalNotRaining = 4
|
|
SpawnConditionalRaining = 8
|
|
)
|
|
|
|
// Distance constants
|
|
const (
|
|
SendSpawnDistance = 250.0 // When spawns appear visually to the client
|
|
HearSpawnDistance = 30.0 // Max distance a client can be from a spawn to 'hear' it
|
|
MaxChaseDistance = 80.0 // Maximum chase distance for NPCs
|
|
RemoveSpawnDistance = 300.0 // Distance at which spawns are removed from client
|
|
MaxRevivePointDistance = 1000.0 // Maximum distance for revive point selection
|
|
)
|
|
|
|
// Tracking system constants
|
|
const (
|
|
TrackingStop = iota
|
|
TrackingStart
|
|
TrackingUpdate
|
|
TrackingCloseWindow
|
|
)
|
|
|
|
const (
|
|
TrackingTypeEntities = iota + 1
|
|
TrackingTypeHarvestables
|
|
)
|
|
|
|
const (
|
|
TrackingSpawnTypePC = iota
|
|
TrackingSpawnTypeNPC
|
|
)
|
|
|
|
// Waypoint categories
|
|
const (
|
|
WaypointCategoryGroup = iota
|
|
WaypointCategoryQuests
|
|
WaypointCategoryPeople
|
|
WaypointCategoryPlaces
|
|
WaypointCategoryUser
|
|
WaypointCategoryDirections
|
|
WaypointCategoryTracking
|
|
WaypointCategoryHouses
|
|
WaypointCategoryMap
|
|
)
|
|
|
|
// Weather system constants
|
|
const (
|
|
WeatherTypeNormal = iota
|
|
WeatherTypeDynamic
|
|
WeatherTypeRandom
|
|
WeatherTypeChaotic
|
|
)
|
|
|
|
const (
|
|
WeatherPatternDecreasing = iota
|
|
WeatherPatternIncreasing
|
|
WeatherPatternRandom
|
|
)
|
|
|
|
// NewZoneServer creates a new zone server instance with the given zone name
|
|
func NewZoneServer(zoneName string) *ZoneServer {
|
|
zs := &ZoneServer{
|
|
zoneName: zoneName,
|
|
respawnsAllowed: true,
|
|
finishedDepop: true,
|
|
canBind: true,
|
|
canGate: true,
|
|
canEvac: true,
|
|
clients: make([]Client, 0),
|
|
spawnList: make(map[int32]*spawn.Spawn),
|
|
spawnLocationList: make(map[int32]*SpawnLocation),
|
|
changedSpawns: make(map[int32]bool),
|
|
damagedSpawns: make([]int32, 0),
|
|
pendingSpawnList: make([]*spawn.Spawn, 0),
|
|
pendingSpawnRemove: make(map[int32]bool),
|
|
spawnDeleteList: make(map[*spawn.Spawn]int32),
|
|
spawnExpireTimers: make(map[int32]int32),
|
|
gridMaps: make(map[int32]*GridMap),
|
|
playerProximities: make(map[int32]*PlayerProximity),
|
|
locationProximities: make([]*LocationProximity, 0),
|
|
locationGrids: make([]*LocationGrid, 0),
|
|
enemyFactionList: make(map[int32][]int32),
|
|
npcFactionList: make(map[int32][]int32),
|
|
reverseEnemyFactionList: make(map[int32][]int32),
|
|
revivePoints: make([]*RevivePoint, 0),
|
|
transportSpawns: make([]int32, 0),
|
|
transportLocations: make([]*LocationTransportDestination, 0),
|
|
transporters: make(map[int32][]*TransportDestination),
|
|
locationTransporters: make(map[int32][]*LocationTransportDestination),
|
|
transportMaps: make(map[int32]string),
|
|
flightPaths: make(map[int32]*FlightPathInfo),
|
|
flightPathRoutes: make(map[int32][]*FlightPathLocation),
|
|
lootTables: make(map[int32]*LootTable),
|
|
lootDrops: make(map[int32][]*LootDrop),
|
|
spawnLootList: make(map[int32][]int32),
|
|
levelLootList: make([]*GlobalLoot, 0),
|
|
racialLootList: make(map[int16][]*GlobalLoot),
|
|
zoneLootList: make(map[int32][]*GlobalLoot),
|
|
npcList: make(map[int32]*NPC),
|
|
objectList: make(map[int32]*Object),
|
|
signList: make(map[int32]*Sign),
|
|
widgetList: make(map[int32]*Widget),
|
|
groundSpawnList: make(map[int32]*GroundSpawn),
|
|
entityCommandList: make(map[int32][]*EntityCommand),
|
|
spawnGroupAssociations: make(map[int32][]int32),
|
|
spawnGroupChances: make(map[int32]float32),
|
|
spawnGroupLocations: make(map[int32]map[int32]int32),
|
|
spawnGroupMap: make(map[int32][]int32),
|
|
spawnLocationGroups: make(map[int32][]int32),
|
|
spawnScriptTimers: make([]*SpawnScriptTimer, 0),
|
|
widgetTimers: make(map[int32]int32),
|
|
ignoredWidgets: make(map[int32]bool),
|
|
subspawnList: make(map[SubspawnType]map[int32]*spawn.Spawn),
|
|
housingSpawnMap: make(map[int32]int32),
|
|
respawnTimers: make(map[int32]int32),
|
|
luaQueuedStateCommands: make(map[int32]int32),
|
|
luaSpawnUpdateCommands: make(map[int32]map[string]float32),
|
|
watchdogTimestamp: int32(time.Now().Unix()),
|
|
}
|
|
|
|
// Initialize subspawn lists
|
|
for i := SubspawnType(0); i < SubspawnTypeMax; i++ {
|
|
zs.subspawnList[i] = make(map[int32]*spawn.Spawn)
|
|
}
|
|
|
|
zs.loadingData = true
|
|
zs.zoneShuttingDown.Store(false)
|
|
zs.isInitialized.Store(false)
|
|
|
|
return zs
|
|
}
|
|
|
|
// String returns a string representation of the instance type
|
|
func (it InstanceType) String() string {
|
|
switch it {
|
|
case InstanceTypeNone:
|
|
return "None"
|
|
case InstanceTypeGroupLockout:
|
|
return "Group Lockout"
|
|
case InstanceTypeGroupPersist:
|
|
return "Group Persistent"
|
|
case InstanceTypeRaidLockout:
|
|
return "Raid Lockout"
|
|
case InstanceTypeRaidPersist:
|
|
return "Raid Persistent"
|
|
case InstanceTypeSoloLockout:
|
|
return "Solo Lockout"
|
|
case InstanceTypeSoloPersist:
|
|
return "Solo Persistent"
|
|
case InstanceTypeTradeskill:
|
|
return "Tradeskill"
|
|
case InstanceTypePublic:
|
|
return "Public"
|
|
case InstanceTypePersonalHouse:
|
|
return "Personal House"
|
|
case InstanceTypeGuildHouse:
|
|
return "Guild House"
|
|
case InstanceTypeQuest:
|
|
return "Quest"
|
|
default:
|
|
return "Unknown"
|
|
}
|
|
}
|
|
|
|
// IsShuttingDown returns whether the zone is in the process of shutting down
|
|
func (zs *ZoneServer) IsShuttingDown() bool {
|
|
return zs.zoneShuttingDown.Load()
|
|
}
|
|
|
|
// IsInitialized returns whether the zone has completed initialization
|
|
func (zs *ZoneServer) IsInitialized() bool {
|
|
return zs.isInitialized.Load()
|
|
}
|
|
|
|
// Shutdown initiates the zone shutdown process
|
|
func (zs *ZoneServer) Shutdown() {
|
|
zs.zoneShuttingDown.Store(true)
|
|
}
|