feat(socket): 统一使用 glog.Info 替代 glog.Infof 将 ServerEvent.go 中的 glog.Infof 更改为 glog.Info,以统一日志输出方式并减少格式化开销。 feat(controller): 优化宠物经验设置逻辑与错误码返回 在 SetPetExp 方法中提前返回结果,并修正最终返回的错误码为 ErrSystemError。同时规范化注释格式。 feat(space): 支持天气地图判断与动态天气 BOSS 刷新 引入 lo 包用于查找
225 lines
6.7 KiB
Go
225 lines
6.7 KiB
Go
package space
|
||
|
||
import (
|
||
"blazing/cool"
|
||
"math/rand"
|
||
"strconv"
|
||
"strings"
|
||
"sync"
|
||
"sync/atomic"
|
||
"time"
|
||
)
|
||
|
||
// ========== 1. 定义TimeBoss的定时规则(补全周四-周六,新增周日规则) ==========
|
||
// TimeBossRule 单个BOSS的定时规则
|
||
type TimeBossRule struct {
|
||
PetID uint32 // BOSS ID(对应XML的petID="261")
|
||
Week int // 星期(1=周一,2=周二...7=周日)
|
||
ShowHours []int // 出现小时(如12,17,18,24);周日填0-23表示每小时
|
||
ShowMinute int // 出现分钟(如35,0)
|
||
LastTime int // 持续时间(分钟)
|
||
MapIDs []uint32 // 可选刷新地图ID列表(随机选一个)
|
||
}
|
||
|
||
// 全局:261号BOSS的规则配置(补全周四-周六,新增周日)
|
||
var timeBossRules = []TimeBossRule{
|
||
// 周一规则
|
||
{
|
||
PetID: 261,
|
||
Week: 1, // 周一
|
||
ShowHours: []int{12, 17, 18, 24}, // 12|17|18|24点35分
|
||
ShowMinute: 35, // 35分
|
||
LastTime: 40, // 持续40分钟
|
||
MapIDs: []uint32{15, 105, 54}, // 随机选一个地图
|
||
},
|
||
|
||
// 周二规则
|
||
{
|
||
PetID: 261,
|
||
Week: 2, // 周二
|
||
ShowHours: []int{17, 18, 24}, // 17|18|24点0分
|
||
ShowMinute: 0, // 0分
|
||
LastTime: 5, // 持续5分钟
|
||
MapIDs: []uint32{15, 105, 54},
|
||
},
|
||
// 周三规则
|
||
{
|
||
PetID: 261,
|
||
Week: 3, // 周三
|
||
ShowHours: []int{17, 18, 24}, // 17|18|24点0分
|
||
ShowMinute: 0, // 0分
|
||
LastTime: 5, // 持续5分钟
|
||
MapIDs: []uint32{15, 105, 54},
|
||
},
|
||
// 周四规则(和周一完全一致)
|
||
{
|
||
PetID: 261,
|
||
Week: 4, // 周四
|
||
ShowHours: []int{12, 17, 18, 24}, // 12|17|18|24点35分
|
||
ShowMinute: 35, // 35分
|
||
LastTime: 40, // 持续40分钟
|
||
MapIDs: []uint32{15, 105, 54},
|
||
},
|
||
// 周五规则(和周二完全一致)
|
||
{
|
||
PetID: 261,
|
||
Week: 5, // 周五
|
||
ShowHours: []int{17, 18, 24}, // 17|18|24点0分
|
||
ShowMinute: 0, // 0分
|
||
LastTime: 5, // 持续5分钟
|
||
MapIDs: []uint32{15, 105, 54},
|
||
},
|
||
// 周六规则(和周三完全一致)
|
||
{
|
||
PetID: 261,
|
||
Week: 6, // 周六
|
||
ShowHours: []int{17, 18, 24}, // 17|18|24点0分
|
||
ShowMinute: 0, // 0分
|
||
LastTime: 5, // 持续5分钟
|
||
MapIDs: []uint32{15, 105, 54},
|
||
},
|
||
// 周日规则(特殊:每小时刷新,持续10分钟)
|
||
{
|
||
PetID: 261,
|
||
Week: 7, // 周日
|
||
ShowHours: generateHourRange(0, 23), // 0-23点(每小时)
|
||
ShowMinute: 0, // 每小时0分触发
|
||
LastTime: 10, // 持续10分钟
|
||
MapIDs: []uint32{15, 105, 54}, // 随机选一个地图
|
||
},
|
||
}
|
||
|
||
// ========== 2. 全局变量(无修改,新增随机数生成器已存在) ==========
|
||
var (
|
||
registeredCronIDs = make(map[string]bool) // 记录已注册的Cron任务ID
|
||
cronMu sync.Mutex // 保护registeredCronIDs的互斥锁
|
||
randSource = rand.New(rand.NewSource(time.Now().UnixNano())) // 安全的随机数生成器
|
||
)
|
||
|
||
// ========== 3. 工具函数:生成0-23小时数组(适配周日每小时规则) ==========
|
||
// generateHourRange 生成从start到end的连续小时数组(如0-23)
|
||
func generateHourRange(start, end int) []int {
|
||
hours := make([]int, 0, end-start+1)
|
||
for i := start; i <= end; i++ {
|
||
hours = append(hours, i)
|
||
}
|
||
return hours
|
||
}
|
||
|
||
// ========== 4. 原有方法:gettimeboss(无修改,自动适配新规则) ==========
|
||
func init() { // 忽略传入的mapid,随机选地图
|
||
|
||
// 遍历所有TimeBoss规则(包含周四-周六-周日)
|
||
for _, rule := range timeBossRules {
|
||
|
||
// 为该规则的每个小时生成Cron任务
|
||
for _, hour := range rule.ShowHours {
|
||
// 生成唯一Cron任务ID(避免重复注册)
|
||
cronID := genCronTaskID(rule.PetID, rule.Week, hour, rule.ShowMinute)
|
||
cronMu.Lock()
|
||
if registeredCronIDs[cronID] {
|
||
cronMu.Unlock()
|
||
continue // 已注册过,跳过
|
||
}
|
||
registeredCronIDs[cronID] = true
|
||
cronMu.Unlock()
|
||
|
||
// 转换规则为Cron表达式
|
||
cronExpr := genCronExpr(rule.Week, hour, rule.ShowMinute)
|
||
|
||
// 捕获当前循环的rule(避免闭包引用同一变量)
|
||
currentRule := rule
|
||
|
||
// 注册Cron定时任务
|
||
cool.Cron.AddFunc(cronExpr, func() {
|
||
// 1. 随机选一个地图ID
|
||
randomMapID := getRandomMapID(currentRule.MapIDs)
|
||
if randomMapID == 0 {
|
||
return // 无可用地图,跳过
|
||
}
|
||
|
||
sp := GetSpace(randomMapID)
|
||
if sp != nil {
|
||
// 2. 显示BOSS(指定随机地图广播)
|
||
sp.refushgaiya(true)
|
||
|
||
// 3. 启动定时器:持续时间到后隐藏BOSS(同样指定地图)
|
||
time.AfterFunc(time.Duration(currentRule.LastTime)*time.Minute, func() {
|
||
sp.refushgaiya(false)
|
||
})
|
||
}
|
||
|
||
})
|
||
}
|
||
}
|
||
}
|
||
|
||
// ========== 5. 修改后的refushgaiya(指定地图广播) ==========
|
||
func (s *Space) refushgaiya(vis bool) {
|
||
|
||
if !vis {
|
||
atomic.StoreUint32(&s.TimeBoss.Flag, 0)
|
||
} else {
|
||
atomic.StoreUint32(&s.TimeBoss.Flag, 1)
|
||
}
|
||
atomic.StoreUint32(&s.TimeBoss.ID, 261)
|
||
|
||
// 只向指定地图广播(核心:不再全局广播)
|
||
s.Broadcast(nil, 2022, &s.TimeBoss)
|
||
|
||
}
|
||
|
||
// ========== 6. 工具函数(无修改,自动适配周日规则) ==========
|
||
// getRandomMapID 从地图列表中随机选一个
|
||
func getRandomMapID(mapIDs []uint32) uint32 {
|
||
if len(mapIDs) == 0 {
|
||
return 0
|
||
}
|
||
return mapIDs[randSource.Intn(len(mapIDs))]
|
||
}
|
||
|
||
// genCronExpr 生成Cron表达式(自动适配周日的0值)
|
||
func genCronExpr(week, hour, minute int) string {
|
||
// 1. 处理小时:24点转为0点(Cron小时范围0-23)
|
||
cronHour := hour
|
||
if cronHour == 24 {
|
||
cronHour = 0
|
||
}
|
||
|
||
// 2. 处理星期:XML的7=周日 → Cron的0=周日,其余直接用
|
||
cronWeek := week
|
||
if cronWeek == 7 {
|
||
cronWeek = 0
|
||
}
|
||
|
||
// 3. 生成Cron表达式(秒 分 时 日 月 周)
|
||
return strings.Join([]string{
|
||
"0", // 秒(固定0,整分触发)
|
||
strconv.Itoa(minute), // 分
|
||
strconv.Itoa(cronHour), // 时
|
||
"?", // 日(不指定)
|
||
"*", // 月(每月)
|
||
strconv.Itoa(cronWeek), // 周
|
||
}, " ")
|
||
}
|
||
|
||
// genCronTaskID 生成唯一的Cron任务ID
|
||
func genCronTaskID(petID uint32, week, hour, minute int) string {
|
||
return strings.Join([]string{
|
||
strconv.FormatUint(uint64(petID), 10),
|
||
strconv.Itoa(week),
|
||
strconv.Itoa(hour),
|
||
strconv.Itoa(minute),
|
||
}, "_")
|
||
}
|
||
|
||
// containsMapID 检查mapid是否在列表中(备用)
|
||
func containsMapID(mapIDs []uint32, mapid uint32) bool {
|
||
for _, id := range mapIDs {
|
||
if id == mapid {
|
||
return true
|
||
}
|
||
}
|
||
return false
|
||
}
|