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"` }]() type Space struct { User *csmap.CsMap[uint32, common.PlayerI] UserInfo *csmap.CsMap[uint32, info.SimpleInfo] CanRefresh bool Super uint32 ID uint32 Name string Owner ARENA MapBossSInfo info.MapModelBroadcastInfo WeatherType []uint32 TimeBoss info.S2C_2022 IsTime bool DropItemIds []uint32 PitS *csmap.CsMap[int, []model.MapPit] MapNodeS *csmap.CsMap[uint32, *model.MapNode] } func NewSpace() *Space { ret := &Space{ User: csmap.New[uint32, common.PlayerI](), UserInfo: csmap.New[uint32, info.SimpleInfo](), MapNodeS: csmap.New[uint32, *model.MapNode](), } 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 } 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 { 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 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.MapModelBroadcastInfo{} ret.MapBossSInfo.INFO = make([]info.MapModelBroadcastEntry, 0) mapNodes := service.NewMapNodeService().GetData(ret.ID) for i := range mapNodes { ret.MapNodeS.Store(mapNodes[i].NodeID, &mapNodes[i]) } if len(r.WeatherType) > 1 { ret.WeatherType = r.WeatherType cool.Cron.CustomFunc(ret, ret.GenWer) } for _, v := range mapNodes { if v.IsBroadcast == 0 { continue } r := service.NewMapmodelService().GetDataByModelId(v.IsBroadcast) if r == nil { continue } info := info.MapModelBroadcastEntry{ ModelID: uint32(r.ID), Region: v.NodeID, Hp: r.HP, PosInfo: ParseCoordinateString(r.Pos), Config: v, Model: *r, } 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) GetMatchedMapNode(nodeID uint32) *model.MapNode { if p == nil || p.MapNodeS == nil { return nil } mapNode, ok := p.MapNodeS.Load(nodeID) if !ok || mapNode == nil || mapNode.Event == nil || !p.IsMatch(*mapNode.Event) { return nil } return mapNode } func (p *Space) IsMatch(t model.Event) bool { if len(t.Weather) > 0 { _, 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 } } if len(t.Week) > 0 { week := int32(time.Now().Weekday()) if week == 0 { week = 7 } _, ok := lo.Find(t.Week, func(item int32) bool { return item == week }) if !ok { return false } } return true } func (ret *Space) GenBoss(isfrist bool) *info.MapModelBroadcastInfo { var res info.MapModelBroadcastInfo res.Wer = ret.MapBossSInfo.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].PosIndex = uint32(grand.Intn(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.Model.HP)) } } func (ret *Space) GenWer() { 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, 2022, 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 }