782 lines
19 KiB
Go
782 lines
19 KiB
Go
package groups
|
|
|
|
import (
|
|
"fmt"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
// Group represents a player group with embedded database operations
|
|
type Group struct {
|
|
// Core fields
|
|
GroupID int32 `json:"group_id" db:"group_id"`
|
|
Options GroupOptions `json:"options"`
|
|
Members []*GroupMemberInfo `json:"members"`
|
|
RaidGroups []int32 `json:"raid_groups"`
|
|
CreatedTime time.Time `json:"created_time" db:"created_time"`
|
|
LastActivity time.Time `json:"last_activity" db:"last_activity"`
|
|
Disbanded bool `json:"disbanded" db:"disbanded"`
|
|
|
|
// Internal fields
|
|
membersMutex sync.RWMutex `json:"-"`
|
|
raidGroupsMutex sync.RWMutex `json:"-"`
|
|
optionsMutex sync.RWMutex `json:"-"`
|
|
activityMutex sync.RWMutex `json:"-"`
|
|
disbandMutex sync.RWMutex `json:"-"`
|
|
|
|
// Communication channels
|
|
messageQueue chan *GroupMessage `json:"-"`
|
|
updateQueue chan *GroupUpdate `json:"-"`
|
|
|
|
// Background processing
|
|
stopChan chan struct{} `json:"-"`
|
|
wg sync.WaitGroup `json:"-"`
|
|
|
|
// Database integration - embedded operations
|
|
db any `json:"-"` // Database connection
|
|
isNew bool `json:"-"` // Flag for new groups
|
|
}
|
|
|
|
// New creates a new group
|
|
func New(db any) *Group {
|
|
group := &Group{
|
|
GroupID: 0, // Will be set when saved
|
|
Options: DefaultGroupOptions(),
|
|
Members: make([]*GroupMemberInfo, 0, MAX_GROUP_SIZE),
|
|
RaidGroups: make([]int32, 0),
|
|
CreatedTime: time.Now(),
|
|
LastActivity: time.Now(),
|
|
Disbanded: false,
|
|
messageQueue: make(chan *GroupMessage, 100),
|
|
updateQueue: make(chan *GroupUpdate, 100),
|
|
stopChan: make(chan struct{}),
|
|
db: db,
|
|
isNew: true,
|
|
}
|
|
|
|
// Start background processing
|
|
group.wg.Add(1)
|
|
go group.processMessages()
|
|
|
|
return group
|
|
}
|
|
|
|
// NewGroup creates a new group with specified ID and options
|
|
func NewGroup(id int32, options *GroupOptions, db any) *Group {
|
|
if options == nil {
|
|
defaultOpts := DefaultGroupOptions()
|
|
options = &defaultOpts
|
|
}
|
|
|
|
group := &Group{
|
|
GroupID: id,
|
|
Options: *options,
|
|
Members: make([]*GroupMemberInfo, 0, MAX_GROUP_SIZE),
|
|
RaidGroups: make([]int32, 0),
|
|
CreatedTime: time.Now(),
|
|
LastActivity: time.Now(),
|
|
Disbanded: false,
|
|
messageQueue: make(chan *GroupMessage, 100),
|
|
updateQueue: make(chan *GroupUpdate, 100),
|
|
stopChan: make(chan struct{}),
|
|
db: db,
|
|
isNew: false,
|
|
}
|
|
|
|
// Start background processing
|
|
group.wg.Add(1)
|
|
go group.processMessages()
|
|
|
|
return group
|
|
}
|
|
|
|
// GetID returns the group ID (implements Identifiable interface)
|
|
func (g *Group) GetID() int32 {
|
|
return g.GroupID
|
|
}
|
|
|
|
// Save saves the group to the database
|
|
func (g *Group) Save() error {
|
|
// TODO: Implement database save logic
|
|
// This would require integration with the actual database system
|
|
return nil
|
|
}
|
|
|
|
// Delete removes the group from the database
|
|
func (g *Group) Delete() error {
|
|
// Disband the group first
|
|
g.Disband()
|
|
|
|
// TODO: Implement database delete logic
|
|
// This would require integration with the actual database system
|
|
return nil
|
|
}
|
|
|
|
// Reload refreshes the group from the database
|
|
func (g *Group) Reload() error {
|
|
// TODO: Implement database reload logic
|
|
// This would require integration with the actual database system
|
|
return nil
|
|
}
|
|
|
|
// GetSize returns the number of members in the group
|
|
func (g *Group) GetSize() int32 {
|
|
g.membersMutex.RLock()
|
|
defer g.membersMutex.RUnlock()
|
|
|
|
return int32(len(g.Members))
|
|
}
|
|
|
|
// GetMembers returns a copy of the member list
|
|
func (g *Group) GetMembers() []*GroupMemberInfo {
|
|
g.membersMutex.RLock()
|
|
defer g.membersMutex.RUnlock()
|
|
|
|
members := make([]*GroupMemberInfo, len(g.Members))
|
|
for i, member := range g.Members {
|
|
members[i] = member.Copy()
|
|
}
|
|
|
|
return members
|
|
}
|
|
|
|
// AddMember adds a new member to the group
|
|
func (g *Group) AddMember(member Entity, isLeader bool) error {
|
|
if member == nil {
|
|
return fmt.Errorf("member cannot be nil")
|
|
}
|
|
|
|
g.disbandMutex.RLock()
|
|
if g.Disbanded {
|
|
g.disbandMutex.RUnlock()
|
|
return fmt.Errorf("group has been disbanded")
|
|
}
|
|
g.disbandMutex.RUnlock()
|
|
|
|
g.membersMutex.Lock()
|
|
defer g.membersMutex.Unlock()
|
|
|
|
// Check if group is full
|
|
if len(g.Members) >= MAX_GROUP_SIZE {
|
|
return fmt.Errorf("group is full")
|
|
}
|
|
|
|
// Check if member is already in the group
|
|
for _, gmi := range g.Members {
|
|
if gmi.Member == member {
|
|
return fmt.Errorf("member is already in the group")
|
|
}
|
|
}
|
|
|
|
// Create new group member info
|
|
gmi := &GroupMemberInfo{
|
|
GroupID: g.GroupID,
|
|
Name: member.GetName(),
|
|
Leader: isLeader,
|
|
Member: member,
|
|
IsClient: member.IsPlayer(),
|
|
JoinTime: time.Now(),
|
|
LastUpdate: time.Now(),
|
|
}
|
|
|
|
// Update member stats from entity
|
|
gmi.UpdateStats()
|
|
|
|
// Set client reference if it's a player
|
|
if member.IsPlayer() {
|
|
// TODO: Get client reference from player
|
|
// gmi.Client = member.GetClient()
|
|
}
|
|
|
|
// Update zone information
|
|
if zone := member.GetZone(); zone != nil {
|
|
gmi.ZoneID = zone.GetZoneID()
|
|
gmi.InstanceID = zone.GetInstanceID()
|
|
gmi.Zone = zone.GetZoneName()
|
|
}
|
|
|
|
// Add to members list
|
|
g.Members = append(g.Members, gmi)
|
|
g.updateLastActivity()
|
|
|
|
// Set group reference on the entity
|
|
// TODO: Set group member info on entity
|
|
// member.SetGroupMemberInfo(gmi)
|
|
|
|
// Send group update
|
|
g.sendGroupUpdate(nil, false)
|
|
|
|
return nil
|
|
}
|
|
|
|
// AddMemberFromPeer adds a member from a peer server
|
|
func (g *Group) AddMemberFromPeer(name string, isLeader, isClient bool, classID int8,
|
|
hpCur, hpMax int32, levelCur, levelMax int16, powerCur, powerMax int32,
|
|
raceID int8, zoneName string, mentorTargetCharID int32,
|
|
zoneID, instanceID int32, peerAddress string, peerPort int16, isRaidLooter bool) error {
|
|
|
|
g.disbandMutex.RLock()
|
|
if g.Disbanded {
|
|
g.disbandMutex.RUnlock()
|
|
return fmt.Errorf("group has been disbanded")
|
|
}
|
|
g.disbandMutex.RUnlock()
|
|
|
|
g.membersMutex.Lock()
|
|
defer g.membersMutex.Unlock()
|
|
|
|
// Check if group is full
|
|
if len(g.Members) >= MAX_GROUP_SIZE {
|
|
return fmt.Errorf("group is full")
|
|
}
|
|
|
|
// Create new group member info for peer member
|
|
gmi := &GroupMemberInfo{
|
|
GroupID: g.GroupID,
|
|
Name: name,
|
|
Zone: zoneName,
|
|
HPCurrent: hpCur,
|
|
HPMax: hpMax,
|
|
PowerCurrent: powerCur,
|
|
PowerMax: powerMax,
|
|
LevelCurrent: levelCur,
|
|
LevelMax: levelMax,
|
|
RaceID: raceID,
|
|
ClassID: classID,
|
|
Leader: isLeader,
|
|
IsClient: isClient,
|
|
ZoneID: zoneID,
|
|
InstanceID: instanceID,
|
|
MentorTargetCharID: mentorTargetCharID,
|
|
ClientPeerAddress: peerAddress,
|
|
ClientPeerPort: peerPort,
|
|
IsRaidLooter: isRaidLooter,
|
|
Member: nil, // No local entity reference for peer members
|
|
Client: nil, // No local client reference for peer members
|
|
JoinTime: time.Now(),
|
|
LastUpdate: time.Now(),
|
|
}
|
|
|
|
// Add to members list
|
|
g.Members = append(g.Members, gmi)
|
|
g.updateLastActivity()
|
|
|
|
// Send group update
|
|
g.sendGroupUpdate(nil, false)
|
|
|
|
return nil
|
|
}
|
|
|
|
// RemoveMember removes a member from the group
|
|
func (g *Group) RemoveMember(member Entity) error {
|
|
if member == nil {
|
|
return fmt.Errorf("member cannot be nil")
|
|
}
|
|
|
|
g.membersMutex.Lock()
|
|
defer g.membersMutex.Unlock()
|
|
|
|
// Find and remove the member
|
|
for i, gmi := range g.Members {
|
|
if gmi.Member == member {
|
|
// Clear group reference on entity
|
|
// TODO: Clear group member info on entity
|
|
// member.SetGroupMemberInfo(nil)
|
|
|
|
// Remove from slice
|
|
g.Members = append(g.Members[:i], g.Members[i+1:]...)
|
|
g.updateLastActivity()
|
|
|
|
// If this was a bot, camp it
|
|
// TODO: Handle bot camping
|
|
// if member.IsBot() {
|
|
// member.Camp()
|
|
// }
|
|
|
|
// Send group update
|
|
g.sendGroupUpdate(nil, false)
|
|
|
|
return nil
|
|
}
|
|
}
|
|
|
|
return fmt.Errorf("member not found in group")
|
|
}
|
|
|
|
// RemoveMemberByName removes a member by name (for peer members)
|
|
func (g *Group) RemoveMemberByName(name string, isClient bool, charID int32) error {
|
|
g.membersMutex.Lock()
|
|
defer g.membersMutex.Unlock()
|
|
|
|
// Find and remove the member
|
|
for i, gmi := range g.Members {
|
|
if gmi.Name == name && gmi.IsClient == isClient {
|
|
// Handle mentorship cleanup
|
|
if isClient && charID > 0 {
|
|
for _, otherGmi := range g.Members {
|
|
if otherGmi.MentorTargetCharID == charID {
|
|
otherGmi.MentorTargetCharID = 0
|
|
// TODO: Enable reset mentorship on client
|
|
// if otherGmi.Client != nil {
|
|
// otherGmi.Client.GetPlayer().EnableResetMentorship()
|
|
// }
|
|
}
|
|
}
|
|
}
|
|
|
|
// Remove from slice
|
|
g.Members = append(g.Members[:i], g.Members[i+1:]...)
|
|
g.updateLastActivity()
|
|
|
|
// Send group update
|
|
g.sendGroupUpdate(nil, false)
|
|
|
|
return nil
|
|
}
|
|
}
|
|
|
|
return fmt.Errorf("member not found in group")
|
|
}
|
|
|
|
// Disband disbands the group and removes all members
|
|
func (g *Group) Disband() {
|
|
g.disbandMutex.Lock()
|
|
if g.Disbanded {
|
|
g.disbandMutex.Unlock()
|
|
return
|
|
}
|
|
g.Disbanded = true
|
|
g.disbandMutex.Unlock()
|
|
|
|
// Stop background processing first to avoid deadlock
|
|
close(g.stopChan)
|
|
g.wg.Wait()
|
|
|
|
g.membersMutex.Lock()
|
|
defer g.membersMutex.Unlock()
|
|
|
|
// Clear raid groups
|
|
g.raidGroupsMutex.Lock()
|
|
g.RaidGroups = nil
|
|
g.raidGroupsMutex.Unlock()
|
|
|
|
// Remove all members
|
|
for _, gmi := range g.Members {
|
|
if gmi.Member != nil {
|
|
// Clear group reference on entity
|
|
// TODO: Clear group member info on entity
|
|
// gmi.Member.SetGroupMemberInfo(nil)
|
|
|
|
// Handle bot camping
|
|
// TODO: Handle bot camping
|
|
// if gmi.Member.IsBot() {
|
|
// gmi.Member.Camp()
|
|
// }
|
|
}
|
|
|
|
// Handle mentorship cleanup
|
|
if gmi.MentorTargetCharID > 0 {
|
|
// TODO: Enable reset mentorship on client
|
|
// if gmi.Client != nil {
|
|
// gmi.Client.GetPlayer().EnableResetMentorship()
|
|
// }
|
|
}
|
|
|
|
// TODO: Set character/raid sheet changed flags
|
|
// if gmi.Client != nil {
|
|
// gmi.Client.GetPlayer().SetCharSheetChanged(true)
|
|
// if isInRaid {
|
|
// gmi.Client.GetPlayer().SetRaidSheetChanged(true)
|
|
// }
|
|
// }
|
|
}
|
|
|
|
// Clear members list
|
|
g.Members = nil
|
|
}
|
|
|
|
// SendGroupUpdate sends an update to all group members
|
|
func (g *Group) SendGroupUpdate(excludeClient any, forceRaidUpdate bool) {
|
|
g.sendGroupUpdate(excludeClient, forceRaidUpdate)
|
|
}
|
|
|
|
// sendGroupUpdate internal method to send group updates
|
|
func (g *Group) sendGroupUpdate(excludeClient any, forceRaidUpdate bool) {
|
|
update := NewGroupUpdate(GROUP_UPDATE_FLAG_MEMBER_LIST, g.GroupID)
|
|
update.ExcludeClient = excludeClient
|
|
update.ForceRaidUpdate = forceRaidUpdate
|
|
|
|
select {
|
|
case g.updateQueue <- update:
|
|
default:
|
|
// Queue is full, drop the update
|
|
}
|
|
}
|
|
|
|
// SimpleGroupMessage sends a simple message to all group members
|
|
func (g *Group) SimpleGroupMessage(message string) {
|
|
msg := NewGroupMessage(GROUP_MESSAGE_TYPE_SYSTEM, CHANNEL_GROUP_CHAT, message, "", 0)
|
|
|
|
select {
|
|
case g.messageQueue <- msg:
|
|
default:
|
|
// Queue is full, drop the message
|
|
}
|
|
}
|
|
|
|
// SendGroupMessage sends a formatted message to all group members
|
|
func (g *Group) SendGroupMessage(msgType int8, message string) {
|
|
msg := NewGroupMessage(msgType, CHANNEL_GROUP_CHAT, message, "", 0)
|
|
|
|
select {
|
|
case g.messageQueue <- msg:
|
|
default:
|
|
// Queue is full, drop the message
|
|
}
|
|
}
|
|
|
|
// GroupChatMessage sends a chat message from a member to the group
|
|
func (g *Group) GroupChatMessage(from Entity, language int32, message string, channel int16) {
|
|
if from == nil {
|
|
return
|
|
}
|
|
|
|
msg := NewGroupMessage(GROUP_MESSAGE_TYPE_CHAT, channel, message, from.GetName(), language)
|
|
|
|
select {
|
|
case g.messageQueue <- msg:
|
|
default:
|
|
// Queue is full, drop the message
|
|
}
|
|
}
|
|
|
|
// GroupChatMessageFromName sends a chat message from a named sender to the group
|
|
func (g *Group) GroupChatMessageFromName(fromName string, language int32, message string, channel int16) {
|
|
msg := NewGroupMessage(GROUP_MESSAGE_TYPE_CHAT, channel, message, fromName, language)
|
|
|
|
select {
|
|
case g.messageQueue <- msg:
|
|
default:
|
|
// Queue is full, drop the message
|
|
}
|
|
}
|
|
|
|
// MakeLeader changes the group leader
|
|
func (g *Group) MakeLeader(newLeader Entity) error {
|
|
if newLeader == nil {
|
|
return fmt.Errorf("new leader cannot be nil")
|
|
}
|
|
|
|
g.membersMutex.Lock()
|
|
defer g.membersMutex.Unlock()
|
|
|
|
var newLeaderGMI *GroupMemberInfo
|
|
|
|
// Find the new leader and update leadership
|
|
for _, gmi := range g.Members {
|
|
if gmi.Member == newLeader {
|
|
newLeaderGMI = gmi
|
|
gmi.Leader = true
|
|
} else if gmi.Leader {
|
|
// Remove leadership from current leader
|
|
gmi.Leader = false
|
|
}
|
|
}
|
|
|
|
if newLeaderGMI == nil {
|
|
return fmt.Errorf("new leader not found in group")
|
|
}
|
|
|
|
g.updateLastActivity()
|
|
|
|
// Send group update
|
|
g.sendGroupUpdate(nil, false)
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetLeaderName returns the name of the group leader
|
|
func (g *Group) GetLeaderName() string {
|
|
g.membersMutex.RLock()
|
|
defer g.membersMutex.RUnlock()
|
|
|
|
for _, gmi := range g.Members {
|
|
if gmi.Leader {
|
|
return gmi.Name
|
|
}
|
|
}
|
|
|
|
return ""
|
|
}
|
|
|
|
// ShareQuestWithGroup shares a quest with all group members
|
|
func (g *Group) ShareQuestWithGroup(questSharer any, quest any) bool {
|
|
// TODO: Implement quest sharing
|
|
// This would require integration with the quest system
|
|
return false
|
|
}
|
|
|
|
// UpdateGroupMemberInfo updates information for a specific member
|
|
func (g *Group) UpdateGroupMemberInfo(member Entity, groupMembersLocked bool) {
|
|
if member == nil {
|
|
return
|
|
}
|
|
|
|
if !groupMembersLocked {
|
|
g.membersMutex.Lock()
|
|
defer g.membersMutex.Unlock()
|
|
}
|
|
|
|
// Find the member and update their info
|
|
for _, gmi := range g.Members {
|
|
if gmi.Member == member {
|
|
gmi.UpdateStats()
|
|
g.updateLastActivity()
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
// GetGroupMemberByPosition returns a group member at a specific position
|
|
func (g *Group) GetGroupMemberByPosition(seeker Entity, mappedPosition int32) Entity {
|
|
g.membersMutex.RLock()
|
|
defer g.membersMutex.RUnlock()
|
|
|
|
if mappedPosition < 0 || int(mappedPosition) >= len(g.Members) {
|
|
return nil
|
|
}
|
|
|
|
return g.Members[mappedPosition].Member
|
|
}
|
|
|
|
// GetGroupOptions returns a copy of the group options
|
|
func (g *Group) GetGroupOptions() GroupOptions {
|
|
g.optionsMutex.RLock()
|
|
defer g.optionsMutex.RUnlock()
|
|
|
|
return g.Options.Copy()
|
|
}
|
|
|
|
// SetGroupOptions sets new group options
|
|
func (g *Group) SetGroupOptions(options *GroupOptions) error {
|
|
if options == nil {
|
|
return fmt.Errorf("options cannot be nil")
|
|
}
|
|
|
|
if !options.IsValid() {
|
|
return fmt.Errorf("invalid group options")
|
|
}
|
|
|
|
g.optionsMutex.Lock()
|
|
g.Options = *options
|
|
g.optionsMutex.Unlock()
|
|
|
|
g.updateLastActivity()
|
|
|
|
// Send group update for options change
|
|
update := NewGroupUpdate(GROUP_UPDATE_FLAG_OPTIONS, g.GroupID)
|
|
update.Options = options
|
|
|
|
select {
|
|
case g.updateQueue <- update:
|
|
default:
|
|
// Queue is full, drop the update
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetLastLooterIndex returns the last looter index
|
|
func (g *Group) GetLastLooterIndex() int8 {
|
|
g.optionsMutex.RLock()
|
|
defer g.optionsMutex.RUnlock()
|
|
|
|
return g.Options.LastLootedIndex
|
|
}
|
|
|
|
// SetNextLooterIndex sets the next looter index
|
|
func (g *Group) SetNextLooterIndex(newIndex int8) {
|
|
g.optionsMutex.Lock()
|
|
g.Options.LastLootedIndex = newIndex
|
|
g.optionsMutex.Unlock()
|
|
|
|
g.updateLastActivity()
|
|
}
|
|
|
|
// Raid functionality
|
|
|
|
// GetRaidGroups returns a copy of the raid groups list
|
|
func (g *Group) GetRaidGroups() []int32 {
|
|
g.raidGroupsMutex.RLock()
|
|
defer g.raidGroupsMutex.RUnlock()
|
|
|
|
if g.RaidGroups == nil {
|
|
return []int32{}
|
|
}
|
|
|
|
groups := make([]int32, len(g.RaidGroups))
|
|
copy(groups, g.RaidGroups)
|
|
return groups
|
|
}
|
|
|
|
// ReplaceRaidGroups replaces the entire raid groups list
|
|
func (g *Group) ReplaceRaidGroups(groups []int32) {
|
|
g.raidGroupsMutex.Lock()
|
|
defer g.raidGroupsMutex.Unlock()
|
|
|
|
if groups == nil {
|
|
g.RaidGroups = make([]int32, 0)
|
|
} else {
|
|
g.RaidGroups = make([]int32, len(groups))
|
|
copy(g.RaidGroups, groups)
|
|
}
|
|
|
|
g.updateLastActivity()
|
|
}
|
|
|
|
// IsInRaidGroup checks if this group is in a raid with the specified group
|
|
func (g *Group) IsInRaidGroup(groupID int32, isLeaderGroup bool) bool {
|
|
g.raidGroupsMutex.RLock()
|
|
defer g.raidGroupsMutex.RUnlock()
|
|
|
|
for _, id := range g.RaidGroups {
|
|
if id == groupID {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
// AddGroupToRaid adds a group to the raid
|
|
func (g *Group) AddGroupToRaid(groupID int32) {
|
|
g.raidGroupsMutex.Lock()
|
|
defer g.raidGroupsMutex.Unlock()
|
|
|
|
// Check if already in raid
|
|
for _, id := range g.RaidGroups {
|
|
if id == groupID {
|
|
return
|
|
}
|
|
}
|
|
|
|
g.RaidGroups = append(g.RaidGroups, groupID)
|
|
g.updateLastActivity()
|
|
}
|
|
|
|
// RemoveGroupFromRaid removes a group from the raid
|
|
func (g *Group) RemoveGroupFromRaid(groupID int32) {
|
|
g.raidGroupsMutex.Lock()
|
|
defer g.raidGroupsMutex.Unlock()
|
|
|
|
for i, id := range g.RaidGroups {
|
|
if id == groupID {
|
|
g.RaidGroups = append(g.RaidGroups[:i], g.RaidGroups[i+1:]...)
|
|
g.updateLastActivity()
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
// IsGroupRaid checks if this group is part of a raid
|
|
func (g *Group) IsGroupRaid() bool {
|
|
g.raidGroupsMutex.RLock()
|
|
defer g.raidGroupsMutex.RUnlock()
|
|
|
|
return len(g.RaidGroups) > 0
|
|
}
|
|
|
|
// ClearGroupRaid clears all raid associations
|
|
func (g *Group) ClearGroupRaid() {
|
|
g.raidGroupsMutex.Lock()
|
|
defer g.raidGroupsMutex.Unlock()
|
|
|
|
g.RaidGroups = make([]int32, 0)
|
|
g.updateLastActivity()
|
|
}
|
|
|
|
// IsDisbanded checks if the group has been disbanded
|
|
func (g *Group) IsDisbanded() bool {
|
|
g.disbandMutex.RLock()
|
|
defer g.disbandMutex.RUnlock()
|
|
|
|
return g.Disbanded
|
|
}
|
|
|
|
// GetCreatedTime returns when the group was created
|
|
func (g *Group) GetCreatedTime() time.Time {
|
|
return g.CreatedTime
|
|
}
|
|
|
|
// GetLastActivity returns the last activity time
|
|
func (g *Group) GetLastActivity() time.Time {
|
|
g.activityMutex.RLock()
|
|
defer g.activityMutex.RUnlock()
|
|
return g.LastActivity
|
|
}
|
|
|
|
// updateLastActivity updates the last activity timestamp
|
|
func (g *Group) updateLastActivity() {
|
|
g.activityMutex.Lock()
|
|
defer g.activityMutex.Unlock()
|
|
g.LastActivity = time.Now()
|
|
}
|
|
|
|
// processMessages processes messages and updates in the background
|
|
func (g *Group) processMessages() {
|
|
defer g.wg.Done()
|
|
|
|
for {
|
|
select {
|
|
case msg := <-g.messageQueue:
|
|
g.handleMessage(msg)
|
|
case update := <-g.updateQueue:
|
|
g.handleUpdate(update)
|
|
case <-g.stopChan:
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
// handleMessage handles a group message
|
|
func (g *Group) handleMessage(msg *GroupMessage) {
|
|
if msg == nil {
|
|
return
|
|
}
|
|
|
|
g.membersMutex.RLock()
|
|
defer g.membersMutex.RUnlock()
|
|
|
|
// Send message to all group members except the excluded client
|
|
for _, gmi := range g.Members {
|
|
if gmi.Client != nil && gmi.Client != msg.ExcludeClient {
|
|
// TODO: Send message to client
|
|
// This would require integration with the client system
|
|
}
|
|
}
|
|
}
|
|
|
|
// handleUpdate handles a group update
|
|
func (g *Group) handleUpdate(update *GroupUpdate) {
|
|
if update == nil {
|
|
return
|
|
}
|
|
|
|
g.membersMutex.RLock()
|
|
defer g.membersMutex.RUnlock()
|
|
|
|
// Send update to all group members except the excluded client
|
|
for _, gmi := range g.Members {
|
|
if gmi.Client != nil && gmi.Client != update.ExcludeClient {
|
|
// TODO: Send update to client
|
|
// This would require integration with the client system
|
|
// if gmi.Client != nil {
|
|
// gmi.Client.GetPlayer().SetCharSheetChanged(true)
|
|
// if isInRaid || update.ForceRaidUpdate {
|
|
// gmi.Client.GetPlayer().SetRaidSheetChanged(true)
|
|
// }
|
|
// }
|
|
}
|
|
}
|
|
}
|