eq2go/internal/groups/types.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 &copy
}
// 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)
}