game2006go/server/imserver/guildmgr.go
2023-08-24 11:50:40 +08:00

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
}