459 lines
12 KiB
Go
459 lines
12 KiB
Go
package main
|
|
|
|
import (
|
|
"cs"
|
|
"f5"
|
|
"fmt"
|
|
"math/rand"
|
|
"q5"
|
|
)
|
|
|
|
type GuildMgr struct {
|
|
cs.MsgHandlerImpl
|
|
Guilds map[int64]*Guild // 公会ID -> 公会列表
|
|
pendingReqs map[int64]map[string]bool // 公会ID -> 申请者账户ID -> bool
|
|
Logs map[int64][]*GuildLog // 公会ID -> 公会日志
|
|
}
|
|
|
|
func NewGuildMgr() *GuildMgr {
|
|
return &GuildMgr{
|
|
Guilds: make(map[int64]*Guild),
|
|
pendingReqs: make(map[int64]map[string]bool),
|
|
Logs: make(map[int64][]*GuildLog, DefaultLogs),
|
|
}
|
|
}
|
|
|
|
func (gm *GuildMgr) init() {
|
|
gm.pendingReqs = make(map[int64]map[string]bool)
|
|
// 加载公会
|
|
gm.loadGuildFromDB()
|
|
// 加载公会成员
|
|
gm.loadGuildMemberFromDB()
|
|
// 加载公会申请者列表
|
|
gm.loadPendingReqsFromDB()
|
|
}
|
|
|
|
// CreateGuild 创建公会
|
|
func (gm *GuildMgr) CreateGuild(name string, leaderID string) (int64, error) {
|
|
// Check joined guild
|
|
otherGuildId, isJoined := gm.checkJoinGuild(leaderID)
|
|
if isJoined {
|
|
errMsg := fmt.Sprintf("Player:%s has joined other guild:%d", leaderID, otherGuildId)
|
|
return 0, fmt.Errorf(errMsg)
|
|
}
|
|
|
|
guildId := f5.GetApp().NewUuid()
|
|
if _, exists := gm.Guilds[guildId]; exists {
|
|
return 0, fmt.Errorf("guild already exists")
|
|
}
|
|
maxMembers := 10
|
|
guild := &Guild{
|
|
GuildId: guildId,
|
|
Name: name,
|
|
LeaderId: leaderID,
|
|
MaxMembers: maxMembers,
|
|
}
|
|
gm.createGuildDB(guild)
|
|
|
|
newLevel := 1 // 会长
|
|
newMember := GuildMember{AccountId: leaderID, Level: newLevel}
|
|
_ = guild.AddMember(&newMember)
|
|
gm.upsertGuildMember(guildId, &newMember)
|
|
gm.Guilds[guildId] = guild
|
|
|
|
return guildId, nil
|
|
}
|
|
|
|
// ApplyToGuild 申请加入公会
|
|
func (gm *GuildMgr) ApplyToGuild(guildId int64, applicantAccountId string) error {
|
|
if _, exists := gm.Guilds[guildId]; !exists {
|
|
return fmt.Errorf("guild not found")
|
|
}
|
|
// check join guild
|
|
otherGuildId, isJoin := gm.checkJoinGuild(applicantAccountId)
|
|
if isJoin {
|
|
errMsg := fmt.Sprintf("Player:%s has joined other guild:%d", applicantAccountId, otherGuildId)
|
|
return fmt.Errorf(errMsg)
|
|
}
|
|
|
|
guild := gm.Guilds[guildId]
|
|
if len(guild.Members) >= guild.MaxMembers {
|
|
return fmt.Errorf("guild is full")
|
|
}
|
|
// IF exists, then replace it
|
|
gm.upsertPendingReqs(guildId, applicantAccountId, "0")
|
|
gm.pendingReqs[guildId][applicantAccountId] = true
|
|
return nil
|
|
}
|
|
|
|
// Approve 同意申请者加入公会
|
|
func (gm *GuildMgr) Approve(guildId int64, operatorAccountId, accountId string) error {
|
|
guild, exists := gm.Guilds[guildId]
|
|
if !exists {
|
|
return fmt.Errorf("guild not found")
|
|
}
|
|
|
|
// 公会干部及以上仅可操作
|
|
operatorPermLevel := 2
|
|
err := gm.checkOperatorPerm(guild, operatorAccountId, operatorPermLevel)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
otherGuildId, isJoin := gm.checkJoinGuild(accountId)
|
|
if isJoin {
|
|
errMsg := fmt.Sprintf("Player:%s has joined other guild:%d", accountId, otherGuildId)
|
|
return fmt.Errorf(errMsg)
|
|
}
|
|
|
|
_, exists = gm.pendingReqs[guildId][accountId]
|
|
if !exists {
|
|
return fmt.Errorf("no pending applications for this guild")
|
|
}
|
|
|
|
newMember := GuildMember{AccountId: accountId, Level: 3}
|
|
err = guild.AddMember(&newMember)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
gm.upsertGuildMember(guildId, &newMember)
|
|
delete(gm.pendingReqs[guildId], accountId)
|
|
gm.updatePendingReqs(guildId, accountId, "1")
|
|
|
|
logContent := fmt.Sprintf("Approve[%d-%s-%s]", guildId, operatorAccountId, accountId)
|
|
gm.WriteLog(guildId, accountId, LogTypeApprove, logContent)
|
|
|
|
return nil
|
|
}
|
|
|
|
// Reject 拒绝申请者加入公会
|
|
func (gm *GuildMgr) Reject(guildId int64, applicantAccountId string) error {
|
|
_, exists := gm.pendingReqs[guildId]
|
|
if !exists {
|
|
return fmt.Errorf("no pending applications for this guild")
|
|
}
|
|
|
|
//delete(gm.pendingReqs[guildId], applicantAccountId)
|
|
gm.pendingReqs[guildId][applicantAccountId] = false
|
|
gm.updatePendingReqs(guildId, applicantAccountId, "2")
|
|
|
|
return nil
|
|
}
|
|
|
|
// JoinGuild 直接加入公会
|
|
func (gm *GuildMgr) JoinGuild(guildId int64, accountId string) error {
|
|
guild, exists := gm.Guilds[guildId]
|
|
if !exists {
|
|
return fmt.Errorf("guild not found")
|
|
}
|
|
|
|
if len(guild.Members) >= guild.MaxMembers {
|
|
return fmt.Errorf("guild is full")
|
|
}
|
|
|
|
newMember := GuildMember{AccountId: accountId, Level: 3}
|
|
err := guild.AddMember(&newMember)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
gm.upsertGuildMember(guildId, &newMember)
|
|
delete(gm.pendingReqs[guildId], accountId)
|
|
gm.updatePendingReqs(guildId, accountId, "1")
|
|
|
|
return nil
|
|
}
|
|
|
|
// LeaveGuild 离开公会
|
|
func (gm *GuildMgr) LeaveGuild(guildId int64, accountId string) error {
|
|
guild, exists := gm.Guilds[guildId]
|
|
if !exists {
|
|
return fmt.Errorf("guild not found")
|
|
}
|
|
|
|
if guild.LeaderId == accountId {
|
|
return fmt.Errorf("leader not leave guild")
|
|
}
|
|
|
|
member, err := guild.GetMember(accountId)
|
|
if err != nil {
|
|
return fmt.Errorf("member not found in the guild")
|
|
}
|
|
|
|
_ = guild.RemoveMember(accountId)
|
|
fields := [][]string{{"is_leave_guild", q5.ToString(1)}}
|
|
gm.updateGuildMember(guild, member.AccountId, fields)
|
|
|
|
logContent := fmt.Sprintf("LeaveGuild[%d-%s]", guildId, accountId)
|
|
gm.WriteLog(guildId, accountId, LogTypeLeave, logContent)
|
|
|
|
return nil
|
|
}
|
|
|
|
// DismissMember 开除成员 踢出
|
|
func (gm *GuildMgr) DismissMember(guildId int64, operatorAccountId, accountId string) error {
|
|
guild, exists := gm.Guilds[guildId]
|
|
if !exists {
|
|
return fmt.Errorf("guild not found")
|
|
}
|
|
|
|
if accountId == guild.LeaderId {
|
|
return fmt.Errorf("cannot dismiss the leader")
|
|
}
|
|
|
|
// 公会干部及以上仅可操作
|
|
operatorPermLevel := 2
|
|
err := gm.checkOperatorPerm(guild, operatorAccountId, operatorPermLevel)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if operatorAccountId == accountId {
|
|
return fmt.Errorf("member not dismiss")
|
|
}
|
|
|
|
dismissMember, err := guild.GetMember(accountId)
|
|
if err != nil {
|
|
return fmt.Errorf("member not found in the guild")
|
|
}
|
|
if dismissMember.Level <= 2 {
|
|
return fmt.Errorf("no permission")
|
|
}
|
|
|
|
_ = guild.RemoveMember(accountId)
|
|
fields := [][]string{{"is_leave_guild", q5.ToString(1)}}
|
|
gm.updateGuildMember(guild, dismissMember.AccountId, fields)
|
|
|
|
logContent := fmt.Sprintf("DismissMember[%d-%s-%s]", guildId, operatorAccountId, accountId)
|
|
gm.WriteLog(guildId, accountId, LogTypeDismiss, logContent)
|
|
|
|
return nil
|
|
}
|
|
|
|
// PromoteMember 提升成员为干部
|
|
func (gm *GuildMgr) PromoteMember(guildId int64, operatorAccountId, accountId string) error {
|
|
guild, exists := gm.Guilds[guildId]
|
|
if !exists {
|
|
return fmt.Errorf("guild not found")
|
|
}
|
|
|
|
if accountId == guild.LeaderId {
|
|
return fmt.Errorf("cannot promote the leader")
|
|
}
|
|
|
|
// 会长仅可操作
|
|
operatorPermLevel := 1
|
|
err := gm.checkOperatorPerm(guild, operatorAccountId, operatorPermLevel)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
member, err := guild.GetMember(accountId)
|
|
if err != nil {
|
|
return fmt.Errorf("member not found in the guild")
|
|
}
|
|
newLevel := 2
|
|
if member.Level == newLevel {
|
|
return nil
|
|
}
|
|
|
|
member.Level = newLevel
|
|
fields := [][]string{{"level", q5.ToString(newLevel)}}
|
|
gm.updateGuildMember(guild, member.AccountId, fields)
|
|
|
|
logContent := fmt.Sprintf("PromoteMember[%d-%s-%s]", guildId, operatorAccountId, accountId)
|
|
gm.WriteLog(guildId, accountId, LogTypePromote, logContent)
|
|
|
|
return nil
|
|
}
|
|
|
|
// DemoteMember 解除成员干部身份
|
|
func (gm *GuildMgr) DemoteMember(guildId int64, operatorAccountId, accountId string) error {
|
|
guild, exists := gm.Guilds[guildId]
|
|
if !exists {
|
|
return fmt.Errorf("guild not found")
|
|
}
|
|
|
|
if accountId == guild.LeaderId {
|
|
return fmt.Errorf("cannot demote the leader")
|
|
}
|
|
|
|
// 会长仅可操作
|
|
operatorPermLevel := 1
|
|
err := gm.checkOperatorPerm(guild, operatorAccountId, operatorPermLevel)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
member, err := guild.GetMember(accountId)
|
|
if err != nil {
|
|
return fmt.Errorf("member not found in the guild")
|
|
}
|
|
|
|
newLevel := 3
|
|
if member.Level == newLevel {
|
|
return nil
|
|
}
|
|
member.Level = newLevel
|
|
fields := [][]string{{"level", q5.ToString(newLevel)}}
|
|
gm.updateGuildMember(guild, member.AccountId, fields)
|
|
|
|
logContent := fmt.Sprintf("DemoteMember[%d-%s-%s]", guildId, operatorAccountId, accountId)
|
|
gm.WriteLog(guildId, accountId, LogTypeDemote, logContent)
|
|
|
|
return nil
|
|
}
|
|
|
|
// Disband 解散公会
|
|
func (gm *GuildMgr) Disband(guildId int64, accountId string) error {
|
|
guild, exists := gm.Guilds[guildId]
|
|
if !exists {
|
|
return fmt.Errorf("guild not found")
|
|
}
|
|
|
|
// 会长仅可操作
|
|
if accountId != guild.LeaderId {
|
|
return fmt.Errorf("cannot disband guild")
|
|
}
|
|
|
|
guildName := guild.Name
|
|
guild.Members = nil
|
|
|
|
updateFields := [][]string{
|
|
{"is_deleted", q5.ToString(1)},
|
|
}
|
|
gm.updateGuild(guild, updateFields)
|
|
|
|
fields := [][]string{{"is_leave_guild", q5.ToString(1)}}
|
|
gm.updateGuildMembers(guild, fields)
|
|
|
|
isJoinGuild := 3
|
|
gm.updateAllPendingReqs(guildId, isJoinGuild)
|
|
|
|
// 确保在删除之前没有其他地方引用了公会对象的指针, 以避免空指针异常
|
|
gm.Guilds[guildId] = nil
|
|
gm.pendingReqs[guildId] = nil
|
|
gm.Logs[guildId] = nil
|
|
delete(gm.Guilds, guildId)
|
|
delete(gm.pendingReqs, guildId)
|
|
delete(gm.Logs, guildId)
|
|
|
|
logContent := fmt.Sprintf("GuildDisbanded[%d-%s]", guildId, guildName)
|
|
gm.WriteLog(guildId, accountId, LogTypeDisband, logContent)
|
|
|
|
return nil
|
|
}
|
|
|
|
// WriteLog 记录公会日志
|
|
func (gm *GuildMgr) WriteLog(guildId int64, accountId string, logType uint16, content string) {
|
|
_, exists := gm.Logs[guildId]
|
|
if !exists {
|
|
gm.Logs[guildId] = make([]*GuildLog, DefaultLogs)
|
|
}
|
|
log := &GuildLog{
|
|
GuildId: guildId,
|
|
AccountId: accountId,
|
|
LogType: logType,
|
|
Content: content,
|
|
}
|
|
gm.Logs[guildId] = append(gm.Logs[guildId], log)
|
|
gm.insertGuildLog(log)
|
|
}
|
|
|
|
func (gm *GuildMgr) GetLogs(guildID int64) []*GuildLog {
|
|
return gm.Logs[guildID]
|
|
}
|
|
|
|
// SearchGuilds 根据关键字搜索公会
|
|
func (gm *GuildMgr) SearchGuilds(keyword string) []Guild {
|
|
var results []Guild
|
|
for _, guild := range gm.Guilds {
|
|
if containsSubstring(guild.Name, keyword) {
|
|
results = append(results, *guild)
|
|
}
|
|
}
|
|
return results
|
|
}
|
|
|
|
func shuffleGuildIds(slice []*Guild) {
|
|
for i := len(slice) - 1; i > 0; i-- {
|
|
j := rand.Intn(i + 1)
|
|
slice[i], slice[j] = slice[j], slice[i]
|
|
}
|
|
}
|
|
|
|
// RandomGuilds 随机10个公会
|
|
func (gm *GuildMgr) RandomGuilds() []Guild {
|
|
guildCount := 10
|
|
count := len(gm.Guilds)
|
|
if count <= guildCount {
|
|
guildCount = count
|
|
}
|
|
|
|
guildSlice := make([]*Guild, 0, count)
|
|
for _, guild := range gm.Guilds {
|
|
guildSlice = append(guildSlice, guild)
|
|
}
|
|
shuffleGuildIds(guildSlice)
|
|
|
|
randomlySelectedGuilds := guildSlice[:guildCount]
|
|
var results []Guild
|
|
for _, guild := range randomlySelectedGuilds {
|
|
results = append(results, *gm.Guilds[guild.GuildId])
|
|
}
|
|
return results
|
|
}
|
|
|
|
// GetGuildByAccountId 查询我的工会
|
|
func (gm *GuildMgr) GetGuildByAccountId(accountId string) *Guild {
|
|
for _, guild := range gm.Guilds {
|
|
for _, member := range guild.Members {
|
|
if accountId == member.AccountId {
|
|
return guild
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Info 工会信息
|
|
func (gm *GuildMgr) Info(accountId string) (*Guild, map[string]bool, []*GuildLog) {
|
|
guild := gm.GetGuildByAccountId(accountId)
|
|
pendingReqs := make(map[string]bool, MaxPendingReqs)
|
|
guildLogs := make([]*GuildLog, 10)
|
|
if guild != nil {
|
|
guildId := guild.GuildId
|
|
pendingReqs = gm.pendingReqs[guildId]
|
|
guildLogs = gm.Logs[guildId]
|
|
}
|
|
|
|
return guild, pendingReqs, guildLogs
|
|
}
|
|
|
|
func (gm *GuildMgr) checkOperatorPerm(guild *Guild, operatorAccountId string, level int) error {
|
|
operatorMember, err := guild.GetMember(operatorAccountId)
|
|
if err != nil {
|
|
//return fmt.Errorf("checkOperatorPerm: no member")
|
|
return fmt.Errorf("checkOperatorPerm: no member[%s]", operatorAccountId)
|
|
}
|
|
if operatorMember.Level > level {
|
|
return fmt.Errorf("checkOperatorPerm: no permission[%s-%d]", operatorAccountId, operatorMember.Level)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (gm *GuildMgr) checkJoinGuild(accountId string) (int64, bool) {
|
|
for guildId, guild := range gm.Guilds {
|
|
for _, member := range guild.Members {
|
|
if accountId == member.AccountId {
|
|
return guildId, true
|
|
}
|
|
}
|
|
}
|
|
return 0, false
|
|
}
|
|
|
|
func containsSubstring(s, substr string) bool {
|
|
return len(s) >= len(substr) && s[len(s)-len(substr):] == substr
|
|
}
|