diff --git a/logic/controller/fight_boss.go b/logic/controller/fight_boss.go index a38440cdc..ef61d407a 100644 --- a/logic/controller/fight_boss.go +++ b/logic/controller/fight_boss.go @@ -3,6 +3,8 @@ package controller import ( "blazing/common/data/xmlres" "blazing/common/socket/errorcode" + "math/rand" + "strings" "blazing/logic/service/fight" "blazing/logic/service/fight/info" @@ -13,13 +15,41 @@ import ( "github.com/gogf/gf/v2/util/gconv" ) +func processMonID(bm string) string { + // 按空格分割字符串 + monid := strings.Split(bm, " ") + + // 过滤分割后可能的空字符串(如连续空格导致的空元素) + filtered := make([]string, 0, len(monid)) + for _, m := range monid { + if m != "" { + filtered = append(filtered, m) + } + } + monid = filtered + + var selected string + switch len(monid) { + case 0: + // 无元素时,可返回空或默认值(根据业务需求调整) + selected = "" + case 1: + // 长度为1时,取第一个(唯一的元素) + selected = monid[0] + default: + // 长度大于1时,随机选取一个 + randomIdx := rand.Intn(len(monid)) + selected = monid[randomIdx] + } + return selected +} + // 挑战地图boss func (h Controller) PlayerFightBoss(data *fight.ChallengeBossInboundInfo, c *player.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) { if !c.CanFight() { return nil, errorcode.ErrorCodes.ErrPokemonNotEligible } - var petid int var mo *model.PetInfo moinfo := &model.PlayerInfo{} // 新手任务2(选择不同精灵) @@ -34,61 +64,35 @@ func (h Controller) PlayerFightBoss(data *fight.ChallengeBossInboundInfo, c *pla // // // - if c.Info.MapID == 515 && data.BossId == 0 { //说明是新手,随机生成 - switch c.Info.PetList[0].ID { - case 1: - petid = 4 + mdata, ok := xmlres.MonsterMap[int(c.Info.MapID)] + if !ok { + return nil, errorcode.ErrorCodes.ErrPokemonNotExists + } + if len(mdata.Bosses) == 0 { + return nil, errorcode.ErrorCodes.ErrPokemonNotExists + } + for _, bc := range mdata.Bosses { + if (bc.Id == nil && data.BossId == 0) || uint32(*bc.Id) == data.BossId { //打默认第一个boss - case 7: - petid = 1 + for _, bm := range bc.BossMon { - case 4: - petid = 7 - } + mo = c.GenPetInfo( + gconv.Int(processMonID(bm.MonID)), 24, //24个体 + -1, + 0, //野怪没特性 + 0, + bm.Lv) - mo = c.GenPetInfo( - int(petid), 24, //24个体 - -1, - 0, //野怪没特性 - 0, - 50) - moinfo.Nick = xmlres.PetMAP[int(mo.ID)].DefName - moinfo.PetList = append(moinfo.PetList, *mo) - } else { - - mdata, ok := xmlres.MonsterMap[int(c.Info.MapID)] - if !ok { - return nil, errorcode.ErrorCodes.ErrPokemonNotExists - } - if len(mdata.Bosses) == 0 { - return nil, errorcode.ErrorCodes.ErrPokemonNotExists - } - for _, bc := range mdata.Bosses { - if bc.Id == nil { - return nil, errorcode.ErrorCodes.ErrPokemonNotExists + // mo.Level = uint32(bm.Lv) + mo.CalculatePetPane() + mo.Hp = uint32(bm.Hp) + mo.MaxHp = uint32(bm.Hp) + moinfo.PetList = append(moinfo.PetList, *mo) } - if uint32(*bc.Id) == data.BossId { - for _, bm := range bc.BossMon { - mo = c.GenPetInfo( - gconv.Int(bm.MonID), 24, //24个体 - -1, - 0, //野怪没特性 - 0, - bm.Lv) - - // mo.Level = uint32(bm.Lv) - mo.CalculatePetPane() - mo.Hp = uint32(bm.Hp) - mo.MaxHp = uint32(bm.Hp) - moinfo.PetList = append(moinfo.PetList, *mo) - - } - moinfo.Nick = xmlres.PetMAP[int(mo.ID)].DefName - break - } - + moinfo.Nick = xmlres.PetMAP[int(mo.ID)].DefName + break } } diff --git a/logic/controller/map.go b/logic/controller/map.go index 5bf660bc4..f455bc58d 100644 --- a/logic/controller/map.go +++ b/logic/controller/map.go @@ -3,7 +3,6 @@ package controller import ( "blazing/common/socket/errorcode" - "blazing/logic/service/common" "blazing/logic/service/maphot" "blazing/logic/service/maps" "blazing/logic/service/maps/info" @@ -11,19 +10,24 @@ import ( "blazing/logic/service/space" "github.com/jinzhu/copier" + "github.com/panjf2000/ants/v2" ) +var mappool, _ = ants.NewPool(-1) + func (h *Controller) MapEnter(data *maps.InInfo, c *player.Player) (result *info.OutInfo, err errorcode.ErrorCode) { //这个时候player应该是空的 - c.Info.MapID = data.MapId //登录地图 - space.GetSpace(c.Info.MapID).User.Store(c.Info.UserID, c) //添加玩家 + c.Info.MapID = data.MapId //登录地图 + c.GetSpace().User.Store(c.Info.UserID, c) //添加玩家 result = info.NewOutInfo() c.Info.Pos = data.Point copier.Copy(result, c.Info) + mappool.Submit(func() { + c.GetSpace().EnterMap(c) + }) - go space.GetSpace(c.Info.MapID).EnterMap(c) //玩家进入地图 - return result, -1 + return result, 0 } func (h Controller) MapHot(data *maphot.InInfo, c *player.Player) (result *maphot.OutInfo, err errorcode.ErrorCode) { @@ -39,33 +43,21 @@ func (h *Controller) MapLeave(data *maps.LeaveMapInboundInfo, c *player.Player) c.Canmon = false c.Changemap = true //可以刷怪 //data.Broadcast(c.Info.MapID, info.LeaveMapOutboundInfo{UserID: c.Info.UserID}) //同步广播 - go space.GetSpace(c.Info.MapID).LeaveMap(c) //玩家离开地图 + mappool.Submit(func() { + c.GetSpace().LeaveMap(c) //玩家离开地图 + }) + // 如果有正在运行的刷怪协程,发送停止信号 c.Info.MapID = 0 // 重置当前地图 - return &info.LeaveMapOutboundInfo{UserID: c.Info.UserID}, -1 + return &info.LeaveMapOutboundInfo{UserID: c.Info.UserID}, 0 } -func (h *Controller) MapList(data *maps.ListMapPlayerInboundInfo, c *player.Player) (result *maps.ListMapPlayerOutboundInfo, err errorcode.ErrorCode) { //这个时候player应该是空的 +func (h *Controller) MapList(data *maps.ListMapPlayerInboundInfo, c *player.Player) (result *info.ListMapPlayerOutboundInfo, err errorcode.ErrorCode) { //这个时候player应该是空的 - result = &maps.ListMapPlayerOutboundInfo{} - result.Player = make([]info.OutInfo, 0) - space.GetSpace(c.Info.MapID).User.Range(func(playerID uint32, player common.PlayerI) bool { - result1 := info.NewOutInfo() - copier.CopyWithOption(result1, player.GetInfo(), copier.Option{DeepCopy: true}) - result.Player = append(result.Player, *result1) - result.Player = LastFourElements(result.Player) - return false - }) + result = &info.ListMapPlayerOutboundInfo{ + Player: c.GetSpace().GetInfo(), + } c.Canmon = true //可以刷怪 return } -func LastFourElements[T any](s []T) []T { - n := len(s) - if n <= 30 { - // 切片长度小于等于4时,返回整个切片 - return s - } - // 切片长度大于4时,返回最后4个元素(从n-4索引到末尾) - return s[n-30:] -} diff --git a/logic/controller/task.go b/logic/controller/task.go index e9e52a4ea..c015748d6 100644 --- a/logic/controller/task.go +++ b/logic/controller/task.go @@ -70,6 +70,9 @@ func (h Controller) Complete_Task(data *task.CompleteTaskInboundInfo, c *player. //task.Tasktopic.Pub(*data) tt := task.Get_Task_Info(*data) + if tt == nil { + return result, 0 //通过PUB/SUB回包 + } result.ItemList = tt.ItemList if tt.PetTypeId != 0 { @@ -81,11 +84,12 @@ func (h Controller) Complete_Task(data *task.CompleteTaskInboundInfo, c *player. var ttt []model.SingleItemInfo - copier.Copy(ttt, result.ItemList) + copier.CopyWithOption(&ttt, &result.ItemList, copier.Option{IgnoreEmpty: true, DeepCopy: true}) + ret := c.ItemAdd(ttt...) //获取成功的条目 + result.ItemList = make([]task.ItemInfo, 0) //清空 + copier.CopyWithOption(&result.ItemList, &ret, copier.Option{IgnoreEmpty: true, DeepCopy: true}) - copier.Copy(result.ItemList, c.ItemAdd(ttt...)) - - return result, -1 //通过PUB/SUB回包 + return result, 0 //通过PUB/SUB回包 } /** diff --git a/logic/service/maps/info/info.go b/logic/service/maps/info/info.go index b3f33298c..e7654e637 100644 --- a/logic/service/maps/info/info.go +++ b/logic/service/maps/info/info.go @@ -6,6 +6,13 @@ import ( "github.com/creasty/defaults" ) +type ListMapPlayerOutboundInfo struct { + PlayersLen uint32 `struc:"sizeof=Player" json:"player_len"` + + // 穿戴装备的信息 + Player []OutInfo ` json:"player"` +} + // 这里存储星球的map //var planetmap utils.SyncMap[] //= space.NewSyncMap() diff --git a/logic/service/maps/maplist.go b/logic/service/maps/maplist.go index fe620c690..7593f7824 100644 --- a/logic/service/maps/maplist.go +++ b/logic/service/maps/maplist.go @@ -1,17 +1,9 @@ package maps import ( - "blazing/logic/service/maps/info" "blazing/logic/service/player" ) type ListMapPlayerInboundInfo struct { Head player.TomeeHeader `cmd:"2003" struc:"[0]pad"` //切换地图 } - -type ListMapPlayerOutboundInfo struct { - PlayersLen uint32 `struc:"sizeof=Player" json:"player_len"` - - // 穿戴装备的信息 - Player []info.OutInfo ` json:"player"` -} diff --git a/logic/service/maps/walk.go b/logic/service/maps/walk.go index 78c4c3589..3acda65fe 100644 --- a/logic/service/maps/walk.go +++ b/logic/service/maps/walk.go @@ -30,6 +30,7 @@ func (t *WalkInInfo) Broadcast(mapid uint32, o WalkOutInfo) { if !limiter.Allow() { return } + space.GetSpace(mapid).User.Range(func(playerID uint32, player common.PlayerI) bool { t.Head.Result = 0 tt := t.Head.Pack(&o) diff --git a/logic/service/player/player.go b/logic/service/player/player.go index 03bb58d34..6d1fd4484 100644 --- a/logic/service/player/player.go +++ b/logic/service/player/player.go @@ -6,6 +6,7 @@ import ( "blazing/common/utils" "blazing/cool" "blazing/logic/service/fight/info" + "blazing/logic/service/space" "math/rand" "strings" @@ -81,6 +82,9 @@ func (p *Player) UseCoins(t uint32) bool { } func (p *Player) GetAction() { +} +func (p *Player) GetSpace() *space.Space { + return space.GetSpace(p.Info.MapID) } func (p *Player) CanFight() bool { if p.FightC != nil { diff --git a/logic/service/space/hot.go b/logic/service/space/hot.go index 87187526b..d8c147136 100644 --- a/logic/service/space/hot.go +++ b/logic/service/space/hot.go @@ -1,45 +1,68 @@ package space import ( - "blazing/common/data/xmlres" - + csmap "github.com/mhmtszr/concurrent-swiss-map" "golang.org/x/sync/singleflight" ) var requestGroup singleflight.Group // SingleFlight 实例 // MapHotInfo 表示地图热度信息 type MapHotInfo struct { - MapID uint32 `json:"mapId"` // 地图ID - Count uint32 `json:"count"` // 地图里的人数 + MapID uint32 `json:"mapId"` // 地图ID + Count int32 `struc:"uint32" json:"count"` // 地图里的人数 } +var maphot = csmap.New[uint32, *int32]( + // set the number of map shards. the default value is 32. + csmap.WithShardCount[uint32, *int32](32), + + // // if don't set custom hasher, use the built-in maphash. + // csmap.WithCustomHasher[string, int](func(key string) uint64 { + // hash := fnv.New64a() + // hash.Write([]byte(key)) + // return hash.Sum64() + // }), + + // set the total capacity, every shard map has total capacity/shard count capacity. the default value is 0. + // csmap.WithSize[string, int](1000), +) + func GetMapHot() []MapHotInfo { + ret := make([]MapHotInfo, 0) + maphot.Range(func(key uint32, value *int32) (stop bool) { + ret = append(ret, MapHotInfo{ + MapID: key, + Count: *value, + }) - result1, _, _ := requestGroup.Do("map_hot", func() (interface{}, error) { - - tt := make(map[uint32]uint32) - - for _, v := range xmlres.MapConfig.Maps { - - t1, ok := tt[uint32(v.Super)] - if ok { - tt[uint32(v.Super)] = uint32(int(t1) + GetSpace(uint32(v.ID)).User.Count()) - - } else { - tt[uint32(v.Super)] = uint32(GetSpace(uint32(v.ID)).User.Count()) - } - - } - var result = make([]MapHotInfo, 0) - for k, v := range tt { - - result = append(result, MapHotInfo{ - MapID: uint32(k), - Count: uint32(v), - }) - - } - return result, nil + return true }) - return result1.([]MapHotInfo) + return ret + // result1, _, _ := requestGroup.Do("map_hot", func() (interface{}, error) { + + // tt := make(map[uint32]uint32) + + // for _, v := range xmlres.MapConfig.Maps { + + // t1, ok := tt[uint32(v.Super)] + // if ok { + // tt[uint32(v.Super)] = uint32(int(t1) + GetSpace(uint32(v.ID)).User.Count()) + + // } else { + // tt[uint32(v.Super)] = uint32(GetSpace(uint32(v.ID)).User.Count()) + // } + + // } + // var result = make([]MapHotInfo, 0) + // for k, v := range tt { + + // result = append(result, MapHotInfo{ + // MapID: uint32(k), + // Count: uint32(v), + // }) + + // } + // return result, nil + // }) + } diff --git a/logic/service/space/in_out.go b/logic/service/space/in_out.go index 05c484d3e..163d15b57 100644 --- a/logic/service/space/in_out.go +++ b/logic/service/space/in_out.go @@ -3,6 +3,8 @@ package space import ( "blazing/logic/service/common" "blazing/logic/service/maps/info" + maps "blazing/logic/service/maps/info" + "sync/atomic" "github.com/jinzhu/copier" ) @@ -29,6 +31,12 @@ func (s *Space) LeaveMap(c common.PlayerI) { }) s.User.Delete(c.GetInfo().UserID) + s.UserInfo.Delete(c.GetInfo().UserID) + if s.SuperValue != nil { + + atomic.AddInt32(s.SuperValue, -1) + } + } func (s *Space) EnterMap(c common.PlayerI) { @@ -36,10 +44,34 @@ func (s *Space) EnterMap(c common.PlayerI) { out := info.NewOutInfo() copier.CopyWithOption(out, c.GetInfo(), copier.Option{DeepCopy: true}) s.User.Range(func(k uint32, v common.PlayerI) (stop bool) { - - v.SendEnterMapInfo(*out) - + if k != c.GetInfo().UserID { + v.SendEnterMapInfo(*out) + } return false }) s.User.Store(c.GetInfo().UserID, c) + s.UserInfo.Store(c.GetInfo().UserID, *out) + if s.SuperValue != nil { + atomic.AddInt32(s.SuperValue, 1) + } + +} +func (s *Space) GetInfo() []maps.OutInfo { + ret := make([]maps.OutInfo, 0) + s.UserInfo.Range(func(k uint32, v maps.OutInfo) (stop bool) { + ret = append(ret, v) + return len(ret) > 30 + }) + + return ret + +} +func LastFourElements[T any](s []T) []T { + n := len(s) + if n <= 30 { + // 切片长度小于等于4时,返回整个切片 + return s + } + // 切片长度大于4时,返回最后4个元素(从n-4索引到末尾) + return s[n-30:] } diff --git a/logic/service/space/space.go b/logic/service/space/space.go index 1c4b4dfa7..684982bb9 100644 --- a/logic/service/space/space.go +++ b/logic/service/space/space.go @@ -6,6 +6,7 @@ import ( "blazing/logic/service/common" "blazing/logic/service/fight/info" + maps "blazing/logic/service/maps/info" csmap "github.com/mhmtszr/concurrent-swiss-map" ) @@ -13,7 +14,10 @@ import ( // Space 针对Player的并发安全map,键为uint32类型 type Space struct { User *csmap.CsMap[uint32, common.PlayerI] // 存储玩家数据的map,键为玩家ID - CanRefresh bool //是否能够刷怪 + UserInfo *csmap.CsMap[uint32, maps.OutInfo] + CanRefresh bool //是否能够刷怪 + Super uint32 + SuperValue *int32 //ID uint32 // 地图ID Name string //地图名称 ARENA info.S2C_ARENA_GET_INFO @@ -93,6 +97,20 @@ func NewSpace() *Space { // return hash.Sum64() // }), + // set the total capacity, every shard map has total capacity/shard count capacity. the default value is 0. + // csmap.WithSize[string, int](1000), + ), + UserInfo: csmap.New[uint32, maps.OutInfo]( + // set the number of map shards. the default value is 32. + csmap.WithShardCount[uint32, maps.OutInfo](32), + + // // if don't set custom hasher, use the built-in maphash. + // csmap.WithCustomHasher[string, int](func(key string) uint64 { + // hash := fnv.New64a() + // hash.Write([]byte(key)) + // return hash.Sum64() + // }), + // set the total capacity, every shard map has total capacity/shard count capacity. the default value is 0. // csmap.WithSize[string, int](1000), ), @@ -113,6 +131,16 @@ func GetSpace(id uint32) *Space { for _, v := range xmlres.MapConfig.Maps { if v.ID == int(id) { //找到这个地图 t := NewSpace() + t.Super = uint32(v.Super) + ok := maphot.Has(t.Super) + if !ok { + var tt int32 = 0 + maphot.Store(uint32(v.Super), &tt) + t.SuperValue = &tt //创建一个 + + } else { + t.SuperValue, _ = maphot.Load(uint32(v.Super)) + } t.Name = v.Name diff --git a/logic/service/task/CompleteTask.go b/logic/service/task/CompleteTask.go index 80a5900e8..dabb93354 100644 --- a/logic/service/task/CompleteTask.go +++ b/logic/service/task/CompleteTask.go @@ -18,6 +18,6 @@ type CompleteTaskOutboundInfo struct { // ItemInfo // 用于表示发放物品的信息 type ItemInfo struct { - ItemId uint32 `json:"itemId" description:"发放物品ID"` // 发放物品ID, - ItemCount uint32 `json:"itemCount" description:"发放物品的数量"` // 发放物品的数量, + ItemId uint32 `json:"itemId" description:"发放物品ID"` // 发放物品ID, + ItemCnt uint32 `json:"itemCount" description:"发放物品的数量"` // 发放物品的数量, } diff --git a/logic/service/task/list.go b/logic/service/task/list.go index 4ae9dd7e3..45ddf2ff4 100644 --- a/logic/service/task/list.go +++ b/logic/service/task/list.go @@ -37,7 +37,7 @@ func init() { {300011, 3}, // 初级体力药剂x3 }, 0) - RegisterTask(88, 0, []ItemInfo{ // 新手任务4(默认分支) + RegisterTask(88, 1, []ItemInfo{ // 新手任务4(默认分支) {1, 50000}, // 赛尔豆x50000 {3, 50000}, // 累积经验x50000 {5, 20}, // 金豆x20 diff --git a/logic/service/task/list_daily.go b/logic/service/task/list_daily.go index 0ed568fd0..184e3bc10 100644 --- a/logic/service/task/list_daily.go +++ b/logic/service/task/list_daily.go @@ -1,6 +1,5 @@ package task - type TaskResult struct { PetTypeId uint32 `json:"petTypeId" description:"发放的精灵ID"` // 发放的精灵ID, @@ -19,9 +18,9 @@ func Get_Task_Info(v CompleteTaskInboundInfo) *TaskResult { } func init() { // 定义通用奖励:经验奖励(ItemId:3,数量20000) - expReward := []ItemInfo{{ItemId: 3, ItemCount: 20000}} + expReward := []ItemInfo{{ItemId: 3, ItemCnt: 20000}} // 定义扭蛋牌奖励(ItemId:400501,数量5) - eggReward := []ItemInfo{{ItemId: 400501, ItemCount: 5}} + eggReward := []ItemInfo{{ItemId: 400501, ItemCnt: 5}} // 批量初始化任务ID 401-407(奖励均为经验) for taskID := 401; taskID <= 407; taskID++ {