diff --git a/common/data/socket/Client.go b/common/data/socket/Client.go deleted file mode 100644 index 7ede19f20..000000000 --- a/common/data/socket/Client.go +++ /dev/null @@ -1,30 +0,0 @@ -package socket - -func ConutPlayer() int { - - count := 0 - Mainplayer.Range(func(uint32, *Player) bool { - count++ - return true // 继续遍历 - }) - return count -} - -type ClientData struct { - IsCrossDomain bool //是否跨域过 - Player *Player //客户实体 - //UserID uint32 - - Wsmsg *WsCodec -} - -func NewClientData() *ClientData { - cd := ClientData{ - IsCrossDomain: false, - Player: nil, - - Wsmsg: &WsCodec{}, - } - return &cd - -} diff --git a/common/socket/ServerEvent.go b/common/socket/ServerEvent.go index a7b5c5e77..c1232a97f 100644 --- a/common/socket/ServerEvent.go +++ b/common/socket/ServerEvent.go @@ -7,7 +7,8 @@ import ( "time" "blazing/common/data/share" - "blazing/common/data/socket" + + "blazing/logic/service" "blazing/logic/service/maps" "github.com/gogf/gf/v2/os/glog" @@ -42,7 +43,7 @@ func (s *Server) Stop() error { func (s *Server) OnClose(c gnet.Conn, _ error) (action gnet.Action) { atomic.AddInt64(&s.connected, -1) //logging.Infof("conn[%v] disconnected", c.RemoteAddr().String()) - v, ok := c.Context().(*socket.ClientData) + v, ok := c.Context().(*service.ClientData) if !ok { return @@ -54,7 +55,7 @@ func (s *Server) OnClose(c gnet.Conn, _ error) (action gnet.Action) { maps.LeaveMap(v.Player) v.Player.IsLogin = false - socket.Mainplayer.Delete(v.Player.Info.UserID) + service.Mainplayer.Delete(v.Player.Info.UserID) share.ShareManager.DeleteUserOnline(v.Player.Info.UserID) //设置用户登录服务器 v.Player.Save() //保存玩家数据 } @@ -77,7 +78,7 @@ func (s *Server) OnBoot(eng gnet.Engine) gnet.Action { func (s *Server) OnOpen(conn gnet.Conn) (out []byte, action gnet.Action) { if conn.Context() == nil { - conn.SetContext(socket.NewClientData()) //注入data + conn.SetContext(service.NewClientData()) //注入data } atomic.AddInt64(&s.connected, 1) @@ -90,7 +91,7 @@ func (s *Server) OnTraffic(c gnet.Conn) (action gnet.Action) { return gnet.Close } - ws := c.Context().(*socket.ClientData).Wsmsg + ws := c.Context().(*service.ClientData).Wsmsg tt, len1 := ws.ReadBufferBytes(c) if tt == gnet.Close { @@ -169,7 +170,7 @@ const CROSS_DOMAIN = " candidates[j].Priority + // }) + + // // 执行 + // for _, eff := range candidates { + // ctx.Effect = eff + // keep := eff.Apply(ctx) + + // if !keep { + // // 持续回合结束 / 返回 false 的 effect 删除 + // c.removeEffect(eff) + // } + + // if ctx.Done { + // break // 被拦截 + // } + // } + } + +} diff --git a/logic/service/fight/fight.go b/logic/service/fight/fight.go deleted file mode 100644 index 94fa40c25..000000000 --- a/logic/service/fight/fight.go +++ /dev/null @@ -1,130 +0,0 @@ -package fight - -import ( - "blazing/common/data/socket" - "blazing/common/socket/handler" - "blazing/logic/service/fight/info" - "strings" - - "github.com/google/uuid" - "github.com/jinzhu/copier" -) - -var FightCache = make(map[string]*info.NoteReadyToFightInfo) //默认our是房主 - -func ReadyFight(c *socket.Player) { - tt, _ := FightCache[c.FightID] - t1 := handler.NewTomeeHeader(2504, c.Info.UserID) - rett := info.FightStartOutboundInfo{ - IsCanAuto: 0, - } - copier.Copy(&rett.Info1, &c.Info.PetList[0]) //复制自己的信息 - switch tt.FightId { //判断战斗类型 - case 1: - //1v1 - - if c.Info.UserID == tt.OwnerID { //这个时候是房主发来的消息 - tt.AFinished = true - if tt.BFinished { - - copier.Copy(&rett.Info2, &tt.OpponentPetList[0]) //复制对方信息 - c.SendPack(t1.Pack(&rett)) //给自己发 - tt.Opp.SendPack(t1.Pack(&rett)) //给对方发 - } - - } else { - tt.BFinished = true - if tt.AFinished { //如果房主完成 - - copier.Copy(&rett.Info2, &tt.OurPetList[0]) //复制房主信息,因为这时候不是房主发来的消息 - c.SendPack(t1.Pack(&rett)) //给自己发 - tt.Our.SendPack(t1.Pack(&rett)) //给房主发 - } - } - - case 3: //野怪战斗 - - copier.Copy(&rett.Info2, &tt.OpponentPetList[0]) - rett.Info1.UserID = c.Info.UserID //用户ID复制进去 - c.SendPack(t1.Pack(&rett)) - } - -} -func NewFight(i *info.NoteReadyToFightInfo, plays *socket.Player) { - - t12, _ := uuid.NewV7() - uuid := strings.Replace(t12.String(), "-", "", -1) //绑定战斗ID - FightCache[uuid] = i - //先发送战斗准备包 - switch i.FightId { - case 1: - //1v1 - - case 3: //野怪战斗 - - t1 := handler.NewTomeeHeader(2503, plays.Info.UserID) - - plays.FightID = uuid //绑定战斗ID - plays.SendPack(t1.Pack(i)) //准备包由各自发,因为协议不一样 - - } - - //调用技能产生effect参数后,创建effect实例,而非技能创建 - c := info.NewBattleContainer1v1(*i) //创建战斗容器 - t := info.BattleSkillEntity{} // - t.SideEffectArgs = []int{1, 2, 3} - //先提交effecet后然后计算伤害 - - //物理和特殊,百分比和固定伤害也算,真实伤害不分类别,故直接扣血就行,不需要计算 - if t.Category() == info.Category.PHYSICAL || t.Category() == info.Category.SPECIAL { - - for _, v := range c.Effects { - v.Exec(func(e info.Effect) bool { - return e.PreDamage() //执行预处理效果 - }) - } - - // Apply pre-damage effects for pet sources - // battle.applyEffects(context, EffectTrigger.PreDamage) - // if (context.crit) { - // battle.applyEffects(context, EffectTrigger.OnCritPreDamage) // Trigger crit pre-damage effects - // } - //假如说这里需要能力提升 - // c.Exec(func(e Effect) func() { - // return e.OnBeforeAddMark() - // }) - //添加印记前的效果如果有任何一个false,说明组织了添加效果 - //这里能力提升 - // c.Exec(func(e Effect) bool { - // return e.OnAnyMarkAdded() - // }) - - // var candidates []*Effect - // for _, eff := range c.Effects { - // if eff.Trigger == trigger { - // candidates = append(candidates, eff) - // } - // } - - // // 按优先级排序 - // sort.SliceStable(candidates, func(i, j int) bool { - // return candidates[i].Priority > candidates[j].Priority - // }) - - // // 执行 - // for _, eff := range candidates { - // ctx.Effect = eff - // keep := eff.Apply(ctx) - - // if !keep { - // // 持续回合结束 / 返回 false 的 effect 删除 - // c.removeEffect(eff) - // } - - // if ctx.Done { - // break // 被拦截 - // } - // } - } - -} diff --git a/logic/service/fight/info.go b/logic/service/fight/info.go new file mode 100644 index 000000000..f98df33b4 --- /dev/null +++ b/logic/service/fight/info.go @@ -0,0 +1,60 @@ +package fight + +import ( + "blazing/logic/service" +) + +// 野怪对战包 +type FightNpcMonsterInboundInfo struct { + Head service.TomeeHeader `cmd:"2408" struc:"[0]pad"` + // Number 地图刷新怪物结构体对应的序号(1-9的位置序号) + // @UInt long类型,使用uint32保持无符号特性 + Number uint32 `fieldDesc:"地图刷新怪物结构体对应的序号 1 - 9 的位置序号" ` +} + +type NullOutboundInfo struct { +} + +// 准备战斗包 +type ReadyToFightInboundInfo struct { + Head service.TomeeHeader `cmd:"2404" struc:"[0]pad"` +} + +// 战斗逃跑 +type EscapeFightInboundInfo struct { + Head service.TomeeHeader `cmd:"2410" struc:"[0]pad"` +} + +// FightOverInfo 战斗结束信息结构体 2506 +type FightOverInfo struct { + Reason uint32 // 固定值0 + WinnerId uint32 // 胜者的米米号 野怪为0 + TwoTimes uint32 // 双倍经验剩余次数 + ThreeTimes uint32 // 三倍经验剩余次数 + AutoFightTimes uint32 // 自动战斗剩余次数 + EnergyTimes uint32 // 能量吸收器剩余次数 + LearnTimes uint32 // 双倍学习器剩余次数 +} + +// HandleFightInviteInboundInfo 处理战斗邀请的入站消息 +// 回空包就行 +type HandleFightInviteInboundInfo struct { + Head service.TomeeHeader `cmd:"2403" struc:"[0]pad"` + UserID uint32 `json:"userId" codec:"userId,uint"` // 邀请我对战人的userid + Flag uint32 `json:"flag" codec:"flag,uint"` // 1为同意对战 0为取消对战 + Mode uint32 `json:"mode" codec:"mode,uint"` // 战斗类型 1 = 1v1 2 = 6v6 +} + +// 2502的回复包 PVP邀请消息 +type NoteHandleFightInviteOutboundInfo struct { + UserID uint32 + Nickname string `struc:"[16]byte"` // 固定长度16字节 + Result uint32 // 0=拒绝 1=同意 2=在线超6小时 3=无出战精灵 4=不在线 +} + +// 实现入站消息接口(Go中通过方法集隐式实现) +type UseSkillInboundInfo struct { + Head service.TomeeHeader `cmd:"2405" struc:"[0]pad"` + // 技能id, + SkillId uint32 +} diff --git a/logic/service/fight/info/fight.go b/logic/service/fight/info/info.go similarity index 73% rename from logic/service/fight/info/fight.go rename to logic/service/fight/info/info.go index 1f126d568..2b3b7e3ab 100644 --- a/logic/service/fight/info/fight.go +++ b/logic/service/fight/info/info.go @@ -1,39 +1,10 @@ package info import ( - "blazing/common/data/socket" - "blazing/common/socket/handler" "blazing/modules/blazing/model" "fmt" ) -// 野怪对战包 -type FightNpcMonsterInboundInfo struct { - Head handler.TomeeHeader `cmd:"2408" struc:"[0]pad"` - // Number 地图刷新怪物结构体对应的序号(1-9的位置序号) - // @UInt long类型,使用uint32保持无符号特性 - Number uint32 `fieldDesc:"地图刷新怪物结构体对应的序号 1 - 9 的位置序号" ` -} - -type NullOutboundInfo struct { -} - -// 准备战斗包 -type ReadyToFightInboundInfo struct { - Head handler.TomeeHeader `cmd:"2404" struc:"[0]pad"` -} - -type FightStartOutboundInfo struct { - // @UInt long类型 - IsCanAuto uint32 `fieldDesc:"是否自动 默认给0 怀疑是自动战斗器使用的" ` - - // 当前战斗精灵信息1(前端通过userid判断是否为我方) - Info1 FightPetInfo `fieldDesc:"当前战斗精灵的信息 可能不准.看前端代码是以userid来判断哪个结构体是我方的" serialize:"struct"` - - // 当前战斗精灵信息2(前端通过userid判断是否为我方) - Info2 FightPetInfo `fieldDesc:"当前战斗精灵的信息 可能不准.看前端代码是以userid来判断哪个结构体是我方的" serialize:"struct"` -} - // FightPetInfo 战斗精灵信息结构体,FightPetInfo类 type FightPetInfo struct { // 用户ID(野怪为0),@UInt long @@ -87,43 +58,15 @@ type NoteUseSkillOutboundInfo struct { SecondAttackInfo AttackValue // 本轮后手的精灵在释放技能结束后的状态 } -// 战斗逃跑 -type EscapeFightInboundInfo struct { - Head handler.TomeeHeader `cmd:"2410" struc:"[0]pad"` -} +type FightStartOutboundInfo struct { + // @UInt long类型 + IsCanAuto uint32 `fieldDesc:"是否自动 默认给0 怀疑是自动战斗器使用的" ` -// FightOverInfo 战斗结束信息结构体 2506 -type FightOverInfo struct { - Reason uint32 // 固定值0 - WinnerId uint32 // 胜者的米米号 野怪为0 - TwoTimes uint32 // 双倍经验剩余次数 - ThreeTimes uint32 // 三倍经验剩余次数 - AutoFightTimes uint32 // 自动战斗剩余次数 - EnergyTimes uint32 // 能量吸收器剩余次数 - LearnTimes uint32 // 双倍学习器剩余次数 -} + // 当前战斗精灵信息1(前端通过userid判断是否为我方) + Info1 FightPetInfo `fieldDesc:"当前战斗精灵的信息 可能不准.看前端代码是以userid来判断哪个结构体是我方的" serialize:"struct"` -// HandleFightInviteInboundInfo 处理战斗邀请的入站消息 -// 回空包就行 -type HandleFightInviteInboundInfo struct { - Head handler.TomeeHeader `cmd:"2403" struc:"[0]pad"` - UserID uint32 `json:"userId" codec:"userId,uint"` // 邀请我对战人的userid - Flag uint32 `json:"flag" codec:"flag,uint"` // 1为同意对战 0为取消对战 - Mode uint32 `json:"mode" codec:"mode,uint"` // 战斗类型 1 = 1v1 2 = 6v6 -} - -// 2502的回复包 PVP邀请消息 -type NoteHandleFightInviteOutboundInfo struct { - UserID uint32 - Nickname string `struc:"[16]byte"` // 固定长度16字节 - Result uint32 // 0=拒绝 1=同意 2=在线超6小时 3=无出战精灵 4=不在线 -} - -// 实现入站消息接口(Go中通过方法集隐式实现) -type UseSkillInboundInfo struct { - Head handler.TomeeHeader `cmd:"2405" struc:"[0]pad"` - // 技能id, - SkillId uint32 + // 当前战斗精灵信息2(前端通过userid判断是否为我方) + Info2 FightPetInfo `fieldDesc:"当前战斗精灵的信息 可能不准.看前端代码是以userid来判断哪个结构体是我方的" serialize:"struct"` } type FightUserInfo struct { @@ -148,17 +91,17 @@ type NoteReadyToFightInfo struct { FightId EnumBattleMode `fieldDesc:"战斗类型ID 但前端好像没有用到 与野怪战斗为3,与人战斗似乎是1" ` // 我方信息 - OurInfo FightUserInfo `fieldDesc:"我方信息" serialize:"struct"` - Our *socket.Player `struc:"skip"` - OurPetListLen uint32 `struc:"sizeof=OurPetList"` + OurInfo FightUserInfo `fieldDesc:"我方信息" serialize:"struct"` + // Our *socket.Player `struc:"skip"` + OurPetListLen uint32 `struc:"sizeof=OurPetList"` // 我方携带精灵的信息 // ArrayList,使用切片模拟动态列表 OurPetList []ReadyFightPetInfo `fieldDesc:"我方携带精灵的信息" serialize:"lengthFirst,lengthType=uint16,type=structArray"` // 对方信息 - OpponentInfo FightUserInfo `fieldDesc:"对方信息" serialize:"struct"` - Opp *socket.Player `struc:"skip"` - OpponentPetListLen uint32 `struc:"sizeof=OpponentPetList"` + OpponentInfo FightUserInfo `fieldDesc:"对方信息" serialize:"struct"` + //Opp *socket.Player `struc:"skip"` + OpponentPetListLen uint32 `struc:"sizeof=OpponentPetList"` // 敌方的精灵信息 // 野怪战斗时:客户端接收此包前已生成精灵PetInfo,将部分信息写入该列表 OpponentPetList []ReadyFightPetInfo `fieldDesc:"敌方的精灵信息 如果是野怪 那么再给客户端发送这个包体时就提前生成好了这只精灵的PetInfo,然后把从PetInfo中把部分信息写入到这个敌方的精灵信息中再发送这个包结构体" serialize:"lengthFirst,lengthType=uint16,type=structArray"` diff --git a/logic/service/friend/friend.go b/logic/service/friend/friend.go index 445b113fe..0c13c702e 100644 --- a/logic/service/friend/friend.go +++ b/logic/service/friend/friend.go @@ -1,10 +1,10 @@ package friend -import "blazing/common/socket/handler" +import "blazing/logic/service" //基地查看好友列表 type SeeOnlineInboundInfo struct { - Head handler.TomeeHeader `cmd:"2157" struc:"[0]pad"` + Head service.TomeeHeader `cmd:"2157" struc:"[0]pad"` UserIdsLen uint32 `json:"userIdsLen" struc:"sizeof=UserIds"` UserIds []uint32 `json:"userIds" ` diff --git a/logic/service/item/item.go b/logic/service/item/item.go index 3085e3ece..696a76db6 100644 --- a/logic/service/item/item.go +++ b/logic/service/item/item.go @@ -1,10 +1,10 @@ package item -import "blazing/common/socket/handler" +import "blazing/logic/service" // 实现了入站消息接口(Go中通过方法集隐式实现) type ItemListInboundInfo struct { - Head handler.TomeeHeader `cmd:"2605" struc:"[0]pad"` + Head service.TomeeHeader `cmd:"2605" struc:"[0]pad"` // 查询物品id的开始,对应Java的@UInt long Param1 uint32 `fieldDesc:"查询物品id的开始" messageType:"Item_List"` // 查询物品id的结尾,对应Java的@UInt long diff --git a/logic/service/login/LoginSidInfo.go b/logic/service/login/LoginSidInfo.go index ead611be8..4640c5235 100644 --- a/logic/service/login/LoginSidInfo.go +++ b/logic/service/login/LoginSidInfo.go @@ -2,7 +2,8 @@ package login import ( "blazing/common/data/share" - "blazing/common/socket/handler" + "blazing/logic/service" + "blazing/modules/blazing/model" "context" "encoding/hex" @@ -12,7 +13,7 @@ import ( // LoginSidInfo 登录携带的凭证结构体 type InInfo struct { //这里直接使用组合来实现将传入的原始头部数据和结构体参数序列化 - Head handler.TomeeHeader `cmd:"1001" struc:"[0]pad"` //玩家登录 + Head service.TomeeHeader `cmd:"1001" struc:"[0]pad"` //玩家登录 Sid []byte `struc:"[16]byte"` // 登录会话ID,固定长度16字节 diff --git a/logic/service/login/create_player.go b/logic/service/login/create_player.go index 61ea93608..46d0b24ae 100644 --- a/logic/service/login/create_player.go +++ b/logic/service/login/create_player.go @@ -1,9 +1,9 @@ package login -import "blazing/common/socket/handler" +import "blazing/logic/service" type CreatePlayerInboundInfo struct { //这里直接使用组合来实现将传入的原始头部数据和结构体参数序列化 - Head handler.TomeeHeader `cmd:"108" struc:"[0]pad"` //玩家登录 + Head service.TomeeHeader `cmd:"108" struc:"[0]pad"` //玩家登录 // 玩家昵称,@ArraySerialize注解 Nickname string `struc:"[16]byte"` // 固定长度16字节 diff --git a/logic/service/maphot/maphot.go b/logic/service/maphot/maphot.go index a2eb326c7..4dba49005 100644 --- a/logic/service/maphot/maphot.go +++ b/logic/service/maphot/maphot.go @@ -1,12 +1,12 @@ package maphot import ( - "blazing/common/socket/handler" + "blazing/logic/service" "blazing/logic/service/space" ) type InInfo struct { - Head handler.TomeeHeader `cmd:"1004" struc:"[0]pad"` //玩家登录 + Head service.TomeeHeader `cmd:"1004" struc:"[0]pad"` //玩家登录 } // OutInfo 表示地图热度的出站消息 diff --git a/logic/service/maps/mapin.go b/logic/service/maps/mapin.go index 103c849aa..e4ef42a4e 100644 --- a/logic/service/maps/mapin.go +++ b/logic/service/maps/mapin.go @@ -1,10 +1,10 @@ package maps import ( - "blazing/common/data/socket" "blazing/common/data/xmlres" - "blazing/common/socket/handler" + "blazing/logic/service" "blazing/logic/service/space" + "blazing/modules/blazing/model" "math/rand" "strings" @@ -15,7 +15,7 @@ import ( ) type InInfo struct { - Head handler.TomeeHeader `cmd:"2001" struc:"[0]pad"` //切换地图 + Head service.TomeeHeader `cmd:"2001" struc:"[0]pad"` //切换地图 // 地图类型 MapType uint32 @@ -29,7 +29,7 @@ type InInfo struct { func (t *InInfo) Broadcast(mapid uint32, o OutInfo) { - space.GetSpace(mapid).Range(func(playerID uint32, player *socket.Player) bool { + space.GetSpace(mapid).Range(func(playerID uint32, player service.PlayerI) bool { t.Head.Result = 0 player.SendPack(t.Head.Pack(&o)) @@ -38,7 +38,7 @@ func (t *InInfo) Broadcast(mapid uint32, o OutInfo) { } // 刷怪具体实现 -func (t *InInfo) SpawnMonsters(c *socket.Player, isfrist bool) { +func (t *InInfo) SpawnMonsters(c *service.Player, isfrist bool) { // 获取当前地图的怪物配置 if c == nil || c.Info.MapID == 0 { //用户离线 @@ -55,7 +55,7 @@ func (t *InInfo) SpawnMonsters(c *socket.Player, isfrist bool) { } // 创建数据包 - tt := handler.NewTomeeHeader(2004, c.Info.UserID) + tt := service.NewTomeeHeader(2004, c.Info.UserID) if isfrist { t.monsters = generateThreeUniqueNumbers() @@ -81,16 +81,16 @@ func RandomStringFromSlice(s []string) string { } // 应该根据怪物信息决定后端生成 -func (t *InInfo) genMonster(mapid uint32) *socket.OgreInfo { +func (t *InInfo) genMonster(mapid uint32) *service.OgreInfo { // 设置怪物信息 - t1 := socket.OgreInfo{} + t1 := service.OgreInfo{} mapss, ok := xmlres.MonsterMap[gconv.Int(mapid)] if ok && mapss.Monsters != nil { for i, m := range mapss.Monsters.Monsters { //这里是9个 id := strings.Split(m.ID, " ") lv := strings.Split(m.Lv, " ") - ttt := socket.OgrePetInfo{ + ttt := service.OgrePetInfo{ Id: gconv.Uint32(RandomStringFromSlice(id)), } if ttt.Id != 0 { @@ -103,7 +103,7 @@ func (t *InInfo) genMonster(mapid uint32) *socket.OgreInfo { } - t2 := socket.OgreInfo{} + t2 := service.OgreInfo{} for i := 0; i < 3; i++ { t2.Data[t.monsters[i]] = t1.Data[t.monsters[i]] @@ -291,14 +291,3 @@ func NewOutInfo() *OutInfo { return l } - -func LeaveMap(c *socket.Player) { - t := handler.NewTomeeHeader(2002, c.Info.UserID) - - space.GetSpace(c.Info.MapID).Range(func(playerID uint32, player *socket.Player) bool { - - player.SendPack(t.Pack(&LeaveMapOutboundInfo{UserID: c.Info.UserID})) - return true - }) - space.GetSpace(c.Info.MapID).Delete(c.Info.UserID) -} diff --git a/logic/service/maps/maplist.go b/logic/service/maps/maplist.go index 5fc09943b..3a88db6f1 100644 --- a/logic/service/maps/maplist.go +++ b/logic/service/maps/maplist.go @@ -1,11 +1,9 @@ package maps -import ( - "blazing/common/socket/handler" -) +import "blazing/logic/service" type ListMapPlayerInboundInfo struct { - Head handler.TomeeHeader `cmd:"2003" struc:"[0]pad"` //切换地图 + Head service.TomeeHeader `cmd:"2003" struc:"[0]pad"` //切换地图 } type ListMapPlayerOutboundInfo struct { diff --git a/logic/service/maps/mapout.go b/logic/service/maps/mapout.go index 6ff000ba2..8424e422a 100644 --- a/logic/service/maps/mapout.go +++ b/logic/service/maps/mapout.go @@ -1,8 +1,7 @@ package maps import ( - "blazing/common/data/socket" - "blazing/common/socket/handler" + "blazing/logic/service" "blazing/logic/service/space" ) @@ -12,15 +11,26 @@ type LeaveMapOutboundInfo struct { } type LeaveMapInboundInfo struct { - Head handler.TomeeHeader `cmd:"2002" struc:"[0]pad"` //切换地图 + Head service.TomeeHeader `cmd:"2002" struc:"[0]pad"` //切换地图 } func (t *LeaveMapInboundInfo) Broadcast(mapid uint32, o LeaveMapOutboundInfo) { - space.GetSpace(mapid).Range(func(playerID uint32, player *socket.Player) bool { + space.GetSpace(mapid).Range(func(playerID uint32, player service.PlayerI) bool { t.Head.Result = 0 player.SendPack(t.Head.Pack(&o)) return true }) } + +func LeaveMap(c service.PlayerI) { + t := service.NewTomeeHeader(2002, c.ID()) + + space.GetSpace(c.MapID()).Range(func(playerID uint32, player service.PlayerI) bool { + + player.SendPack(t.Pack(&LeaveMapOutboundInfo{UserID: c.ID()})) + return true + }) + space.GetSpace(c.MapID()).Delete(c.ID()) +} diff --git a/logic/service/nono/nono.go b/logic/service/nono/nono.go index a5c5431c2..6f70878f7 100644 --- a/logic/service/nono/nono.go +++ b/logic/service/nono/nono.go @@ -1,6 +1,6 @@ package nono -import "blazing/common/socket/handler" +import "blazing/logic/service" // NonoOutboundInfo 用于表示Nono相关的出站信息 type NonoOutboundInfo struct { @@ -55,7 +55,7 @@ type NonoOutboundInfo struct { type NonoInboundInfo struct { // 消息头部,命令ID对应MessageCommandIDRegistry.Nono_Info - Head handler.TomeeHeader `cmd:"9003" struc:"[0]pad"` + Head service.TomeeHeader `cmd:"9003" struc:"[0]pad"` // 米米号,对应Java的@UInt long类型 UserID uint32 `fieldDescription:"米米号" struc:"uint32" uint:"true"` diff --git a/logic/service/pet/list.go b/logic/service/pet/list.go index 6eb3feb9e..f19e3bf2b 100644 --- a/logic/service/pet/list.go +++ b/logic/service/pet/list.go @@ -1,9 +1,9 @@ package pet -import "blazing/common/socket/handler" +import "blazing/logic/service" type GetPetListInboundEmpty struct { - Head handler.TomeeHeader `cmd:"2303" struc:"[0]pad"` + Head service.TomeeHeader `cmd:"2303" struc:"[0]pad"` } type GetPetListOutboundInfo struct { ShortInfoListLen uint32 `struc:"int32,sizeof=ShortInfoList"` diff --git a/logic/service/pet/pet.go b/logic/service/pet/pet.go index 95e83c6f7..6dbfdb9fb 100644 --- a/logic/service/pet/pet.go +++ b/logic/service/pet/pet.go @@ -1,12 +1,12 @@ package pet import ( - "blazing/common/socket/handler" + "blazing/logic/service" "blazing/modules/blazing/model" ) type InInfo struct { - Head handler.TomeeHeader `cmd:"2301" struc:"[0]pad"` + Head service.TomeeHeader `cmd:"2301" struc:"[0]pad"` CatchTime uint32 } @@ -25,7 +25,7 @@ type PetReleaseOutboundInfo struct { // 放入背包或者加入仓库 type PetReleaseInboundInfo struct { - Head handler.TomeeHeader `cmd:"2304" struc:"[0]pad"` + Head service.TomeeHeader `cmd:"2304" struc:"[0]pad"` CatchTime uint32 `json:"catch_time" fieldDescription:"精灵生成时间" autoCodec:"true" uint:"true"` Flag uint32 `json:"flag" fieldDescription:"0为放入仓库,1为放入背包" autoCodec:"true" uint:"true"` } diff --git a/common/data/socket/player.go b/logic/service/player.go similarity index 80% rename from common/data/socket/player.go rename to logic/service/player.go index 7e70eb252..645fa006e 100644 --- a/common/data/socket/player.go +++ b/logic/service/player.go @@ -1,210 +1,264 @@ -package socket - -import ( - "blazing/common/utils" - - "blazing/modules/blazing/model" - "blazing/modules/blazing/service" - "context" - "fmt" - "sync" - "time" - - "github.com/gobwas/ws" - "github.com/gobwas/ws/wsutil" - "github.com/gogf/gf/v2/frame/g" - "github.com/panjf2000/gnet/pkg/logging" - "github.com/tnnmigga/enum" -) - -var Mainplayer = &utils.SyncMap[uint32, *Player]{} //玩家数据 - -func (c *Conn) SendPack(bytes []byte) error { - if t, ok := c.MainConn.Context().(*ClientData); ok { - if t.Wsmsg.Upgraded { - // This is the echo server - err := wsutil.WriteServerMessage(c.MainConn, ws.OpBinary, bytes) - if err != nil { - logging.Infof("conn[%v] [err=%v]", c.MainConn.RemoteAddr().String(), err.Error()) - return err - } - } else { - - _, err := c.MainConn.Write(bytes) - if err != nil { - logging.Error(err) - - } - } - } - - return nil -} - -type OgreInfo struct { - Data [9]OgrePetInfo -} - -type OgrePetInfo struct { - Id uint32 - Shiny uint32 - Lv uint32 `struc:"skip"` //等级 -} - -type Player struct { - MainConn *Conn - - IsLogin bool //是否登录 - mu sync.Mutex - - loginChan chan struct{} // 登录完成通知通道 - Info *model.PlayerInfo - StopChan chan struct{} //停止刷怪协程 - - context.Context - Playerinvite uint32 //当前邀请的玩家ID - Onlinetime uint32 //当前登录时间 - OgreInfo *OgreInfo - FightID string //绑定战斗标识 替代本身的是否战斗标记 //IsFighting bool - //FightInfo info.NoteReadyToFightInfo -} - -// PlayerOption 定义配置 Player 的函数类型 -type PlayerOption func(*Player) - -func WithConn(c *Conn) PlayerOption { - return func(p *Player) { - p.MainConn = c - } -} - -// NewPlayer 使用 Options 模式创建 Player 实例 -func NewPlayer(opts ...PlayerOption) *Player { - p := &Player{ - loginChan: make(chan struct{}), - } - for _, opt := range opts { - opt(p) - } - return p -} - -func (p *Player) SendPack(b []byte) error { - // fmt.Println("发送数据包", len(b)) - err := p.MainConn.SendPack(b) - return err -} -func (p *Player) Cheak(b error) { - if b != nil { - g.Log().Error(context.Background(), "出现错误", p.Info.UserID, b.Error()) - } - -} - -// Save 保存玩家数据 -func (p *Player) Save() { - - p.Info.TimeToday = p.Info.TimeToday + uint32(time.Now().Unix()) - uint32(p.Onlinetime) //保存电池时间 - p.Onlinetime = uint32(time.Now().Unix()) - - service.NewUserService(p.Info.UserID).Save(p.Info) - -} - -// IsLoggedIn 检查是否已登录 -func (lw *Player) IsLoggedIn() bool { - lw.mu.Lock() - defer lw.mu.Unlock() - return lw.IsLogin -} - -// WaitForLogin 等待登录完成,无超时 -func (lw *Player) WaitForLogin() error { - if lw.IsLoggedIn() { - return nil - } - - // 阻塞等待登录完成 - <-lw.loginChan - return nil -} - -// WaitForLoginWithTimeout 带超时的登录等待 -func (lw *Player) WaitForLoginWithTimeout(timeout time.Duration) error { - if lw.IsLoggedIn() { - return nil - } - - // 使用定时器实现超时 - timer := time.NewTimer(timeout) - defer timer.Stop() - - select { - case <-lw.loginChan: - return nil - case <-timer.C: - return fmt.Errorf("登录等待超时: %v", timeout) - } -} - -// WaitForLoginWithCtx 带上下文的登录等待 -func (lw *Player) WaitForLoginWithCtx(ctx context.Context) error { - if lw.IsLoggedIn() { - return nil - } - - select { - case <-lw.loginChan: - return nil - case <-ctx.Done(): - return ctx.Err() // 上下文取消或超时 - } -} - -// CompleteLogin 标记登录完成并通知等待者 -func (lw *Player) CompleteLogin() { - lw.mu.Lock() - defer lw.mu.Unlock() - - if !lw.IsLogin { - lw.IsLogin = true - close(lw.loginChan) // 关闭通道以通知所有等待者 - } -} - -// 战斗模式 -type EnumBattleMode int - -var BattleMode_PVP = enum.New[struct { - PVP_1V1 EnumBattleMode `enum:"1"` - PVP_6V6 EnumBattleMode `enum:"2"` -}]() -var Playerinvitemap map[uint32][]Playerinvite = make(map[uint32][]Playerinvite) //玩家邀请信息 ,比如一个玩家被多人邀请对战 - -type Playerinvite struct { //挂载到[]Playerinvite上? 被邀请者->邀请者 - InviteID uint32 // 邀请者 - InviteTime EnumBattleMode //游戏模式 -} - -// 邀请玩家加入战斗 邀请者,被邀请者,邀请模式 -func (lw *Player) InvitePlayerToBattle(target int64, mode EnumBattleMode) { - t, ok := Playerinvitemap[uint32(target)] //被邀请者是否被邀请过 - if ok { //说明存在被邀请 - t = append(t, Playerinvite{uint32(lw.Info.UserID), mode}) - Playerinvitemap[uint32(target)] = t - } else { - Playerinvitemap[uint32(target)] = []Playerinvite{{uint32(lw.Info.UserID), mode}} - } - - lw.Playerinvite = uint32(target) -} - -// 取消对战邀请 -func (lw *Player) CancelBattle() { - - if lw.Playerinvite == 0 { - return - } - delete(Playerinvitemap, uint32(lw.Playerinvite)) //删除玩家邀请信息 - lw.Playerinvite = 0 -} +package service + +import ( + "blazing/common/utils" + "blazing/logic/service/fight/info" + + "blazing/modules/blazing/model" + "blazing/modules/blazing/service" + "context" + "fmt" + "sync" + "time" + + "github.com/gobwas/ws" + "github.com/gobwas/ws/wsutil" + "github.com/gogf/gf/v2/frame/g" + "github.com/panjf2000/gnet/pkg/logging" + "github.com/tnnmigga/enum" +) + +func ConutPlayer() int { + + count := 0 + Mainplayer.Range(func(uint32, *Player) bool { + count++ + return true // 继续遍历 + }) + return count +} + +type ClientData struct { + IsCrossDomain bool //是否跨域过 + Player *Player //客户实体 + //UserID uint32 + + Wsmsg *WsCodec +} + +func NewClientData() *ClientData { + cd := ClientData{ + IsCrossDomain: false, + Player: nil, + + Wsmsg: &WsCodec{}, + } + return &cd + +} + +var Mainplayer = &utils.SyncMap[uint32, *Player]{} //玩家数据 + +func (c *Conn) SendPack(bytes []byte) error { + if t, ok := c.MainConn.Context().(*ClientData); ok { + if t.Wsmsg.Upgraded { + // This is the echo server + err := wsutil.WriteServerMessage(c.MainConn, ws.OpBinary, bytes) + if err != nil { + logging.Infof("conn[%v] [err=%v]", c.MainConn.RemoteAddr().String(), err.Error()) + return err + } + } else { + + _, err := c.MainConn.Write(bytes) + if err != nil { + logging.Error(err) + + } + } + } + + return nil +} + +type OgreInfo struct { + Data [9]OgrePetInfo +} + +type OgrePetInfo struct { + Id uint32 + Shiny uint32 + Lv uint32 `struc:"skip"` //等级 +} + +type Player struct { + MainConn *Conn + + IsLogin bool //是否登录 + mu sync.Mutex + + loginChan chan struct{} // 登录完成通知通道 + Info *model.PlayerInfo + StopChan chan struct{} //停止刷怪协程 + + context.Context + Playerinvite uint32 //当前邀请的玩家ID + Onlinetime uint32 //当前登录时间 + OgreInfo *OgreInfo + FightC *FightC //绑定战斗标识 替代本身的是否战斗标记 //IsFighting bool + //FightInfo info.NoteReadyToFightInfo +} + +// PlayerOption 定义配置 Player 的函数类型 +type PlayerOption func(*Player) + +func WithConn(c *Conn) PlayerOption { + return func(p *Player) { + p.MainConn = c + } +} + +// NewPlayer 使用 Options 模式创建 Player 实例 +func NewPlayer(opts ...PlayerOption) *Player { + p := &Player{ + loginChan: make(chan struct{}), + } + for _, opt := range opts { + opt(p) + } + return p +} + +func (p *Player) GetInfo() model.PlayerInfo { + + return *p.Info +} + +func (p *Player) ID() uint32 { + + return p.Info.UserID +} +func (p *Player) MapID() uint32 { + + return p.Info.MapID +} + +func (p *Player) SendPack(b []byte) error { + // fmt.Println("发送数据包", len(b)) + err := p.MainConn.SendPack(b) + return err +} +func (p *Player) Cheak(b error) { + if b != nil { + g.Log().Error(context.Background(), "出现错误", p.Info.UserID, b.Error()) + } + +} + +func (p *Player) SendReadyToFightInfo(b info.FightStartOutboundInfo) { + t1 := NewTomeeHeader(2504, p.Info.UserID) + p.SendPack(t1.Pack(&b)) +} +func (p *Player) SendNoteReadyToFightInfo(b info.NoteReadyToFightInfo) { + t1 := NewTomeeHeader(2503, p.Info.UserID) + + p.SendPack(t1.Pack(&b)) //准备包由各自发,因为协议不一样 +} + +// Save 保存玩家数据 +func (p *Player) Save() { + + p.Info.TimeToday = p.Info.TimeToday + uint32(time.Now().Unix()) - uint32(p.Onlinetime) //保存电池时间 + p.Onlinetime = uint32(time.Now().Unix()) + + service.NewUserService(p.Info.UserID).Save(p.Info) + +} + +// IsLoggedIn 检查是否已登录 +func (lw *Player) IsLoggedIn() bool { + lw.mu.Lock() + defer lw.mu.Unlock() + return lw.IsLogin +} + +// WaitForLogin 等待登录完成,无超时 +func (lw *Player) WaitForLogin() error { + if lw.IsLoggedIn() { + return nil + } + + // 阻塞等待登录完成 + <-lw.loginChan + return nil +} + +// WaitForLoginWithTimeout 带超时的登录等待 +func (lw *Player) WaitForLoginWithTimeout(timeout time.Duration) error { + if lw.IsLoggedIn() { + return nil + } + + // 使用定时器实现超时 + timer := time.NewTimer(timeout) + defer timer.Stop() + + select { + case <-lw.loginChan: + return nil + case <-timer.C: + return fmt.Errorf("登录等待超时: %v", timeout) + } +} + +// WaitForLoginWithCtx 带上下文的登录等待 +func (lw *Player) WaitForLoginWithCtx(ctx context.Context) error { + if lw.IsLoggedIn() { + return nil + } + + select { + case <-lw.loginChan: + return nil + case <-ctx.Done(): + return ctx.Err() // 上下文取消或超时 + } +} + +// CompleteLogin 标记登录完成并通知等待者 +func (lw *Player) CompleteLogin() { + lw.mu.Lock() + defer lw.mu.Unlock() + + if !lw.IsLogin { + lw.IsLogin = true + close(lw.loginChan) // 关闭通道以通知所有等待者 + } +} + +// 战斗模式 +type EnumBattleMode int + +var BattleMode_PVP = enum.New[struct { + PVP_1V1 EnumBattleMode `enum:"1"` + PVP_6V6 EnumBattleMode `enum:"2"` +}]() +var Playerinvitemap map[uint32][]Playerinvite = make(map[uint32][]Playerinvite) //玩家邀请信息 ,比如一个玩家被多人邀请对战 + +type Playerinvite struct { //挂载到[]Playerinvite上? 被邀请者->邀请者 + InviteID uint32 // 邀请者 + InviteTime EnumBattleMode //游戏模式 +} + +// 邀请玩家加入战斗 邀请者,被邀请者,邀请模式 +func (lw *Player) InvitePlayerToBattle(target int64, mode EnumBattleMode) { + t, ok := Playerinvitemap[uint32(target)] //被邀请者是否被邀请过 + if ok { //说明存在被邀请 + t = append(t, Playerinvite{uint32(lw.Info.UserID), mode}) + Playerinvitemap[uint32(target)] = t + } else { + Playerinvitemap[uint32(target)] = []Playerinvite{{uint32(lw.Info.UserID), mode}} + } + + lw.Playerinvite = uint32(target) +} + +// 取消对战邀请 +func (lw *Player) CancelBattle() { + + if lw.Playerinvite == 0 { + return + } + delete(Playerinvitemap, uint32(lw.Playerinvite)) //删除玩家邀请信息 + lw.Playerinvite = 0 +} diff --git a/logic/service/room/FitmentShowInfo.go b/logic/service/room/FitmentShowInfo.go index 9fc01f3a9..35b8366fb 100644 --- a/logic/service/room/FitmentShowInfo.go +++ b/logic/service/room/FitmentShowInfo.go @@ -1,6 +1,8 @@ package room -import "blazing/common/socket/handler" +import ( + "blazing/logic/service" +) // FitmentShowInfo 表示家具展示信息 type FitmentShowInfo struct { @@ -18,7 +20,7 @@ type FitmentShowInfo struct { // FitmentUseringInboundInfo FitmentUseringInboundInfo类,实现InboundMessage接口 type FitmentUseringInboundInfo struct { - Head handler.TomeeHeader `cmd:"10006" struc:"[0]pad"` //玩家登录 + Head service.TomeeHeader `cmd:"10006" struc:"[0]pad"` //玩家登录 // 需要获取基地信息的目标玩家账号ID TargetUserID uint32 `json:"targetUserId"` } @@ -45,12 +47,12 @@ type PetRoomListOutboundInfo struct { } type PetRoomListInboundInfo struct { - Head handler.TomeeHeader `cmd:"2324" struc:"[0]pad"` //玩家登录 + Head service.TomeeHeader `cmd:"2324" struc:"[0]pad"` //玩家登录 // 需要获取基地信息的目标玩家账号ID TargetUserID uint32 `json:"targetUserId"` } type FitmentAllInboundEmpty struct { - Head handler.TomeeHeader `cmd:"10007" struc:"[0]pad"` + Head service.TomeeHeader `cmd:"10007" struc:"[0]pad"` } type FitmentAllOutboundInfo struct { FitmentsLen uint32 `json:"fitmentsLen" struc:"sizeof=Fitments"` diff --git a/logic/service/service.go b/logic/service/service.go deleted file mode 100644 index 8a24040a8..000000000 --- a/logic/service/service.go +++ /dev/null @@ -1,48 +0,0 @@ -package service - -import ( - "blazing/common/data/socket" - "blazing/common/socket/errorcode" - "blazing/common/socket/handler" -) - -func GetPlayer(c *socket.Conn, userid uint32) *socket.Player { //TODO 这里待优化,可能存在内存泄漏问题 - c.Mu.Lock() - defer c.Mu.Unlock() - //检查player初始化,是否为conn初始后取map,防止二次连接后存在两个player - - clientdata := c.MainConn.Context().(*socket.ClientData) - if clientdata.Player != nil { - return clientdata.Player - } - - clientdata.Player = socket.NewPlayer( - - socket.WithConn(c), //注入conn - ) - - // gff := socket.NewClientData() - - // gff.Player = clientdata.Player - // c.MainConn.SetContext(gff) - socket.Mainplayer.Store(userid, clientdata.Player) - - return clientdata.Player - // return nil -} -func KickPlayer(userid uint32) { //踢出玩家 - //TODO 返回错误码 - //var player *entity.Player - if player1, ok := socket.Mainplayer.Load((userid)); ok { - //取成功,否则创建 - head := handler.NewTomeeHeader(1001, userid) - head.Result = uint32(errorcode.ErrorCodes.ErrAccountLoggedInElsewhere) - - player1.SendPack(head.Pack(nil)) - player1.MainConn.MainConn.Close() - // clientdata.Player = player - } - - //return player - // return nil -} diff --git a/logic/service/space/space.go b/logic/service/space/space.go index 63e1f7ae6..6c212d76d 100644 --- a/logic/service/space/space.go +++ b/logic/service/space/space.go @@ -1,34 +1,35 @@ package space import ( - "blazing/common/data/socket" "blazing/common/data/xmlres" "blazing/common/utils" + "blazing/logic/service" + "blazing/modules/blazing/model" "sync" ) // Space 针对Player的并发安全map,键为uint32类型 type Space struct { - mu sync.RWMutex // 读写锁,读多写少场景更高效 - data map[uint32]*socket.Player // 存储玩家数据的map,键为玩家ID - CanRefresh bool //是否能够刷怪 - ID uint32 // 地图ID - Name string //地图名称 - DefaultPos model.Pos //默认位置DefaultPos - Positions map[uint32]model.Pos //从上一个地图跳转后默认位置 + mu sync.RWMutex // 读写锁,读多写少场景更高效 + data map[uint32]service.PlayerI // 存储玩家数据的map,键为玩家ID + CanRefresh bool //是否能够刷怪 + ID uint32 // 地图ID + Name string //地图名称 + DefaultPos model.Pos //默认位置DefaultPos + Positions map[uint32]model.Pos //从上一个地图跳转后默认位置 } // NewSyncMap 创建一个新的玩家同步map func NewSpace() *Space { return &Space{ - data: make(map[uint32]*socket.Player), + data: make(map[uint32]service.PlayerI), } } // Get 根据玩家ID获取玩家实例 // 读操作使用RLock,允许多个goroutine同时读取 -func (m *Space) Get(playerID uint32) (*socket.Player, bool) { +func (m *Space) Get(playerID uint32) (service.PlayerI, bool) { m.mu.RLock() defer m.mu.RUnlock() val, exists := m.data[playerID] @@ -37,7 +38,7 @@ func (m *Space) Get(playerID uint32) (*socket.Player, bool) { // Set 存储玩家实例(按ID) // 写操作使用Lock,独占锁保证数据一致性 -func (m *Space) Set(playerID uint32, player *socket.Player) *Space { +func (m *Space) Set(playerID uint32, player service.PlayerI) *Space { m.mu.Lock() defer m.mu.Unlock() m.data[playerID] = player @@ -63,7 +64,7 @@ func (m *Space) Len() int { // Range 遍历所有玩家并执行回调函数 // 读操作使用RLock,遍历过程中不会阻塞其他读操作 -func (m *Space) Range(f func(playerID uint32, player *socket.Player) bool) { +func (m *Space) Range(f func(playerID uint32, player service.PlayerI) bool) { m.mu.RLock() defer m.mu.RUnlock() for id, player := range m.data { diff --git a/logic/service/space/walk.go b/logic/service/space/walk.go index b20cb9b31..ec069cf6a 100644 --- a/logic/service/space/walk.go +++ b/logic/service/space/walk.go @@ -1,13 +1,12 @@ package space import ( - "blazing/common/data/socket" - "blazing/common/socket/handler" + "blazing/logic/service" "blazing/modules/blazing/model" ) type InInfo struct { - Head handler.TomeeHeader `cmd:"2101" struc:"[0]pad"` //走路包 + Head service.TomeeHeader `cmd:"2101" struc:"[0]pad"` //走路包 // Flag: 0为走,1为飞行模式,@UInt long Flag uint32 @@ -23,11 +22,11 @@ func (t *InInfo) Broadcast(mapid uint32, o OutInfo) { //tt := planetmap //g.Dump(GetSpace(mapid).Len()) - GetSpace(mapid).Range(func(playerID uint32, player *socket.Player) bool { + GetSpace(mapid).Range(func(playerID uint32, player service.PlayerI) bool { t.Head.Result = 0 tt := t.Head.Pack(&o) - err := player.SendPack(tt) - player.Cheak(err) + player.SendPack(tt) + //player.Cheak(err) return true }) } diff --git a/logic/service/systemtime/System.go b/logic/service/systemtime/System.go index 8cd7c40e1..175743f11 100644 --- a/logic/service/systemtime/System.go +++ b/logic/service/systemtime/System.go @@ -1,13 +1,13 @@ package systemtime import ( - "blazing/common/socket/handler" + "blazing/logic/service" "time" ) // LoginSidInfo 登录携带的凭证结构体 type InInfo struct { //这里直接使用组合来实现将传入的原始头部数据和结构体参数序列化 - Head handler.TomeeHeader `cmd:"1002" struc:"[0]pad"` //玩家登录 + Head service.TomeeHeader `cmd:"1002" struc:"[0]pad"` //玩家登录 } diff --git a/logic/service/task/AcceptTask.go b/logic/service/task/AcceptTask.go index 58270079d..b0164a0aa 100644 --- a/logic/service/task/AcceptTask.go +++ b/logic/service/task/AcceptTask.go @@ -1,11 +1,11 @@ package task -import "blazing/common/socket/handler" +import "blazing/logic/service" // AcceptTaskInboundInfo 对应Java的AcceptTaskInboundInfo类 // 用于接收任务的入站信息 type AcceptTaskInboundInfo struct { - Head handler.TomeeHeader `cmd:"2201|2231" struc:"[0]pad"` + Head service.TomeeHeader `cmd:"2201|2231" struc:"[0]pad"` TaskId uint32 `json:"taskId" description:"任务ID"` // 任务ID,对应Java的@UInt long } diff --git a/logic/service/task/AddTask.go b/logic/service/task/AddTask.go index defecfcad..311f2315f 100644 --- a/logic/service/task/AddTask.go +++ b/logic/service/task/AddTask.go @@ -1,11 +1,11 @@ package task -import "blazing/common/socket/handler" +import "blazing/logic/service" // AddTaskBufInboundInfo 对应Java的AddTaskBufInboundInfo类 // 用于接收添加任务缓冲区的入站信息 type AddTaskBufInboundInfo struct { - Head handler.TomeeHeader `cmd:"2204|2235" struc:"[0]pad"` + Head service.TomeeHeader `cmd:"2204|2235" struc:"[0]pad"` TaskId uint32 `json:"taskId" description:"任务ID"` // 任务ID,对应Java的@UInt long TaskList []uint32 `struc:"[20]byte"` // 任务步骤信息,对应Java的@ArraySerialize注解 } diff --git a/logic/service/task/CompleteTask.go b/logic/service/task/CompleteTask.go index a6813d43f..c851826e3 100644 --- a/logic/service/task/CompleteTask.go +++ b/logic/service/task/CompleteTask.go @@ -1,9 +1,9 @@ package task -import "blazing/common/socket/handler" +import "blazing/logic/service" type CompleteTaskInboundInfo struct { - Head handler.TomeeHeader `cmd:"2202|2233" struc:"[0]pad"` + Head service.TomeeHeader `cmd:"2202|2233" struc:"[0]pad"` TaskId uint32 `json:"taskId" description:"任务ID"` // 任务ID,对应Java的@UInt long OutState uint32 `json:"outState" 分支"` // 当前状态,1表示完成任务,对应Java的@UInt long } diff --git a/logic/service/task/Delete_Task.go b/logic/service/task/Delete_Task.go index df69bae95..973c64c39 100644 --- a/logic/service/task/Delete_Task.go +++ b/logic/service/task/Delete_Task.go @@ -1,10 +1,10 @@ package task -import "blazing/common/socket/handler" +import "blazing/logic/service" // DeleteTaskInboundInfo 对应Java的DeleteTaskInboundInfo类 type DeleteTaskInboundInfo struct { - Head handler.TomeeHeader `cmd:"2205|2232" struc:"[0]pad"` + Head service.TomeeHeader `cmd:"2205|2232" struc:"[0]pad"` TaskId uint32 `json:"taskId" description:"任务ID"` // 使用uint64对应Java的@UInt long } type DeleteTaskOutboundInfo struct { diff --git a/logic/service/task/GetTask.go b/logic/service/task/GetTask.go index 4e5b49f08..267c520a9 100644 --- a/logic/service/task/GetTask.go +++ b/logic/service/task/GetTask.go @@ -1,7 +1,7 @@ package task import ( - "blazing/common/socket/handler" + "blazing/logic/service" "encoding/binary" "errors" @@ -9,7 +9,7 @@ import ( ) type GetTaskBufInboundInfo struct { - Head handler.TomeeHeader `cmd:"2203|2234" struc:"[0]pad"` + Head service.TomeeHeader `cmd:"2203|2234" struc:"[0]pad"` TaskId uint32 `json:"taskId" description:"任务ID"` // 任务ID,对应Java的@UInt long } diff --git a/common/data/socket/wscodec.go b/logic/service/wscodec.go similarity index 95% rename from common/data/socket/wscodec.go rename to logic/service/wscodec.go index d8dd965f0..c975a3e53 100644 --- a/common/data/socket/wscodec.go +++ b/logic/service/wscodec.go @@ -1,170 +1,170 @@ -package socket - -import ( - "bytes" - "errors" - "io" - "sync" - - "github.com/gobwas/ws" - "github.com/gobwas/ws/wsutil" - "github.com/panjf2000/gnet/v2" - "github.com/panjf2000/gnet/v2/pkg/logging" -) - -type Conn struct { - MainConn gnet.Conn `struc:"[0]pad"` //TODO 不序列化,,序列化下面的作为blob存数据库 - Mu sync.Mutex -} - -func NewConn(c gnet.Conn) *Conn { - return &Conn{MainConn: c} -} - -type WsCodec struct { - Upgraded bool // 链接是否升级 - Buf bytes.Buffer // 从实际socket中读取到的数据缓存 - wsMsgBuf wsMessageBuf // ws 消息缓存 - //Isinitws bool -} - -type wsMessageBuf struct { - curHeader *ws.Header - cachedBuf bytes.Buffer -} - -type readWrite struct { - io.Reader - io.Writer -} - -func (w *WsCodec) Upgrade(c gnet.Conn) (ok bool, action gnet.Action) { - if w.Upgraded { - ok = true - return - } - buf := &w.Buf - tmpReader := bytes.NewReader(buf.Bytes()) - oldLen := tmpReader.Len() - logging.Infof("do Upgrade") - - hs, err := ws.Upgrade(readWrite{tmpReader, c}) - skipN := oldLen - tmpReader.Len() - if err != nil { - if err == io.EOF || errors.Is(err, io.ErrUnexpectedEOF) { //数据不完整,不跳过 buf 中的 skipN 字节(此时 buf 中存放的仅是部分 "handshake data" bytes),下次再尝试读取 - return - } - buf.Next(skipN) - logging.Errorf("conn[%v] [err=%v]", c.RemoteAddr().String(), err.Error()) - action = gnet.Close - return - } - buf.Next(skipN) - logging.Infof("conn[%v] upgrade websocket protocol! Handshake: %v", c.RemoteAddr().String(), hs) - - ok = true - w.Upgraded = true - return -} -func (w *WsCodec) ReadBufferBytes(c gnet.Conn) (gnet.Action, int) { - size := c.InboundBuffered() - //buf := make([]byte, size) - read, err := c.Peek(size) - if err != nil { - logging.Errorf("read err! %v", err) - return gnet.Close, 0 - } - // if read < size { - // logging.Errorf("read bytes len err! size: %d read: %d", size, read) - // return gnet.Close - // } - w.Buf.Write(read) - return gnet.None, size -} -func (w *WsCodec) Decode(c gnet.Conn) (outs []wsutil.Message, err error) { - // fmt.Println("do Decode") - messages, err := w.readWsMessages() - if err != nil { - logging.Errorf("Error reading message! %v", err) - return nil, err - } - if messages == nil || len(messages) <= 0 { //没有读到完整数据 不处理 - return - } - for _, message := range messages { - if message.OpCode.IsControl() { - err = wsutil.HandleClientControlMessage(c, message) - if err != nil { - return - } - continue - } - if message.OpCode == ws.OpText || message.OpCode == ws.OpBinary { - outs = append(outs, message) - } - } - return -} - -func (w *WsCodec) readWsMessages() (messages []wsutil.Message, err error) { - msgBuf := &w.wsMsgBuf - in := &w.Buf - for { - // 从 in 中读出 header,并将 header bytes 写入 msgBuf.cachedBuf - if msgBuf.curHeader == nil { - if in.Len() < ws.MinHeaderSize { //头长度至少是2 - return - } - var head ws.Header - if in.Len() >= ws.MaxHeaderSize { - head, err = ws.ReadHeader(in) - if err != nil { - return messages, err - } - } else { //有可能不完整,构建新的 reader 读取 head,读取成功才实际对 in 进行读操作 - tmpReader := bytes.NewReader(in.Bytes()) - oldLen := tmpReader.Len() - head, err = ws.ReadHeader(tmpReader) - skipN := oldLen - tmpReader.Len() - if err != nil { - if err == io.EOF || errors.Is(err, io.ErrUnexpectedEOF) { //数据不完整 - return messages, nil - } - in.Next(skipN) - return nil, err - } - in.Next(skipN) - } - - msgBuf.curHeader = &head - err = ws.WriteHeader(&msgBuf.cachedBuf, head) - if err != nil { - return nil, err - } - } - dataLen := (int)(msgBuf.curHeader.Length) - // 从 in 中读出 data,并将 data bytes 写入 msgBuf.cachedBuf - if dataLen > 0 { - if in.Len() < dataLen { //数据不完整 - - logging.Infof("incomplete data") - return - } - - _, err = io.CopyN(&msgBuf.cachedBuf, in, int64(dataLen)) - if err != nil { - return - } - } - if msgBuf.curHeader.Fin { //当前 header 已经是一个完整消息 - messages, err = wsutil.ReadClientMessage(&msgBuf.cachedBuf, messages) - if err != nil { - return nil, err - } - msgBuf.cachedBuf.Reset() - } else { - logging.Infof("The data is split into multiple frames") - } - msgBuf.curHeader = nil - } -} +package service + +import ( + "bytes" + "errors" + "io" + "sync" + + "github.com/gobwas/ws" + "github.com/gobwas/ws/wsutil" + "github.com/panjf2000/gnet/v2" + "github.com/panjf2000/gnet/v2/pkg/logging" +) + +type Conn struct { + MainConn gnet.Conn `struc:"[0]pad"` //TODO 不序列化,,序列化下面的作为blob存数据库 + Mu sync.Mutex +} + +func NewConn(c gnet.Conn) *Conn { + return &Conn{MainConn: c} +} + +type WsCodec struct { + Upgraded bool // 链接是否升级 + Buf bytes.Buffer // 从实际socket中读取到的数据缓存 + wsMsgBuf wsMessageBuf // ws 消息缓存 + //Isinitws bool +} + +type wsMessageBuf struct { + curHeader *ws.Header + cachedBuf bytes.Buffer +} + +type readWrite struct { + io.Reader + io.Writer +} + +func (w *WsCodec) Upgrade(c gnet.Conn) (ok bool, action gnet.Action) { + if w.Upgraded { + ok = true + return + } + buf := &w.Buf + tmpReader := bytes.NewReader(buf.Bytes()) + oldLen := tmpReader.Len() + logging.Infof("do Upgrade") + + hs, err := ws.Upgrade(readWrite{tmpReader, c}) + skipN := oldLen - tmpReader.Len() + if err != nil { + if err == io.EOF || errors.Is(err, io.ErrUnexpectedEOF) { //数据不完整,不跳过 buf 中的 skipN 字节(此时 buf 中存放的仅是部分 "handshake data" bytes),下次再尝试读取 + return + } + buf.Next(skipN) + logging.Errorf("conn[%v] [err=%v]", c.RemoteAddr().String(), err.Error()) + action = gnet.Close + return + } + buf.Next(skipN) + logging.Infof("conn[%v] upgrade websocket protocol! Handshake: %v", c.RemoteAddr().String(), hs) + + ok = true + w.Upgraded = true + return +} +func (w *WsCodec) ReadBufferBytes(c gnet.Conn) (gnet.Action, int) { + size := c.InboundBuffered() + //buf := make([]byte, size) + read, err := c.Peek(size) + if err != nil { + logging.Errorf("read err! %v", err) + return gnet.Close, 0 + } + // if read < size { + // logging.Errorf("read bytes len err! size: %d read: %d", size, read) + // return gnet.Close + // } + w.Buf.Write(read) + return gnet.None, size +} +func (w *WsCodec) Decode(c gnet.Conn) (outs []wsutil.Message, err error) { + // fmt.Println("do Decode") + messages, err := w.readWsMessages() + if err != nil { + logging.Errorf("Error reading message! %v", err) + return nil, err + } + if messages == nil || len(messages) <= 0 { //没有读到完整数据 不处理 + return + } + for _, message := range messages { + if message.OpCode.IsControl() { + err = wsutil.HandleClientControlMessage(c, message) + if err != nil { + return + } + continue + } + if message.OpCode == ws.OpText || message.OpCode == ws.OpBinary { + outs = append(outs, message) + } + } + return +} + +func (w *WsCodec) readWsMessages() (messages []wsutil.Message, err error) { + msgBuf := &w.wsMsgBuf + in := &w.Buf + for { + // 从 in 中读出 header,并将 header bytes 写入 msgBuf.cachedBuf + if msgBuf.curHeader == nil { + if in.Len() < ws.MinHeaderSize { //头长度至少是2 + return + } + var head ws.Header + if in.Len() >= ws.MaxHeaderSize { + head, err = ws.ReadHeader(in) + if err != nil { + return messages, err + } + } else { //有可能不完整,构建新的 reader 读取 head,读取成功才实际对 in 进行读操作 + tmpReader := bytes.NewReader(in.Bytes()) + oldLen := tmpReader.Len() + head, err = ws.ReadHeader(tmpReader) + skipN := oldLen - tmpReader.Len() + if err != nil { + if err == io.EOF || errors.Is(err, io.ErrUnexpectedEOF) { //数据不完整 + return messages, nil + } + in.Next(skipN) + return nil, err + } + in.Next(skipN) + } + + msgBuf.curHeader = &head + err = ws.WriteHeader(&msgBuf.cachedBuf, head) + if err != nil { + return nil, err + } + } + dataLen := (int)(msgBuf.curHeader.Length) + // 从 in 中读出 data,并将 data bytes 写入 msgBuf.cachedBuf + if dataLen > 0 { + if in.Len() < dataLen { //数据不完整 + + logging.Infof("incomplete data") + return + } + + _, err = io.CopyN(&msgBuf.cachedBuf, in, int64(dataLen)) + if err != nil { + return + } + } + if msgBuf.curHeader.Fin { //当前 header 已经是一个完整消息 + messages, err = wsutil.ReadClientMessage(&msgBuf.cachedBuf, messages) + if err != nil { + return nil, err + } + msgBuf.cachedBuf.Reset() + } else { + logging.Infof("The data is split into multiple frames") + } + msgBuf.curHeader = nil + } +} diff --git a/modules/blazing/model/TeamInfo.go b/modules/blazing/model/TeamInfo.go index fd1fb4263..d12548b01 100644 --- a/modules/blazing/model/TeamInfo.go +++ b/modules/blazing/model/TeamInfo.go @@ -2,7 +2,7 @@ package model // TeamInfo 战队信息结构 type TeamInfo struct { - //Head handler.TomeeHeader `cmd:"1001" struc:"[0]pad"` // 命令头 + //Head service.TomeeHeader `cmd:"1001" struc:"[0]pad"` // 命令头 ID uint32 `struc:"uint32" default:"0"` // 默认值0 Priv uint32 `struc:"uint32" default:"1"` // 默认值1 SuperCore uint32 `struc:"uint32" default:"1"` // 默认值1 diff --git a/modules/blazing/model/player.go b/modules/blazing/model/player.go index 2b4e52cac..693f4c7ba 100644 --- a/modules/blazing/model/player.go +++ b/modules/blazing/model/player.go @@ -79,11 +79,11 @@ type PlayerInfo struct { VipEndTime uint32 `struc:"uint32" default:"4294967295" json:"vip_end_time"` // 尽可能大值 FreshManBonus uint32 `struc:"uint32" json:"fresh_man_bonus"` // 固定0 NonoChipList [80]byte `struc:"[80]byte" json:"nono_chip_list"` // 超no芯片列表 - DailyResArr [50]byte `struc:"[50]byte" default:"3" json:"daily_res_arr"` // 任务状态数组默认3 + DailyResArr [50]byte `struc:"[50]byte" default:"0" json:"daily_res_arr"` // 每日任务状态 40+是谱尼的 TeacherID uint32 `struc:"uint32" json:"teacher_id"` // 教官id StudentID uint32 `struc:"uint32" json:"student_id"` // 学员id GraduationCount uint32 `struc:"uint32" default:"0" json:"graduation_count"` // 毕业人数 - MaxPuniLv uint32 `struc:"uint32" default:"0" json:"max_puni_lv"` // 默认0 + MaxPuniLv uint32 `struc:"uint32" default:"0" json:"max_puni_lv"` // 默认0, 虚无 元素 能量 生命 轮回 永恒 圣洁 最高为8 PetMaxLevel uint32 `struc:"uint32" json:"pet_max_level"` // 精灵最高等级 AllPetNumber uint32 `struc:"uint32" json:"all_pet_number"` // 精灵数量 MonKingWin uint32 `struc:"uint32" json:"mon_king_win"` // 精灵王胜场 diff --git a/modules/blazing/service/task.go b/modules/blazing/service/task.go index 62212e0df..a35ade5b5 100644 --- a/modules/blazing/service/task.go +++ b/modules/blazing/service/task.go @@ -62,7 +62,9 @@ func Exec[T cool.UserModel, F any](userid uint32, s *cool.Service, processFunc f // 获取任务信息 func (s *UserService) TaskInfo(id uint32) (ret model.TaskInfo, ok bool) { var gg model.Task - m1 := cool.DBM(s.task.Model).Where("player_id", s.userid) + m1 := cool.DBM(s.task.Model). + Where("player_id", s.userid). + Where("task_id", id) m1.Scan(&gg) if gg.TaskID == 0 { @@ -87,7 +89,11 @@ func (s *UserService) TaskADD(id uint32, ret model.TaskInfo) { tt, _ := json.Marshal(&ret) gg.Data = string(tt) gg.TaskID = id - cool.DBM(s.task.Model).Where("player_id", s.userid).Insert() + gg.PlayerID = uint64(s.userid) + _, err := cool.DBM(s.task.Model).Data(gg).Where("player_id", s.userid).Insert() + if err != nil { + panic(err) + } } func (s *UserService) TaskExec(t func([]model.TaskInfo) []model.TaskInfo) (ret bool) {