763 lines
20 KiB
Go
763 lines
20 KiB
Go
package alt_advancement
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
)
|
|
|
|
// NewAAManager creates a new AA manager
|
|
func NewAAManager(config AAManagerConfig) *AAManager {
|
|
return &AAManager{
|
|
masterAAList: NewMasterAAList(),
|
|
masterNodeList: NewMasterAANodeList(),
|
|
playerStates: make(map[int32]*AAPlayerState),
|
|
config: config,
|
|
eventHandlers: make([]AAEventHandler, 0),
|
|
stats: AAManagerStats{},
|
|
stopChan: make(chan struct{}),
|
|
}
|
|
}
|
|
|
|
// Start starts the AA manager
|
|
func (am *AAManager) Start() error {
|
|
// Load AA data
|
|
if err := am.LoadAAData(); err != nil {
|
|
return fmt.Errorf("failed to load AA data: %v", err)
|
|
}
|
|
|
|
// Start background processes
|
|
if am.config.UpdateInterval > 0 {
|
|
am.wg.Add(1)
|
|
go am.updateStatsLoop()
|
|
}
|
|
|
|
if am.config.AutoSave && am.config.SaveInterval > 0 {
|
|
am.wg.Add(1)
|
|
go am.autoSaveLoop()
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Stop stops the AA manager
|
|
func (am *AAManager) Stop() error {
|
|
close(am.stopChan)
|
|
am.wg.Wait()
|
|
|
|
// Save all player states if auto-save is enabled
|
|
if am.config.AutoSave {
|
|
am.saveAllPlayerStates()
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// IsRunning returns true if the manager is running
|
|
func (am *AAManager) IsRunning() bool {
|
|
select {
|
|
case <-am.stopChan:
|
|
return false
|
|
default:
|
|
return true
|
|
}
|
|
}
|
|
|
|
// LoadAAData loads all AA data from the database
|
|
func (am *AAManager) LoadAAData() error {
|
|
if am.database == nil {
|
|
return fmt.Errorf("database not configured")
|
|
}
|
|
|
|
startTime := time.Now()
|
|
|
|
// Load AA definitions
|
|
if err := am.database.LoadAltAdvancements(); err != nil {
|
|
return fmt.Errorf("failed to load AAs: %v", err)
|
|
}
|
|
|
|
// Load tree nodes
|
|
if err := am.database.LoadTreeNodes(); err != nil {
|
|
return fmt.Errorf("failed to load tree nodes: %v", err)
|
|
}
|
|
|
|
// Update statistics
|
|
am.statsMutex.Lock()
|
|
am.stats.TotalAAsLoaded = int64(am.masterAAList.Size())
|
|
am.stats.TotalNodesLoaded = int64(am.masterNodeList.Size())
|
|
am.stats.LastLoadTime = startTime
|
|
am.stats.LoadDuration = time.Since(startTime)
|
|
am.statsMutex.Unlock()
|
|
|
|
// Fire load event
|
|
am.fireSystemLoadedEvent(int32(am.stats.TotalAAsLoaded), int32(am.stats.TotalNodesLoaded))
|
|
|
|
return nil
|
|
}
|
|
|
|
// ReloadAAData reloads all AA data
|
|
func (am *AAManager) ReloadAAData() error {
|
|
// Clear existing data
|
|
am.masterAAList.DestroyAltAdvancements()
|
|
am.masterNodeList.DestroyTreeNodes()
|
|
|
|
// Clear cached player states
|
|
am.statesMutex.Lock()
|
|
am.playerStates = make(map[int32]*AAPlayerState)
|
|
am.statesMutex.Unlock()
|
|
|
|
// Reload data
|
|
err := am.LoadAAData()
|
|
if err == nil {
|
|
am.fireDataReloadedEvent()
|
|
}
|
|
|
|
return err
|
|
}
|
|
|
|
// LoadPlayerAA loads AA data for a specific player
|
|
func (am *AAManager) LoadPlayerAA(characterID int32) (*AAPlayerState, error) {
|
|
if am.database == nil {
|
|
return nil, fmt.Errorf("database not configured")
|
|
}
|
|
|
|
// Load from database
|
|
playerState, err := am.database.LoadPlayerAA(characterID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to load player AA: %v", err)
|
|
}
|
|
|
|
// Cache the player state
|
|
am.statesMutex.Lock()
|
|
am.playerStates[characterID] = playerState
|
|
am.statesMutex.Unlock()
|
|
|
|
// Fire load event
|
|
am.firePlayerAALoadedEvent(characterID, playerState)
|
|
|
|
return playerState, nil
|
|
}
|
|
|
|
// SavePlayerAA saves AA data for a specific player
|
|
func (am *AAManager) SavePlayerAA(characterID int32) error {
|
|
if am.database == nil {
|
|
return fmt.Errorf("database not configured")
|
|
}
|
|
|
|
// Get player state
|
|
playerState := am.getPlayerState(characterID)
|
|
if playerState == nil {
|
|
return fmt.Errorf("player state not found for character %d", characterID)
|
|
}
|
|
|
|
// Save to database
|
|
return am.database.SavePlayerAA(playerState)
|
|
}
|
|
|
|
// GetPlayerAAState returns the AA state for a player
|
|
func (am *AAManager) GetPlayerAAState(characterID int32) (*AAPlayerState, error) {
|
|
// Try to get from cache first
|
|
if playerState := am.getPlayerState(characterID); playerState != nil {
|
|
return playerState, nil
|
|
}
|
|
|
|
// Load from database if not cached
|
|
return am.LoadPlayerAA(characterID)
|
|
}
|
|
|
|
// PurchaseAA purchases an AA for a player
|
|
func (am *AAManager) PurchaseAA(characterID int32, nodeID int32, targetRank int8) error {
|
|
// Get player state
|
|
playerState := am.getPlayerState(characterID)
|
|
if playerState == nil {
|
|
return fmt.Errorf("player state not found")
|
|
}
|
|
|
|
// Get AA data
|
|
aaData := am.masterAAList.GetAltAdvancementByNodeID(nodeID)
|
|
if aaData == nil {
|
|
return fmt.Errorf("AA node %d not found", nodeID)
|
|
}
|
|
|
|
// Validate purchase
|
|
if am.validator != nil {
|
|
if err := am.validator.ValidateAAPurchase(playerState, nodeID, targetRank); err != nil {
|
|
am.updateErrorStats("validation_errors")
|
|
return fmt.Errorf("validation failed: %v", err)
|
|
}
|
|
}
|
|
|
|
// Perform purchase
|
|
err := am.performAAPurchase(playerState, aaData, targetRank)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Fire purchase event
|
|
pointsSpent := int32(aaData.RankCost) * int32(targetRank)
|
|
am.fireAAPurchasedEvent(characterID, nodeID, targetRank, pointsSpent)
|
|
|
|
// Send notification
|
|
if am.notifier != nil {
|
|
am.notifier.NotifyAAPurchaseSuccess(characterID, aaData.Name, targetRank)
|
|
}
|
|
|
|
// Update statistics
|
|
if am.statistics != nil {
|
|
am.statistics.RecordAAPurchase(characterID, nodeID, pointsSpent)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// RefundAA refunds an AA for a player
|
|
func (am *AAManager) RefundAA(characterID int32, nodeID int32) error {
|
|
// Get player state
|
|
playerState := am.getPlayerState(characterID)
|
|
if playerState == nil {
|
|
return fmt.Errorf("player state not found")
|
|
}
|
|
|
|
// Get AA data
|
|
aaData := am.masterAAList.GetAltAdvancementByNodeID(nodeID)
|
|
if aaData == nil {
|
|
return fmt.Errorf("AA node %d not found", nodeID)
|
|
}
|
|
|
|
// Get current progress
|
|
progress, exists := playerState.AAProgress[nodeID]
|
|
if !exists || progress.CurrentRank == 0 {
|
|
return fmt.Errorf("AA not purchased or already at rank 0")
|
|
}
|
|
|
|
// Calculate refund amount
|
|
pointsRefunded := progress.PointsSpent
|
|
|
|
// Perform refund
|
|
playerState.mutex.Lock()
|
|
delete(playerState.AAProgress, nodeID)
|
|
playerState.SpentPoints -= pointsRefunded
|
|
playerState.AvailablePoints += pointsRefunded
|
|
playerState.needsSync = true
|
|
playerState.mutex.Unlock()
|
|
|
|
// Fire refund event
|
|
am.fireAARefundedEvent(characterID, nodeID, progress.CurrentRank, pointsRefunded)
|
|
|
|
// Send notification
|
|
if am.notifier != nil {
|
|
am.notifier.NotifyAARefund(characterID, aaData.Name, pointsRefunded)
|
|
}
|
|
|
|
// Update statistics
|
|
if am.statistics != nil {
|
|
am.statistics.RecordAARefund(characterID, nodeID, pointsRefunded)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetAvailableAAs returns AAs available for a player in a specific tab
|
|
func (am *AAManager) GetAvailableAAs(characterID int32, tabID int8) ([]*AltAdvanceData, error) {
|
|
// Get player state
|
|
playerState := am.getPlayerState(characterID)
|
|
if playerState == nil {
|
|
return nil, fmt.Errorf("player state not found")
|
|
}
|
|
|
|
// Get all AAs for the tab
|
|
allAAs := am.masterAAList.GetAAsByGroup(tabID)
|
|
var availableAAs []*AltAdvanceData
|
|
|
|
for _, aa := range allAAs {
|
|
// Check if AA is available for this player
|
|
if am.isAAAvailable(playerState, aa) {
|
|
availableAAs = append(availableAAs, aa)
|
|
}
|
|
}
|
|
|
|
return availableAAs, nil
|
|
}
|
|
|
|
// ChangeAATemplate changes the active AA template for a player
|
|
func (am *AAManager) ChangeAATemplate(characterID int32, templateID int8) error {
|
|
// Get player state
|
|
playerState := am.getPlayerState(characterID)
|
|
if playerState == nil {
|
|
return fmt.Errorf("player state not found")
|
|
}
|
|
|
|
// Validate template change
|
|
if am.validator != nil {
|
|
if err := am.validator.ValidateTemplateChange(playerState, templateID); err != nil {
|
|
return fmt.Errorf("template change validation failed: %v", err)
|
|
}
|
|
}
|
|
|
|
// Change template
|
|
oldTemplate := playerState.ActiveTemplate
|
|
playerState.mutex.Lock()
|
|
playerState.ActiveTemplate = templateID
|
|
playerState.needsSync = true
|
|
playerState.mutex.Unlock()
|
|
|
|
// Fire template change event
|
|
am.fireTemplateChangedEvent(characterID, oldTemplate, templateID)
|
|
|
|
return nil
|
|
}
|
|
|
|
// SaveAATemplate saves an AA template for a player
|
|
func (am *AAManager) SaveAATemplate(characterID int32, templateID int8, name string) error {
|
|
// Get player state
|
|
playerState := am.getPlayerState(characterID)
|
|
if playerState == nil {
|
|
return fmt.Errorf("player state not found")
|
|
}
|
|
|
|
// Create or update template
|
|
template := playerState.Templates[templateID]
|
|
if template == nil {
|
|
template = NewAATemplate(templateID, name)
|
|
playerState.Templates[templateID] = template
|
|
} else {
|
|
template.Name = name
|
|
template.UpdatedAt = time.Now()
|
|
}
|
|
|
|
playerState.mutex.Lock()
|
|
playerState.needsSync = true
|
|
playerState.mutex.Unlock()
|
|
|
|
// Fire template created event
|
|
am.fireTemplateCreatedEvent(characterID, templateID, name)
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetAATemplates returns all AA templates for a player
|
|
func (am *AAManager) GetAATemplates(characterID int32) (map[int8]*AATemplate, error) {
|
|
// Get player state
|
|
playerState := am.getPlayerState(characterID)
|
|
if playerState == nil {
|
|
return nil, fmt.Errorf("player state not found")
|
|
}
|
|
|
|
// Return copy of templates
|
|
templates := make(map[int8]*AATemplate)
|
|
playerState.mutex.RLock()
|
|
for id, template := range playerState.Templates {
|
|
templates[id] = template
|
|
}
|
|
playerState.mutex.RUnlock()
|
|
|
|
return templates, nil
|
|
}
|
|
|
|
// AwardAAPoints awards AA points to a player
|
|
func (am *AAManager) AwardAAPoints(characterID int32, points int32, reason string) error {
|
|
// Get player state
|
|
playerState := am.getPlayerState(characterID)
|
|
if playerState == nil {
|
|
return fmt.Errorf("player state not found")
|
|
}
|
|
|
|
// Award points
|
|
playerState.mutex.Lock()
|
|
playerState.TotalPoints += points
|
|
playerState.AvailablePoints += points
|
|
playerState.needsSync = true
|
|
playerState.mutex.Unlock()
|
|
|
|
// Send notification
|
|
if am.notifier != nil {
|
|
am.notifier.NotifyAAPointsAwarded(characterID, points, reason)
|
|
}
|
|
|
|
// Fire points changed event
|
|
am.firePlayerAAPointsChangedEvent(characterID, playerState.TotalPoints-points, playerState.TotalPoints)
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetAAPoints returns AA point totals for a player
|
|
func (am *AAManager) GetAAPoints(characterID int32) (int32, int32, int32, error) {
|
|
// Get player state
|
|
playerState := am.getPlayerState(characterID)
|
|
if playerState == nil {
|
|
return 0, 0, 0, fmt.Errorf("player state not found")
|
|
}
|
|
|
|
playerState.mutex.RLock()
|
|
defer playerState.mutex.RUnlock()
|
|
|
|
return playerState.TotalPoints, playerState.SpentPoints, playerState.AvailablePoints, nil
|
|
}
|
|
|
|
// GetAA returns an AA by node ID
|
|
func (am *AAManager) GetAA(nodeID int32) (*AltAdvanceData, error) {
|
|
aaData := am.masterAAList.GetAltAdvancementByNodeID(nodeID)
|
|
if aaData == nil {
|
|
return nil, fmt.Errorf("AA node %d not found", nodeID)
|
|
}
|
|
return aaData, nil
|
|
}
|
|
|
|
// GetAABySpellID returns an AA by spell ID
|
|
func (am *AAManager) GetAABySpellID(spellID int32) (*AltAdvanceData, error) {
|
|
aaData := am.masterAAList.GetAltAdvancement(spellID)
|
|
if aaData == nil {
|
|
return nil, fmt.Errorf("AA with spell ID %d not found", spellID)
|
|
}
|
|
return aaData, nil
|
|
}
|
|
|
|
// GetAAsByGroup returns AAs for a specific group/tab
|
|
func (am *AAManager) GetAAsByGroup(group int8) ([]*AltAdvanceData, error) {
|
|
return am.masterAAList.GetAAsByGroup(group), nil
|
|
}
|
|
|
|
// GetAAsByClass returns AAs available for a specific class
|
|
func (am *AAManager) GetAAsByClass(classID int8) ([]*AltAdvanceData, error) {
|
|
return am.masterAAList.GetAAsByClass(classID), nil
|
|
}
|
|
|
|
// GetSystemStats returns system statistics
|
|
func (am *AAManager) GetSystemStats() *AAManagerStats {
|
|
am.statsMutex.RLock()
|
|
defer am.statsMutex.RUnlock()
|
|
|
|
// Return copy of stats
|
|
stats := am.stats
|
|
return &stats
|
|
}
|
|
|
|
// GetPlayerStats returns player-specific statistics
|
|
func (am *AAManager) GetPlayerStats(characterID int32) map[string]interface{} {
|
|
playerState := am.getPlayerState(characterID)
|
|
if playerState == nil {
|
|
return map[string]interface{}{"error": "player not found"}
|
|
}
|
|
|
|
playerState.mutex.RLock()
|
|
defer playerState.mutex.RUnlock()
|
|
|
|
return map[string]interface{}{
|
|
"character_id": characterID,
|
|
"total_points": playerState.TotalPoints,
|
|
"spent_points": playerState.SpentPoints,
|
|
"available_points": playerState.AvailablePoints,
|
|
"banked_points": playerState.BankedPoints,
|
|
"active_template": playerState.ActiveTemplate,
|
|
"aa_count": len(playerState.AAProgress),
|
|
"template_count": len(playerState.Templates),
|
|
"last_update": playerState.lastUpdate,
|
|
}
|
|
}
|
|
|
|
// SetConfig updates the manager configuration
|
|
func (am *AAManager) SetConfig(config AAManagerConfig) error {
|
|
am.config = config
|
|
return nil
|
|
}
|
|
|
|
// GetConfig returns the current configuration
|
|
func (am *AAManager) GetConfig() AAManagerConfig {
|
|
return am.config
|
|
}
|
|
|
|
// Integration methods
|
|
|
|
// SetDatabase sets the database interface
|
|
func (am *AAManager) SetDatabase(db AADatabase) {
|
|
am.database = db
|
|
}
|
|
|
|
// SetPacketHandler sets the packet handler interface
|
|
func (am *AAManager) SetPacketHandler(handler AAPacketHandler) {
|
|
am.packetHandler = handler
|
|
}
|
|
|
|
// SetEventHandler adds an event handler
|
|
func (am *AAManager) SetEventHandler(handler AAEventHandler) {
|
|
am.eventMutex.Lock()
|
|
defer am.eventMutex.Unlock()
|
|
|
|
am.eventHandlers = append(am.eventHandlers, handler)
|
|
}
|
|
|
|
// SetValidator sets the validator interface
|
|
func (am *AAManager) SetValidator(validator AAValidator) {
|
|
am.validator = validator
|
|
}
|
|
|
|
// SetNotifier sets the notifier interface
|
|
func (am *AAManager) SetNotifier(notifier AANotifier) {
|
|
am.notifier = notifier
|
|
}
|
|
|
|
// SetStatistics sets the statistics interface
|
|
func (am *AAManager) SetStatistics(stats AAStatistics) {
|
|
am.statistics = stats
|
|
}
|
|
|
|
// SetCache sets the cache interface
|
|
func (am *AAManager) SetCache(cache AACache) {
|
|
am.cache = cache
|
|
}
|
|
|
|
// Helper methods
|
|
|
|
// getPlayerState gets a player state from cache
|
|
func (am *AAManager) getPlayerState(characterID int32) *AAPlayerState {
|
|
am.statesMutex.RLock()
|
|
defer am.statesMutex.RUnlock()
|
|
|
|
return am.playerStates[characterID]
|
|
}
|
|
|
|
// performAAPurchase performs the actual AA purchase
|
|
func (am *AAManager) performAAPurchase(playerState *AAPlayerState, aaData *AltAdvanceData, targetRank int8) error {
|
|
// Calculate cost
|
|
pointsCost := int32(aaData.RankCost) * int32(targetRank)
|
|
|
|
// Check if player has enough points
|
|
if playerState.AvailablePoints < pointsCost {
|
|
return fmt.Errorf("insufficient AA points: need %d, have %d", pointsCost, playerState.AvailablePoints)
|
|
}
|
|
|
|
// Update player state
|
|
playerState.mutex.Lock()
|
|
defer playerState.mutex.Unlock()
|
|
|
|
// Create or update progress
|
|
progress := playerState.AAProgress[aaData.NodeID]
|
|
if progress == nil {
|
|
progress = &PlayerAAData{
|
|
CharacterID: playerState.CharacterID,
|
|
NodeID: aaData.NodeID,
|
|
CurrentRank: 0,
|
|
PointsSpent: 0,
|
|
TemplateID: playerState.ActiveTemplate,
|
|
TabID: aaData.Group,
|
|
PurchasedAt: time.Now(),
|
|
UpdatedAt: time.Now(),
|
|
}
|
|
playerState.AAProgress[aaData.NodeID] = progress
|
|
}
|
|
|
|
// Update progress
|
|
progress.CurrentRank = targetRank
|
|
progress.PointsSpent = pointsCost
|
|
progress.UpdatedAt = time.Now()
|
|
|
|
// Update point totals
|
|
playerState.SpentPoints += pointsCost
|
|
playerState.AvailablePoints -= pointsCost
|
|
playerState.needsSync = true
|
|
|
|
return nil
|
|
}
|
|
|
|
// isAAAvailable checks if an AA is available for a player
|
|
func (am *AAManager) isAAAvailable(playerState *AAPlayerState, aaData *AltAdvanceData) bool {
|
|
// Check if player meets minimum level requirement
|
|
// Note: This would normally get player level from the actual player object
|
|
// For now, we'll assume level requirements are met
|
|
|
|
// Check class requirements
|
|
// Note: This would normally check the player's actual class
|
|
// For now, we'll assume class requirements are met
|
|
|
|
// Check prerequisites
|
|
if aaData.RankPrereqID > 0 {
|
|
prereqProgress, exists := playerState.AAProgress[aaData.RankPrereqID]
|
|
if !exists || prereqProgress.CurrentRank < aaData.RankPrereq {
|
|
return false
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
// Background processing loops
|
|
|
|
// updateStatsLoop periodically updates statistics
|
|
func (am *AAManager) updateStatsLoop() {
|
|
defer am.wg.Done()
|
|
|
|
ticker := time.NewTicker(am.config.UpdateInterval)
|
|
defer ticker.Stop()
|
|
|
|
for {
|
|
select {
|
|
case <-ticker.C:
|
|
am.updateStatistics()
|
|
case <-am.stopChan:
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
// autoSaveLoop periodically saves player states
|
|
func (am *AAManager) autoSaveLoop() {
|
|
defer am.wg.Done()
|
|
|
|
ticker := time.NewTicker(am.config.SaveInterval)
|
|
defer ticker.Stop()
|
|
|
|
for {
|
|
select {
|
|
case <-ticker.C:
|
|
am.saveAllPlayerStates()
|
|
case <-am.stopChan:
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
// updateStatistics updates system statistics
|
|
func (am *AAManager) updateStatistics() {
|
|
am.statsMutex.Lock()
|
|
defer am.statsMutex.Unlock()
|
|
|
|
am.statesMutex.RLock()
|
|
am.stats.ActivePlayers = int64(len(am.playerStates))
|
|
|
|
var totalPointsSpent int64
|
|
var totalPurchases int64
|
|
|
|
for _, playerState := range am.playerStates {
|
|
playerState.mutex.RLock()
|
|
totalPointsSpent += int64(playerState.SpentPoints)
|
|
totalPurchases += int64(len(playerState.AAProgress))
|
|
playerState.mutex.RUnlock()
|
|
}
|
|
am.statesMutex.RUnlock()
|
|
|
|
am.stats.TotalPointsSpent = totalPointsSpent
|
|
am.stats.TotalAAPurchases = totalPurchases
|
|
|
|
if am.stats.ActivePlayers > 0 {
|
|
am.stats.AveragePointsSpent = float64(totalPointsSpent) / float64(am.stats.ActivePlayers)
|
|
}
|
|
|
|
am.stats.LastStatsUpdate = time.Now()
|
|
}
|
|
|
|
// saveAllPlayerStates saves all cached player states
|
|
func (am *AAManager) saveAllPlayerStates() {
|
|
if am.database == nil {
|
|
return
|
|
}
|
|
|
|
am.statesMutex.RLock()
|
|
defer am.statesMutex.RUnlock()
|
|
|
|
for characterID, playerState := range am.playerStates {
|
|
if playerState.needsSync {
|
|
if err := am.database.SavePlayerAA(playerState); err != nil {
|
|
am.updateErrorStats("database_errors")
|
|
continue
|
|
}
|
|
playerState.needsSync = false
|
|
}
|
|
}
|
|
}
|
|
|
|
// updateErrorStats updates error statistics
|
|
func (am *AAManager) updateErrorStats(errorType string) {
|
|
am.statsMutex.Lock()
|
|
defer am.statsMutex.Unlock()
|
|
|
|
switch errorType {
|
|
case "validation_errors":
|
|
am.stats.ValidationErrors++
|
|
case "database_errors":
|
|
am.stats.DatabaseErrors++
|
|
case "packet_errors":
|
|
am.stats.PacketErrors++
|
|
}
|
|
}
|
|
|
|
// Event firing methods
|
|
|
|
// fireSystemLoadedEvent fires a system loaded event
|
|
func (am *AAManager) fireSystemLoadedEvent(totalAAs, totalNodes int32) {
|
|
am.eventMutex.RLock()
|
|
defer am.eventMutex.RUnlock()
|
|
|
|
for _, handler := range am.eventHandlers {
|
|
go handler.OnAASystemLoaded(totalAAs, totalNodes)
|
|
}
|
|
}
|
|
|
|
// fireDataReloadedEvent fires a data reloaded event
|
|
func (am *AAManager) fireDataReloadedEvent() {
|
|
am.eventMutex.RLock()
|
|
defer am.eventMutex.RUnlock()
|
|
|
|
for _, handler := range am.eventHandlers {
|
|
go handler.OnAADataReloaded()
|
|
}
|
|
}
|
|
|
|
// firePlayerAALoadedEvent fires a player AA loaded event
|
|
func (am *AAManager) firePlayerAALoadedEvent(characterID int32, playerState *AAPlayerState) {
|
|
am.eventMutex.RLock()
|
|
defer am.eventMutex.RUnlock()
|
|
|
|
for _, handler := range am.eventHandlers {
|
|
go handler.OnPlayerAALoaded(characterID, playerState)
|
|
}
|
|
}
|
|
|
|
// fireAAPurchasedEvent fires an AA purchased event
|
|
func (am *AAManager) fireAAPurchasedEvent(characterID int32, nodeID int32, newRank int8, pointsSpent int32) {
|
|
am.eventMutex.RLock()
|
|
defer am.eventMutex.RUnlock()
|
|
|
|
for _, handler := range am.eventHandlers {
|
|
go handler.OnAAPurchased(characterID, nodeID, newRank, pointsSpent)
|
|
}
|
|
}
|
|
|
|
// fireAARefundedEvent fires an AA refunded event
|
|
func (am *AAManager) fireAARefundedEvent(characterID int32, nodeID int32, oldRank int8, pointsRefunded int32) {
|
|
am.eventMutex.RLock()
|
|
defer am.eventMutex.RUnlock()
|
|
|
|
for _, handler := range am.eventHandlers {
|
|
go handler.OnAARefunded(characterID, nodeID, oldRank, pointsRefunded)
|
|
}
|
|
}
|
|
|
|
// fireTemplateChangedEvent fires a template changed event
|
|
func (am *AAManager) fireTemplateChangedEvent(characterID int32, oldTemplate, newTemplate int8) {
|
|
am.eventMutex.RLock()
|
|
defer am.eventMutex.RUnlock()
|
|
|
|
for _, handler := range am.eventHandlers {
|
|
go handler.OnAATemplateChanged(characterID, oldTemplate, newTemplate)
|
|
}
|
|
}
|
|
|
|
// fireTemplateCreatedEvent fires a template created event
|
|
func (am *AAManager) fireTemplateCreatedEvent(characterID int32, templateID int8, name string) {
|
|
am.eventMutex.RLock()
|
|
defer am.eventMutex.RUnlock()
|
|
|
|
for _, handler := range am.eventHandlers {
|
|
go handler.OnAATemplateCreated(characterID, templateID, name)
|
|
}
|
|
}
|
|
|
|
// firePlayerAAPointsChangedEvent fires a player AA points changed event
|
|
func (am *AAManager) firePlayerAAPointsChangedEvent(characterID int32, oldPoints, newPoints int32) {
|
|
am.eventMutex.RLock()
|
|
defer am.eventMutex.RUnlock()
|
|
|
|
for _, handler := range am.eventHandlers {
|
|
go handler.OnPlayerAAPointsChanged(characterID, oldPoints, newPoints)
|
|
}
|
|
}
|