258 lines
8.4 KiB
Go
258 lines
8.4 KiB
Go
package groups
|
|
|
|
import (
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
// GroupOptions holds group configuration settings
|
|
type GroupOptions struct {
|
|
LootMethod int8 `json:"loot_method" db:"loot_method"`
|
|
LootItemsRarity int8 `json:"loot_items_rarity" db:"loot_items_rarity"`
|
|
AutoSplit int8 `json:"auto_split" db:"auto_split"`
|
|
DefaultYell int8 `json:"default_yell" db:"default_yell"`
|
|
GroupLockMethod int8 `json:"group_lock_method" db:"group_lock_method"`
|
|
GroupAutolock int8 `json:"group_autolock" db:"group_autolock"`
|
|
SoloAutolock int8 `json:"solo_autolock" db:"solo_autolock"`
|
|
AutoLootMethod int8 `json:"auto_loot_method" db:"auto_loot_method"`
|
|
LastLootedIndex int8 `json:"last_looted_index" db:"last_looted_index"`
|
|
}
|
|
|
|
// GroupMemberInfo contains all information about a group member
|
|
type GroupMemberInfo struct {
|
|
// Group and member identification
|
|
GroupID int32 `json:"group_id" db:"group_id"`
|
|
Name string `json:"name" db:"name"`
|
|
Zone string `json:"zone" db:"zone"`
|
|
|
|
// Health and power stats
|
|
HPCurrent int32 `json:"hp_current" db:"hp_current"`
|
|
HPMax int32 `json:"hp_max" db:"hp_max"`
|
|
PowerCurrent int32 `json:"power_current" db:"power_current"`
|
|
PowerMax int32 `json:"power_max" db:"power_max"`
|
|
|
|
// Level and character info
|
|
LevelCurrent int16 `json:"level_current" db:"level_current"`
|
|
LevelMax int16 `json:"level_max" db:"level_max"`
|
|
RaceID int8 `json:"race_id" db:"race_id"`
|
|
ClassID int8 `json:"class_id" db:"class_id"`
|
|
|
|
// Group status
|
|
Leader bool `json:"leader" db:"leader"`
|
|
IsClient bool `json:"is_client" db:"is_client"`
|
|
IsRaidLooter bool `json:"is_raid_looter" db:"is_raid_looter"`
|
|
|
|
// Zone and instance info
|
|
ZoneID int32 `json:"zone_id" db:"zone_id"`
|
|
InstanceID int32 `json:"instance_id" db:"instance_id"`
|
|
|
|
// Mentoring
|
|
MentorTargetCharID int32 `json:"mentor_target_char_id" db:"mentor_target_char_id"`
|
|
|
|
// Network info for cross-server groups
|
|
ClientPeerAddress string `json:"client_peer_address" db:"client_peer_address"`
|
|
ClientPeerPort int16 `json:"client_peer_port" db:"client_peer_port"`
|
|
|
|
// Entity reference (local members only)
|
|
Member Entity `json:"-"`
|
|
|
|
// Client reference (players only) - interface to avoid circular deps
|
|
Client any `json:"-"`
|
|
|
|
// Timestamps
|
|
JoinTime time.Time `json:"join_time" db:"join_time"`
|
|
LastUpdate time.Time `json:"last_update" db:"last_update"`
|
|
}
|
|
|
|
// Group is now defined in group.go - this type definition removed to avoid duplication
|
|
|
|
// GroupMessage represents a message sent to the group
|
|
type GroupMessage struct {
|
|
Type int8 `json:"type"`
|
|
Channel int16 `json:"channel"`
|
|
Message string `json:"message"`
|
|
FromName string `json:"from_name"`
|
|
Language int32 `json:"language"`
|
|
Timestamp time.Time `json:"timestamp"`
|
|
ExcludeClient any `json:"-"`
|
|
}
|
|
|
|
// GroupUpdate represents a group update event
|
|
type GroupUpdate struct {
|
|
Type int8 `json:"type"`
|
|
GroupID int32 `json:"group_id"`
|
|
MemberInfo *GroupMemberInfo `json:"member_info,omitempty"`
|
|
Options *GroupOptions `json:"options,omitempty"`
|
|
RaidGroups []int32 `json:"raid_groups,omitempty"`
|
|
ForceRaidUpdate bool `json:"force_raid_update"`
|
|
ExcludeClient any `json:"-"`
|
|
Timestamp time.Time `json:"timestamp"`
|
|
}
|
|
|
|
// GroupInvite represents a pending group invitation
|
|
type GroupInvite struct {
|
|
InviterName string `json:"inviter_name"`
|
|
InviteeName string `json:"invitee_name"`
|
|
GroupID int32 `json:"group_id"`
|
|
IsRaidInvite bool `json:"is_raid_invite"`
|
|
CreatedTime time.Time `json:"created_time"`
|
|
ExpiresTime time.Time `json:"expires_time"`
|
|
}
|
|
|
|
// GroupManager manages all player groups
|
|
type GroupManager struct {
|
|
// Group storage
|
|
groups map[int32]*Group
|
|
groupsMutex sync.RWMutex
|
|
|
|
// Group ID generation
|
|
nextGroupID int32
|
|
nextGroupIDMutex sync.Mutex
|
|
|
|
// Pending invitations
|
|
pendingInvites map[string]*GroupInvite
|
|
raidPendingInvites map[string]*GroupInvite
|
|
invitesMutex sync.RWMutex
|
|
|
|
// Event handlers
|
|
eventHandlers []GroupEventHandler
|
|
eventHandlersMutex sync.RWMutex
|
|
|
|
// Configuration
|
|
config GroupManagerConfig
|
|
|
|
// Statistics
|
|
stats GroupManagerStats
|
|
statsMutex sync.RWMutex
|
|
|
|
// Background processing
|
|
stopChan chan struct{}
|
|
wg sync.WaitGroup
|
|
|
|
// Integration interfaces
|
|
database GroupDatabase
|
|
packetHandler GroupPacketHandler
|
|
validator GroupValidator
|
|
notifier GroupNotifier
|
|
}
|
|
|
|
// GroupManagerConfig holds configuration for the group manager
|
|
type GroupManagerConfig struct {
|
|
MaxGroups int32 `json:"max_groups"`
|
|
MaxRaidGroups int32 `json:"max_raid_groups"`
|
|
InviteTimeout time.Duration `json:"invite_timeout"`
|
|
UpdateInterval time.Duration `json:"update_interval"`
|
|
BuffUpdateInterval time.Duration `json:"buff_update_interval"`
|
|
EnableCrossServer bool `json:"enable_cross_server"`
|
|
EnableRaids bool `json:"enable_raids"`
|
|
EnableQuestSharing bool `json:"enable_quest_sharing"`
|
|
EnableAutoInvite bool `json:"enable_auto_invite"`
|
|
EnableStatistics bool `json:"enable_statistics"`
|
|
}
|
|
|
|
// GroupManagerStats holds statistics about group management
|
|
type GroupManagerStats struct {
|
|
TotalGroups int64 `json:"total_groups"`
|
|
ActiveGroups int64 `json:"active_groups"`
|
|
TotalRaids int64 `json:"total_raids"`
|
|
ActiveRaids int64 `json:"active_raids"`
|
|
TotalInvites int64 `json:"total_invites"`
|
|
AcceptedInvites int64 `json:"accepted_invites"`
|
|
DeclinedInvites int64 `json:"declined_invites"`
|
|
ExpiredInvites int64 `json:"expired_invites"`
|
|
AverageGroupSize float64 `json:"average_group_size"`
|
|
AverageGroupDuration time.Duration `json:"average_group_duration"`
|
|
LastStatsUpdate time.Time `json:"last_stats_update"`
|
|
}
|
|
|
|
// Default group options
|
|
func DefaultGroupOptions() GroupOptions {
|
|
return GroupOptions{
|
|
LootMethod: LOOT_METHOD_ROUND_ROBIN,
|
|
LootItemsRarity: LOOT_RARITY_COMMON,
|
|
AutoSplit: AUTO_SPLIT_DISABLED,
|
|
DefaultYell: DEFAULT_YELL_DISABLED,
|
|
GroupLockMethod: LOCK_METHOD_OPEN,
|
|
GroupAutolock: AUTO_LOCK_DISABLED,
|
|
SoloAutolock: AUTO_LOCK_DISABLED,
|
|
AutoLootMethod: AUTO_LOOT_DISABLED,
|
|
LastLootedIndex: 0,
|
|
}
|
|
}
|
|
|
|
// Copy creates a copy of GroupMemberInfo
|
|
func (gmi *GroupMemberInfo) Copy() *GroupMemberInfo {
|
|
copy := *gmi
|
|
return ©
|
|
}
|
|
|
|
// IsValid checks if the group member info is valid
|
|
func (gmi *GroupMemberInfo) IsValid() bool {
|
|
return gmi.GroupID > 0 && len(gmi.Name) > 0
|
|
}
|
|
|
|
// UpdateStats updates member stats from entity
|
|
func (gmi *GroupMemberInfo) UpdateStats() {
|
|
if gmi.Member == nil {
|
|
return
|
|
}
|
|
|
|
entity := gmi.Member
|
|
gmi.HPCurrent = entity.GetHP()
|
|
gmi.HPMax = entity.GetTotalHP()
|
|
gmi.PowerCurrent = entity.GetPower()
|
|
gmi.PowerMax = entity.GetTotalPower()
|
|
gmi.LevelCurrent = int16(entity.GetLevel())
|
|
gmi.LevelMax = int16(entity.GetLevel()) // TODO: Get actual max level
|
|
gmi.LastUpdate = time.Now()
|
|
|
|
// Update zone info if entity has zone
|
|
if zone := entity.GetZone(); zone != nil {
|
|
gmi.ZoneID = zone.GetZoneID()
|
|
gmi.InstanceID = zone.GetInstanceID()
|
|
gmi.Zone = zone.GetZoneName()
|
|
}
|
|
}
|
|
|
|
// Copy creates a copy of GroupOptions
|
|
func (go_opts *GroupOptions) Copy() GroupOptions {
|
|
return *go_opts
|
|
}
|
|
|
|
// IsValid checks if group options are valid
|
|
func (go_opts *GroupOptions) IsValid() bool {
|
|
return go_opts.LootMethod >= LOOT_METHOD_LEADER_ONLY && go_opts.LootMethod <= LOOT_METHOD_LOTTO &&
|
|
go_opts.LootItemsRarity >= LOOT_RARITY_COMMON && go_opts.LootItemsRarity <= LOOT_RARITY_FABLED
|
|
}
|
|
|
|
// NewGroupMessage creates a new group message
|
|
func NewGroupMessage(msgType int8, channel int16, message, fromName string, language int32) *GroupMessage {
|
|
return &GroupMessage{
|
|
Type: msgType,
|
|
Channel: channel,
|
|
Message: message,
|
|
FromName: fromName,
|
|
Language: language,
|
|
Timestamp: time.Now(),
|
|
}
|
|
}
|
|
|
|
// NewGroupUpdate creates a new group update
|
|
func NewGroupUpdate(updateType int8, groupID int32) *GroupUpdate {
|
|
return &GroupUpdate{
|
|
Type: updateType,
|
|
GroupID: groupID,
|
|
Timestamp: time.Now(),
|
|
}
|
|
}
|
|
|
|
// IsExpired checks if the group invite has expired
|
|
func (gi *GroupInvite) IsExpired() bool {
|
|
return time.Now().After(gi.ExpiresTime)
|
|
}
|
|
|
|
// TimeRemaining returns the remaining time for the invite
|
|
func (gi *GroupInvite) TimeRemaining() time.Duration {
|
|
return time.Until(gi.ExpiresTime)
|
|
}
|