Files
bl/logic/service/space/space.go
昔念 f7e5880092
All checks were successful
ci/woodpecker/push/my-first-workflow Pipeline was successful
```
feat(space): 添加天气变化调试日志并优化地图节点配置

- 在天气变化时添加调试打印语句,便于追踪空间天气变化情况
- 重构地图节点模型,将NodeID重命名为TriggerID以更好地表达其用途
- 添加触发器ID字段用于区分精灵和NPC,支持高ID控制NPC逻辑
- 更新注释说明剧情相关配置的重构计划,通过NPC节点判断类型
- 调整地图怪信息结构体初始化逻辑,直接使用TriggerID作为ID
```
2026-02-25 22:47:16 +08:00

235 lines
4.9 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"
"blazing/modules/config/service"
"strconv"
"strings"
"sync/atomic"
"time"
"blazing/logic/service/common"
"blazing/logic/service/space/info"
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
TimeBoss info.S2C_2022
//Weather uint32
IsTime bool
//CanWeather uint32
}
// 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()
if id < 10000 { //说明是玩家地图GetSpace
for _, v := range xmlres.MapConfig.Maps {
if v.ID == int(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 {
var t1 int32
maphot[ret.Super] = &t1
}
ret.Name = v.Name
break
}
}
}
r := service.NewMapService().GetData(ret.ID)
if r != nil {
if r.IsTimeSpace != 0 {
ret.IsTime = true
}
ret.MapBossSInfo = info.MapBossSInfo{}
ret.MapBossSInfo.INFO = make([]info.MapBossInfo, 0)
if len(r.WeatherType) > 1 {
// ret.CanWeather = 1
cool.Cron.CustomFunc(ret, func() {
//if ret.CanWeather == 1 {
var neww uint32 = 0
if len(r.WeatherType) == 2 {
neww, _ = utils.RandomByWeight(r.WeatherType, []uint32{9, 1})
} else {
neww, _ = utils.RandomByWeight(r.WeatherType, []uint32{8, 1, 1})
}
if neww != uint32(ret.MapBossSInfo.Wer) {
ret.IsChange = true
ret.MapBossSInfo.Wer = int32(neww)
println(ret.Name, "change weather", neww)
} else {
ret.IsChange = false
}
//}
})
}
for _, v := range service.NewMapNodeService().GetData(ret.ID) {
if v.IsBroadcast != 0 { //说明是地图怪
info := info.MapBossInfo{
Id: v.TriggerID,
Region: v.NodeID, //这个是注册的index
Hp: v.HP,
PosInfo: ParseCoordinateString(v.Pos),
MaxHP: int(v.HP),
Wer: v.Weather,
}
ret.MapBossSInfo.INFO = append(ret.MapBossSInfo.INFO, info)
}
}
if len(ret.MapBossSInfo.INFO) > 0 {
cool.Cron.ScheduleFunc(10*time.Second, func() {
for i := 0; i < len(ret.MapBossSInfo.INFO); i++ {
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]
}
_, ok := lo.Find(ret.MapBossSInfo.INFO[i].Wer, func(item int32) bool {
return item == ret.MapBossSInfo.Wer
})
if ok {
ret.MapBossSInfo.INFO[i].IsShow = 1
if ret.IsChange {
ret.MapBossSInfo.INFO[i].IsShow = 2
}
} else {
ret.MapBossSInfo.INFO[i].IsShow = 0
}
}
ret.Broadcast(nil, 2021, &ret.MapBossSInfo)
})
cool.Cron.ScheduleFunc(300*time.Second, func() {
for _, v := range ret.MapBossSInfo.INFO {
atomic.StoreInt32(&v.Hp, int32(v.MaxHP))
}
})
}
}
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(6*time.Second, 30*time.Second))
}