Files
bl/logic/service/space/space.go
昔念 e7098e3777
All checks were successful
ci/woodpecker/push/my-first-workflow Pipeline was successful
```
feat(space): 更新地图BOSS生成逻辑并优化天气变化处理

- 修改GetMapPlayerList方法中BOSS信息发送方式为调用GenBoss方法
- 注释掉Space结构体中的IsChange字段,不再使用该标志位
- 调整GenBoss方法参数,添加isfrist参数用于区分首次调用
- 重构定时任务中的GenBoss调用逻辑,改为匿名函数包装广播消息
- 移除GenBoss
2026-03-18 01:22:14 +08:00

315 lines
6.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package space
import (
"blazing/common/data/xmlres"
"blazing/common/utils"
"blazing/cool"
"strconv"
"strings"
"sync/atomic"
"time"
"blazing/logic/service/common"
"blazing/logic/service/space/info"
"blazing/modules/config/model"
"blazing/modules/config/service"
infomodel "blazing/modules/player/model"
"github.com/gogf/gf/v2/util/grand"
csmap "github.com/mhmtszr/concurrent-swiss-map"
"github.com/samber/lo"
"github.com/tnnmigga/enum"
)
// 定义天气状态枚举实例
var WeatherStatus = enum.New[struct {
Normal uint32 `enum:"0"` // 正常
Rain uint32 `enum:"1"` // 下雨
Snow uint32 `enum:"2"` // 下雪
}]()
// Space 针对Player的并发安全map键为uint32类型
type Space struct {
User *csmap.CsMap[uint32, common.PlayerI] // 存储玩家数据的map键为玩家ID
UserInfo *csmap.CsMap[uint32, info.SimpleInfo]
CanRefresh bool //是否能够刷怪
Super uint32
//SuperValue *int32
ID uint32 // 地图ID
Name string //地图名称
Owner ARENA
info.MapBossSInfo
//IsChange bool
WeatherType []uint32
TimeBoss info.S2C_2022
//Weather uint32
IsTime bool
DropItemIds []uint32
PitS *csmap.CsMap[int, []model.MapPit]
}
// NewSyncMap 创建一个新的玩家同步map
func NewSpace() *Space {
ret := &Space{
User: csmap.New[uint32, common.PlayerI](),
UserInfo: csmap.New[uint32, info.SimpleInfo](),
}
return ret
}
// 获取星球
func GetSpace(id uint32) *Space {
planet, ok := planetmap.Load(id)
if ok {
return planet
}
ret := NewSpace()
ret.ID = id
defer ret.init()
planetmap.Store(id, ret)
return ret
}
var planetmap = csmap.New[uint32, *Space]()
func ParseCoordinateString(s string) []infomodel.Pos {
// 存储解析后的坐标
var points []infomodel.Pos
// 空字符串处理
if strings.TrimSpace(s) == "" {
return points
}
// 第一步:按竖线分割成单个坐标字符串
coordStrs := strings.Split(s, "|")
for _, coordStr := range coordStrs {
// 去除首尾空格(兼容可能的格式不规范)
coordStr = strings.TrimSpace(coordStr)
if coordStr == "" {
return nil
}
// 第二步按逗号分割X、Y值
xy := strings.Split(coordStr, ",")
if len(xy) != 2 {
return nil
}
// 第三步:转换为整数
xStr := strings.TrimSpace(xy[0])
yStr := strings.TrimSpace(xy[1])
x, err := strconv.Atoi(xStr)
if err != nil {
return nil
}
y, err := strconv.Atoi(yStr)
if err != nil {
return nil
}
// 添加到切片
points = append(points, infomodel.Pos{X: uint32(x), Y: uint32(y)})
}
return points
}
func (t *Space) Next(time.Time) time.Time {
return time.Now().Add(grand.D(10*time.Minute, 30*time.Minute))
}
func (ret *Space) init() {
if ret.ID < 10000 { //说明是玩家地图GetSpace
for _, v := range xmlres.MapConfig.Maps {
if v.ID == int(ret.ID) { //找到这个地图
ret.Super = uint32(v.Super)
if ret.Super == 0 {
ret.Super = uint32(v.ID)
}
ret.ID = uint32(v.ID)
_, ok := maphot[ret.Super]
if !ok {
maphot[ret.Super] = &MapTip{}
maphot[ret.Super].TipInfoS = make(map[uint32]*TipInfo, 0)
}
ret.Name = v.Name
//ogreconfig := service.NewMapPitService().GetData(ret.ID, uint32(i))
break
}
}
tips := &TipInfo{}
r := service.NewMapService().GetData(ret.ID)
if r != nil {
tips.Diao = service.NewMapService().GetData(ret.ID).DropItemIds
}
pits := service.NewMapPitService().GetDataALL(ret.ID)
ret.PitS = csmap.New[int, []model.MapPit]()
for _, v := range pits {
tips.Pet = append(tips.Pet, v.RefreshID...)
for _, vp := range v.Pos {
t, ok := ret.PitS.Load(vp)
if ok {
t = append(t, v)
ret.PitS.Store(vp, t)
} else {
ret.PitS.Store(vp, []model.MapPit{v})
}
}
}
if ret.Super != 0 {
tips.Pet = lo.Union(tips.Pet)
tips.Talk = service.NewTalkConfigService().GetTip(ret.ID)
tips.Boss = service.NewMapNodeService().GetTip(ret.ID)
maphot[ret.Super].TipInfoS[ret.ID] = tips
}
}
r := service.NewMapService().GetData(ret.ID)
if r != nil {
ret.DropItemIds = r.DropItemIds
if r.IsTimeSpace != 0 {
ret.IsTime = true
}
ret.MapBossSInfo = info.MapBossSInfo{}
ret.MapBossSInfo.INFO = make([]info.MapBossInfo, 0)
if len(r.WeatherType) > 1 {
ret.WeatherType = r.WeatherType
// ret.CanWeather = 1
cool.Cron.CustomFunc(ret, ret.GenWer)
}
for _, v := range service.NewMapNodeService().GetDataB(ret.ID) {
info := info.MapBossInfo{
Id: v.TriggerID,
Region: v.NodeID, //这个是注册的index
Hp: v.HP,
PosInfo: ParseCoordinateString(v.Pos),
Config: v,
}
ret.MapBossSInfo.INFO = append(ret.MapBossSInfo.INFO, info)
}
if len(ret.MapBossSInfo.INFO) > 0 {
cool.Cron.ScheduleFunc(10*time.Second, func() {
ret.Broadcast(nil, 2022, ret.GenBoss(false))
})
cool.Cron.ScheduleFunc(300*time.Second, ret.HealHP)
}
}
}
func (p *Space) IsMatch(t model.Event) bool {
_, ok := lo.Find(t.Weather, func(item int32) bool {
return item == int32(p.MapBossSInfo.Wer)
})
if !ok {
// 不在同一天气下
return false
}
if t.StartTime != "" && t.EndTime != "" {
ok, _ := utils.IsCurrentTimeInRange(t.StartTime, t.EndTime)
if !ok {
return false
}
}
return true
}
func (ret *Space) GenBoss(isfrist bool) *info.MapBossSInfo {
var res info.MapBossSInfo
res.Wer = ret.Wer
for i := 0; i < len(ret.MapBossSInfo.INFO); i++ {
if !ret.IsMatch(*ret.MapBossSInfo.INFO[i].Config.Event) {
if ret.MapBossSInfo.INFO[i].IsShow != 0 {
ret.MapBossSInfo.INFO[i].IsShow = 0
res.INFO = append(res.INFO, ret.MapBossSInfo.INFO[i])
}
continue
}
s := len(ret.MapBossSInfo.INFO[i].PosInfo)
if s != 0 {
ret.MapBossSInfo.INFO[i].Pos = ret.MapBossSInfo.INFO[i].PosInfo[(grand.Intn(s-1)+1+int(ret.MapBossSInfo.INFO[i].PosIndex))%s]
}
ret.MapBossSInfo.INFO[i].IsShow = 1
if isfrist {
ret.MapBossSInfo.INFO[i].IsShow = 2
}
res.INFO = append(res.INFO, ret.MapBossSInfo.INFO[i])
}
return &res
}
func (ret *Space) HealHP() {
for _, v := range ret.MapBossSInfo.INFO {
atomic.StoreInt32(&v.Hp, int32(v.Config.HP))
}
}
func (ret *Space) GenWer() {
//if ret.CanWeather == 1 {
var neww uint32 = 0
if len(ret.WeatherType) == 2 {
neww, _ = utils.RandomByWeight(ret.WeatherType, []uint32{9, 1})
} else {
neww, _ = utils.RandomByWeight(ret.WeatherType, []uint32{8, 1, 1})
}
if neww != uint32(ret.MapBossSInfo.Wer) {
ret.MapBossSInfo.Wer = int32(neww)
ret.Broadcast(nil, 2021, ret.GenBoss(true))
println(ret.Name, "change weather", neww)
}
//}
}
func (ret *Space) GetDrop() int64 {
if len(ret.DropItemIds) > 0 {
item := int64(ret.DropItemIds[grand.Intn(len(ret.DropItemIds))])
return int64(item)
}
return 0
}