All checks were successful
ci/woodpecker/push/my-first-workflow Pipeline was successful
feat(common/cool): 更新GetClient函数支持端口参数 更新GetClient函数签名以接收端口参数,并修改客户端映射键的计算方式, 添加GetClientOnly函数用于仅通过uid获取客户端。 fix(common/rpc): 修复RPC调用中的客户端获取方法 将GetClient调用替换为GetClientOnly,确保正确的客户端获取逻辑。 refactor(logic/controller): 重命名Port字段为UID并优化道具列表处理 将Controller结构体中的Port字段重命名为UID以更好地反映其用途, 优化GetUserItemList函数中道具列表的初始化和填充逻辑。 perf(logic): 调整性能分析web服务启动位置 将PprofWeb服务从全局启动移至调试模式下启动,优化服务配置。 refactor(logic/server): 更新服务器UID生成逻辑 修改Maincontroller的UID字段设置方式,使用服务器ID和端口组合生成唯一标识。 refactor(logic/service/player): 移除未使用的导入并优化怪物生成 移除未使用的service导入,优化怪物生成逻辑中的地图数据访问。 feat(logic/service/space): 添加PitS缓存映射并重构空间初始化 添加新的PitS字段
279 lines
5.9 KiB
Go
279 lines
5.9 KiB
Go
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
|
||
|
||
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(6*time.Second, 30*time.Second))
|
||
|
||
}
|
||
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)
|
||
}
|
||
|
||
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})
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
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
|
||
|
||
ret.Name = v.Name
|
||
|
||
//ogreconfig := service.NewMapPitService().GetData(ret.ID, uint32(i))
|
||
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.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),
|
||
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, ret.GenBoss)
|
||
cool.Cron.ScheduleFunc(300*time.Second, ret.HealHP)
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
func (ret *Space) GenBoss() {
|
||
|
||
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)
|
||
|
||
}
|
||
func (ret *Space) HealHP() {
|
||
|
||
for _, v := range ret.MapBossSInfo.INFO {
|
||
atomic.StoreInt32(&v.Hp, int32(v.MaxHP))
|
||
}
|
||
}
|
||
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.IsChange = true
|
||
ret.MapBossSInfo.Wer = int32(neww)
|
||
ret.GenBoss()
|
||
println(ret.Name, "change weather", neww)
|
||
|
||
} else {
|
||
ret.IsChange = false
|
||
}
|
||
|
||
//}
|
||
|
||
}
|