refactor(socket): 重构 socket 模块

- 移除 common/data/socket 目录下的大部分文件
- 新增 service 目录,将 Player 和 Conn 结构体移至该目录
- 更新 LogicClient 中的方法签名,使用 service 包的类型
- 重构 Controller 中的方法,适应新的 service 包结构
This commit is contained in:
2025-09-04 02:00:57 +08:00
parent afdf015d62
commit 621a9d3858
50 changed files with 886 additions and 849 deletions

View File

@@ -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
}

View File

@@ -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 = "<?xml version=\"1.0\"?><!DOCTYPE cross-domain-policy><cros
const TEXT = "<policy-file-request/>\x00"
func handle(c gnet.Conn) {
clientdata := c.Context().(*socket.ClientData)
clientdata := c.Context().(*service.ClientData)
if clientdata.IsCrossDomain {
return

View File

@@ -2,13 +2,58 @@ package socket
import (
"blazing/common/socket/codec"
"blazing/common/socket/handler"
"blazing/common/socket/errorcode"
"blazing/logic/service"
"github.com/gogf/gf/v2/util/gconv"
"github.com/panjf2000/gnet/pkg/pool/goroutine"
"github.com/panjf2000/gnet/v2"
)
func GetPlayer(c *service.Conn, userid uint32) *service.Player { //TODO 这里待优化,可能存在内存泄漏问题
c.Mu.Lock()
defer c.Mu.Unlock()
//检查player初始化是否为conn初始后取map防止二次连接后存在两个player
clientdata := c.MainConn.Context().(*service.ClientData)
if clientdata.Player != nil {
return clientdata.Player
}
clientdata.Player = service.NewPlayer(
service.WithConn(c), //注入conn
)
// gff := socket.NewClientData()
// gff.Player = clientdata.Player
// c.MainConn.SetContext(gff)
service.Mainplayer.Store(userid, clientdata.Player)
return clientdata.Player
// return nil
}
func KickPlayer(userid uint32) { //踢出玩家
//TODO 返回错误码
//var player *entity.Player
if player1, ok := service.Mainplayer.Load((userid)); ok {
//取成功,否则创建
head := service.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
}
type Handler interface {
Handle(gnet.Conn, []byte)
}
type Server struct {
gnet.BuiltinEventEngine
eng gnet.Engine
@@ -19,7 +64,7 @@ type Server struct {
bufferSize int
workerPool *goroutine.Pool
codec codec.SocketCodec
handler handler.Handler
handler Handler
discorse bool
}
@@ -52,7 +97,7 @@ func WithCORS() Option {
u.discorse = false
}
}
func WithSocketHandler(handler handler.Handler) Option {
func WithSocketHandler(handler Handler) Option {
return func(u *Server) {
u.handler = handler
}

View File

@@ -1,8 +0,0 @@
package handler
import "github.com/panjf2000/gnet/v2"
// Handler The handler receive every syslog entry at Handle method
type Handler interface {
Handle(gnet.Conn, []byte)
}

View File

@@ -1,15 +1,15 @@
package controller
import (
"blazing/common/data/socket"
"blazing/common/socket/errorcode"
"blazing/logic/service"
"blazing/logic/service/login"
"blazing/modules/blazing/service"
blservice "blazing/modules/blazing/service"
)
// 处理命令: 1001
func (h *Controller) CreatePlayer(data *login.CreatePlayerInboundInfo, c *socket.Conn) (result *login.CreatePlayerOutInfo, err errorcode.ErrorCode) {
func (h *Controller) CreatePlayer(data *login.CreatePlayerInboundInfo, c *service.Conn) (result *login.CreatePlayerOutInfo, err errorcode.ErrorCode) {
service.NewUserService(data.Head.UserID).Reg(data.Nickname, data.Color)
blservice.NewUserService(data.Head.UserID).Reg(data.Nickname, data.Color)
return result, 0
}

View File

@@ -1,12 +1,12 @@
package controller
import (
"blazing/common/data/socket"
"blazing/common/socket/errorcode"
"blazing/logic/service"
"blazing/logic/service/friend"
)
func (h Controller) OnSeeOnline(data *friend.SeeOnlineInboundInfo, c *socket.Player) (result *friend.SeeOnlineOutboundInfo, err errorcode.ErrorCode) {
func (h Controller) OnSeeOnline(data *friend.SeeOnlineInboundInfo, c *service.Player) (result *friend.SeeOnlineOutboundInfo, err errorcode.ErrorCode) {
result = &friend.SeeOnlineOutboundInfo{}
result.Friends = make([]friend.OnlineInfo, 0)
return

View File

@@ -1,9 +1,9 @@
package controller
import (
"blazing/common/data/socket"
"blazing/common/socket"
"blazing/common/socket/errorcode"
"blazing/common/socket/handler"
"blazing/cool"
"blazing/logic/service"
"os"
@@ -38,7 +38,7 @@ type LogicClient struct {
func (h *LogicClient) KickPerson(a int) error {
fmt.Println("检测到踢人请求", a)
service.KickPlayer(uint32(a))
socket.KickPlayer(uint32(a))
return nil
}
func (h *LogicClient) QuitSelf(a int) error {
@@ -50,9 +50,9 @@ func (h *LogicClient) QuitSelf(a int) error {
for {
//entity.ConutPlayer()
fmt.Println("当前在线人数", socket.ConutPlayer())
fmt.Println("当前在线人数", service.ConutPlayer())
if socket.ConutPlayer() <= 0 {
if service.ConutPlayer() <= 0 {
//执行退出逻辑
os.Exit(1)
}
@@ -107,7 +107,7 @@ func init() { //默认初始化扫描
}
glog.Debug(context.Background(), "注册方法", func_cmd, method.Name)
// fmt.Println(methodValue.Interface().(func(gnet.Conn, handler.TomeeHeader)))
// fmt.Println(methodValue.Interface().(func(gnet.Conn, service.TomeeHeader)))
_, ok := cool.CmdCache.LoadOrStore(func_cmd, methodValue) //TODO 待实现对不同用户初始化方法以取消全局cmdcache
if ok { //方法已存在init
@@ -136,7 +136,7 @@ func getcmd(t reflect.Type) []uint32 {
field := t.Field(i)
//fmt.Printf("- 字段名: %s\n", field.Name)
//fmt.Printf(" 类型: %v\n", field.Type)
if field.Type == reflect.TypeOf(handler.TomeeHeader{}) {
if field.Type == reflect.TypeOf(service.TomeeHeader{}) {
// fmt.Println(reflect.ValueOf(field))
return gconv.SliceUint32(strings.Split(field.Tag.Get("cmd"), "|"))
@@ -158,7 +158,7 @@ func getcmd(t reflect.Type) []uint32 {
}
// 遍历结构体方法并执行RECV_cmd
func Recv(c *socket.Conn, data handler.TomeeHeader) {
func Recv(c *service.Conn, data service.TomeeHeader) {
cmdlister, ok := cool.CmdCache.Load(data.CMD)
if !ok {
@@ -189,8 +189,8 @@ func Recv(c *socket.Conn, data handler.TomeeHeader) {
if nameField.IsValid() && nameField.CanSet() {
nameField.Set(reflect.ValueOf(data))
}
if cmdlister.Type().In(1) == reflect.TypeOf(&socket.Player{}) {
t := service.GetPlayer(c, data.UserID)
if cmdlister.Type().In(1) == reflect.TypeOf(&service.Player{}) {
t := socket.GetPlayer(c, data.UserID)
// fmt.Println(data.CMD, "接收 变量的地址 ", &t.Info, t.Info.UserID)
err := t.WaitForLoginWithCtx(context.Background())
if err != nil {

View File

@@ -1,12 +1,12 @@
package controller
import (
"blazing/common/data/socket"
"blazing/common/socket/errorcode"
"blazing/common/socket/handler"
"math/rand"
"time"
"blazing/logic/service"
"blazing/logic/service/fight"
"blazing/logic/service/fight/info"
"blazing/modules/blazing/model"
@@ -14,7 +14,7 @@ import (
"github.com/jinzhu/copier"
)
func (h Controller) OnPlayerFightNpcMonster(data *info.FightNpcMonsterInboundInfo, c *socket.Player) (result *info.NullOutboundInfo, err errorcode.ErrorCode) {
func (h Controller) OnPlayerFightNpcMonster(data *fight.FightNpcMonsterInboundInfo, c *service.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
ttt := info.NoteReadyToFightInfo{
OwnerID: data.Head.UserID,
@@ -43,42 +43,42 @@ func (h Controller) OnPlayerFightNpcMonster(data *info.FightNpcMonsterInboundInf
if err1 != nil {
panic(err)
}
fight.NewFight(&ttt, c) //把两个玩家都传进去
c.FightC = &service.FightC{}
c.FightC.NewFight(&ttt, c) //把两个玩家都传进去
return nil, -1
}
// 准备战斗
func (h Controller) OnReadyToFight(data *info.ReadyToFightInboundInfo, c *socket.Player) (result *info.NullOutboundInfo, err errorcode.ErrorCode) {
func (h Controller) OnReadyToFight(data *fight.ReadyToFightInboundInfo, c *service.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
fight.ReadyFight(c)
c.FightC.ReadyFight(c)
return nil, -1
}
// 接收战斗或者取消战斗的包
func (h Controller) OnPlayerHandleFightInvite(data *info.HandleFightInviteInboundInfo, c *socket.Player) (result *info.NullOutboundInfo, err errorcode.ErrorCode) {
func (h Controller) OnPlayerHandleFightInvite(data *fight.HandleFightInviteInboundInfo, c *service.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
return nil, -1
}
// 使用技能包
func (h Controller) UseSkill(data *info.UseSkillInboundInfo, c *socket.Player) (result *info.NullOutboundInfo, err errorcode.ErrorCode) {
func (h Controller) UseSkill(data *fight.UseSkillInboundInfo, c *service.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
return nil, 0
}
// 战斗逃跑
func (h Controller) Escape(data *info.EscapeFightInboundInfo, c *socket.Player) (result *info.NullOutboundInfo, err errorcode.ErrorCode) {
func (h Controller) Escape(data *fight.EscapeFightInboundInfo, c *service.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
defer func() {
//战斗结束Escape
ttt := handler.NewTomeeHeader(2506, c.Info.UserID)
ttt := service.NewTomeeHeader(2506, c.Info.UserID)
c.SendPack(ttt.Pack(&info.FightOverInfo{
c.SendPack(ttt.Pack(&fight.FightOverInfo{
Reason: 0,
}))
c.FightID = ""
}()
return nil, 0

View File

@@ -1,13 +1,13 @@
package controller
import (
"blazing/common/data/socket"
"blazing/common/socket/errorcode"
"blazing/logic/service"
"blazing/logic/service/commendsvr"
)
// 处理命令: 105
func (h *Controller) GetServer(data *commendsvr.SidInfo, c *socket.Conn) (result *commendsvr.CommendSvrInfo, err errorcode.ErrorCode) { //这个时候player应该是空的
func (h *Controller) GetServer(data *commendsvr.SidInfo, c *service.Conn) (result *commendsvr.CommendSvrInfo, err errorcode.ErrorCode) { //这个时候player应该是空的
result = commendsvr.NewInInfo()
result.ServerList = commendsvr.GetServerInfoList()
return

View File

@@ -1,12 +1,12 @@
package controller
import (
"blazing/common/data/socket"
"blazing/common/socket/errorcode"
"blazing/logic/service"
"blazing/logic/service/item"
)
func (h Controller) UserItemList(data *item.ItemListInboundInfo, c *socket.Player) (result *item.ItemListOutboundInfo, err errorcode.ErrorCode) {
func (h Controller) UserItemList(data *item.ItemListInboundInfo, c *service.Player) (result *item.ItemListOutboundInfo, err errorcode.ErrorCode) {
result = &item.ItemListOutboundInfo{}
return result, 0

View File

@@ -2,9 +2,10 @@ package controller
import (
"blazing/common/data/share"
"blazing/common/data/socket"
"blazing/common/socket"
"blazing/common/socket/errorcode"
"blazing/common/socket/handler"
"blazing/logic/service"
"blazing/logic/service/login"
"blazing/logic/service/maps"
@@ -27,12 +28,12 @@ func IsToday(t time.Time) bool {
}
// 处理命令: 1001
func (h *Controller) Login(data *login.InInfo, c *socket.Conn) (result *login.OutInfo, err errorcode.ErrorCode) { //这个时候player应该是空的
func (h *Controller) Login(data *login.InInfo, c *service.Conn) (result *login.OutInfo, err errorcode.ErrorCode) { //这个时候player应该是空的
if tt := data.CheakSession(); tt { //说明sid正确
h.RPCClient.Kick(data.Head.UserID) //先踢人
t := service.GetPlayer(c, data.Head.UserID)
t := socket.GetPlayer(c, data.Head.UserID)
t.Info = blservice.NewUserService(data.Head.UserID).Person()
t.Info.UserID = data.Head.UserID
t.Onlinetime = uint32(time.Now().Unix()) //保存时间戳
@@ -59,8 +60,8 @@ func (h *Controller) Login(data *login.InInfo, c *socket.Conn) (result *login.Ou
tt := maps.NewOutInfo()
//copier.Copy(t.Info, tt)
t1 := handler.NewTomeeHeader(2001, t.Info.UserID)
defer space.GetSpace(t.Info.MapID).Set(t.Info.UserID, t).Range(func(playerID uint32, player *socket.Player) bool {
t1 := service.NewTomeeHeader(2001, t.Info.UserID)
defer space.GetSpace(t.Info.MapID).Set(t.Info.UserID, t).Range(func(playerID uint32, player service.PlayerI) bool {
player.SendPack(t1.Pack(&tt))
return true

View File

@@ -1,8 +1,8 @@
package controller
import (
"blazing/common/data/socket"
"blazing/common/socket/errorcode"
"blazing/logic/service"
"blazing/logic/service/maphot"
"blazing/logic/service/maps"
"blazing/logic/service/space"
@@ -11,7 +11,7 @@ import (
"github.com/jinzhu/copier"
)
func (h *Controller) MapEnter(data *maps.InInfo, c *socket.Player) (result *maps.OutInfo, err errorcode.ErrorCode) { //这个时候player应该是空的
func (h *Controller) MapEnter(data *maps.InInfo, c *service.Player) (result *maps.OutInfo, err errorcode.ErrorCode) { //这个时候player应该是空的
c.Info.MapID = data.MapId //登录地图
space.GetSpace(c.Info.MapID).Set(c.Info.UserID, c) //添加玩家
@@ -33,7 +33,7 @@ func (h *Controller) MapEnter(data *maps.InInfo, c *socket.Player) (result *maps
<-time.After(5 * time.Second)
// 首次刷新
if c.FightID == "" && c.Info.MapID != 0 {
if c.FightC == nil && c.Info.MapID != 0 {
data.SpawnMonsters(c, true)
}
//循环刷新怪物
@@ -48,7 +48,7 @@ func (h *Controller) MapEnter(data *maps.InInfo, c *socket.Player) (result *maps
return
case <-ticker.C:
// 刷新当前地图的怪物
if c.FightID == "" && c.Info.MapID != 0 {
if c.FightC == nil && c.Info.MapID != 0 {
data.SpawnMonsters(c, false)
}
@@ -57,7 +57,7 @@ func (h *Controller) MapEnter(data *maps.InInfo, c *socket.Player) (result *maps
}(c.StopChan, int(c.Info.MapID))
return nil, -1
}
func (h Controller) MapHot(data *maphot.InInfo, c *socket.Player) (result *maphot.OutInfo, err errorcode.ErrorCode) {
func (h Controller) MapHot(data *maphot.InInfo, c *service.Player) (result *maphot.OutInfo, err errorcode.ErrorCode) {
result = &maphot.OutInfo{
@@ -66,7 +66,7 @@ func (h Controller) MapHot(data *maphot.InInfo, c *socket.Player) (result *mapho
return
}
func (h *Controller) MapLeave(data *maps.LeaveMapInboundInfo, c *socket.Player) (result *maps.LeaveMapOutboundInfo, err errorcode.ErrorCode) { //这个时候player应该是空的
func (h *Controller) MapLeave(data *maps.LeaveMapInboundInfo, c *service.Player) (result *maps.LeaveMapOutboundInfo, err errorcode.ErrorCode) { //这个时候player应该是空的
//result = &maps.LeaveMapOutboundInfo{UserID: c.GetUserID()}
data.Broadcast(c.Info.MapID, maps.LeaveMapOutboundInfo{UserID: c.Info.UserID}) //同步广播
@@ -79,14 +79,14 @@ func (h *Controller) MapLeave(data *maps.LeaveMapInboundInfo, c *socket.Player)
c.Info.MapID = 0 // 重置当前地图
return nil, -1
}
func (h *Controller) MapList(data *maps.ListMapPlayerInboundInfo, c *socket.Player) (result *maps.ListMapPlayerOutboundInfo, err errorcode.ErrorCode) { //这个时候player应该是空的
func (h *Controller) MapList(data *maps.ListMapPlayerInboundInfo, c *service.Player) (result *maps.ListMapPlayerOutboundInfo, err errorcode.ErrorCode) { //这个时候player应该是空的
result = &maps.ListMapPlayerOutboundInfo{}
result.Player = make([]maps.OutInfo, 0)
space.GetSpace(c.Info.MapID).Range(func(userID uint32, player *socket.Player) bool {
space.GetSpace(c.Info.MapID).Range(func(userID uint32, player service.PlayerI) bool {
result1 := maps.NewOutInfo()
copier.Copy(result1, player.Info)
copier.Copy(result1, player)
result.Player = append(result.Player, *result1)
return true
})

View File

@@ -1,10 +1,10 @@
package controller
import (
"blazing/common/data/socket"
"blazing/common/socket/errorcode"
"blazing/logic/service"
"blazing/logic/service/pet"
"blazing/modules/blazing/service"
blservice "blazing/modules/blazing/service"
"github.com/jinzhu/copier"
@@ -13,10 +13,10 @@ import (
// 获取精灵信息
func (h *Controller) GetPetInfo(
data *pet.InInfo,
c *socket.Player) (result *pet.OutInfo,
c *service.Player) (result *pet.OutInfo,
err errorcode.ErrorCode) { //这个时候player应该是空的
t := service.NewUserService(c.Info.UserID).GetPetInfo(data.CatchTime)
t := blservice.NewUserService(c.Info.UserID).GetPetInfo(data.CatchTime)
return &pet.OutInfo{
PetInfo: t,
}, 0
@@ -25,7 +25,7 @@ func (h *Controller) GetPetInfo(
// 获取仓库列表
func (h *Controller) GetPetList(
data *pet.GetPetListInboundEmpty,
c *socket.Player) (result *pet.GetPetListOutboundInfo,
c *service.Player) (result *pet.GetPetListOutboundInfo,
err errorcode.ErrorCode) { //这个时候player应该是空的
result = &pet.GetPetListOutboundInfo{}
@@ -43,7 +43,7 @@ func (h *Controller) GetPetList(
// 精灵背包仓库切换
func (h *Controller) PetRelease(
data *pet.PetReleaseInboundInfo,
c *socket.Player) (
c *service.Player) (
result *pet.PetReleaseOutboundInfo,
err errorcode.ErrorCode) { //这个时候player应该是空的
//放入背包=数据库置1+添加到背包+pet release发包 仓库=数据库置0+移除背包 设置首发等于取到首发精灵后重新排序
@@ -51,7 +51,7 @@ func (h *Controller) PetRelease(
result = &pet.PetReleaseOutboundInfo{}
result.Flag = uint32(data.Flag)
t := service.NewUserService(c.Info.UserID).PetM(int(data.CatchTime), int(data.Flag))
t := blservice.NewUserService(c.Info.UserID).PetM(int(data.CatchTime), int(data.Flag))
switch data.Flag {
case 0:
//todo 仓库

View File

@@ -1,13 +1,13 @@
package controller
import (
"blazing/common/data/socket"
"blazing/common/socket/errorcode"
"blazing/logic/service"
"blazing/logic/service/room"
)
// 获取基地物品
func (h Controller) OnFitmentUsering(data *room.FitmentUseringInboundInfo, c *socket.Player) (result *room.FitmentUseringOutboundInfo, err errorcode.ErrorCode) {
func (h Controller) OnFitmentUsering(data *room.FitmentUseringInboundInfo, c *service.Player) (result *room.FitmentUseringOutboundInfo, err errorcode.ErrorCode) {
result = &room.FitmentUseringOutboundInfo{UserId: c.Info.UserID, RoomId: data.TargetUserID}
result.Fitments = make([]room.FitmentShowInfo, 0)
@@ -17,14 +17,14 @@ func (h Controller) OnFitmentUsering(data *room.FitmentUseringInboundInfo, c *so
}
// 获取基地展示精灵
func (h Controller) OnGetRoomPetShowInfo(data *room.PetRoomListInboundInfo, c *socket.Player) (result *room.PetRoomListOutboundInfo, err errorcode.ErrorCode) {
func (h Controller) OnGetRoomPetShowInfo(data *room.PetRoomListInboundInfo, c *service.Player) (result *room.PetRoomListOutboundInfo, err errorcode.ErrorCode) {
result = &room.PetRoomListOutboundInfo{}
result.Pets = make([]room.PetShowInfo, 0)
return
}
// 获取自己房间的家具
func (h Controller) OnGetFitmentAll(data *room.FitmentAllInboundEmpty, c *socket.Player) (result *room.FitmentAllOutboundInfo, err errorcode.ErrorCode) {
func (h Controller) OnGetFitmentAll(data *room.FitmentAllInboundEmpty, c *service.Player) (result *room.FitmentAllOutboundInfo, err errorcode.ErrorCode) {
result = &room.FitmentAllOutboundInfo{}
result.Fitments = make([]room.FitmentItemInfo, 0)

View File

@@ -1,12 +1,12 @@
package controller
import (
"blazing/common/data/socket"
"blazing/common/socket/errorcode"
"blazing/logic/service"
"blazing/logic/service/systemtime"
)
func (h Controller) SystemTimeInfo(data *systemtime.InInfo, c *socket.Player) (result *systemtime.OutInfo, err errorcode.ErrorCode) {
func (h Controller) SystemTimeInfo(data *systemtime.InInfo, c *service.Player) (result *systemtime.OutInfo, err errorcode.ErrorCode) {
return systemtime.NewOutInfo(), 0
}

View File

@@ -1,11 +1,11 @@
package controller
import (
"blazing/common/data/socket"
"blazing/common/socket/errorcode"
"blazing/logic/service"
"blazing/logic/service/task"
"blazing/modules/blazing/model"
"blazing/modules/blazing/service"
blservice "blazing/modules/blazing/service"
"math/rand"
"time"
)
@@ -13,7 +13,7 @@ import (
/**
* 接受任务
*/
func (h Controller) AcceptTask(data *task.AcceptTaskInboundInfo, c *socket.Player) (result *task.AcceptTaskOutboundInfo, err errorcode.ErrorCode) {
func (h Controller) AcceptTask(data *task.AcceptTaskInboundInfo, c *service.Player) (result *task.AcceptTaskOutboundInfo, err errorcode.ErrorCode) {
//isdaliy := false
// if data.Head.CMD != 2201 { //判断是每日任务
// //isdaliy = true
@@ -31,20 +31,20 @@ func (h Controller) AcceptTask(data *task.AcceptTaskInboundInfo, c *socket.Playe
/**
* 更新任务步骤
*/
func (h Controller) AddTaskBuf(data *task.AddTaskBufInboundInfo, c *socket.Player) (result *task.AddTaskBufOutboundInfo, err errorcode.ErrorCode) {
func (h Controller) AddTaskBuf(data *task.AddTaskBufInboundInfo, c *service.Player) (result *task.AddTaskBufOutboundInfo, err errorcode.ErrorCode) {
// isdaliy := false
// if data.Head.CMD != 2204 { //判断是每日任务
// isdaliy = true
// }
result = &task.AddTaskBufOutboundInfo{}
_, ok := service.NewUserService(c.Info.UserID).TaskInfo(data.TaskId)
_, ok := blservice.NewUserService(c.Info.UserID).TaskInfo(data.TaskId)
if ok {
service.NewUserService(c.Info.UserID).TaskSet(data.TaskId, model.TaskInfo{
blservice.NewUserService(c.Info.UserID).TaskSet(data.TaskId, model.TaskInfo{
Info: data.TaskList,
})
} else {
service.NewUserService(c.Info.UserID).TaskADD(data.TaskId, model.TaskInfo{
blservice.NewUserService(c.Info.UserID).TaskADD(data.TaskId, model.TaskInfo{
Info: data.TaskList,
})
@@ -65,7 +65,7 @@ func randInt0To24() int {
/**
* 完成任务
*/
func (h Controller) Complete_Task(data *task.CompleteTaskInboundInfo, c *socket.Player) (result *task.CompleteTaskOutboundInfo, err errorcode.ErrorCode) {
func (h Controller) Complete_Task(data *task.CompleteTaskInboundInfo, c *service.Player) (result *task.CompleteTaskOutboundInfo, err errorcode.ErrorCode) {
if c.Info.TaskList[data.TaskId] != 1 { //如果任务没有接受或者已经完成Complete_Task
@@ -94,7 +94,7 @@ func (h Controller) Complete_Task(data *task.CompleteTaskInboundInfo, c *socket.
r := model.GenPetInfo(1, 1, 1, 1006, 1, 5)
result.CaptureTime = r.CatchTime
result.PetTypeId = r.ID
service.NewUserService(c.Info.UserID).PetAdd(*r)
blservice.NewUserService(c.Info.UserID).PetAdd(*r)
}
if data.TaskId == 87 { //新手注册任务
@@ -113,8 +113,8 @@ func (h Controller) Complete_Task(data *task.CompleteTaskInboundInfo, c *socket.
/**
* 获取任务状态
*/
func (h Controller) Get_Task_Buf(data *task.GetTaskBufInboundInfo, c *socket.Player) (result *task.GetTaskBufOutboundInfo, err errorcode.ErrorCode) {
info, _ := service.NewUserService(c.Info.UserID).TaskInfo(data.TaskId)
func (h Controller) Get_Task_Buf(data *task.GetTaskBufInboundInfo, c *service.Player) (result *task.GetTaskBufOutboundInfo, err errorcode.ErrorCode) {
info, _ := blservice.NewUserService(c.Info.UserID).TaskInfo(data.TaskId)
result = &task.GetTaskBufOutboundInfo{}
result.TaskId = data.TaskId
result.TaskList = info.Info
@@ -125,7 +125,7 @@ func (h Controller) Get_Task_Buf(data *task.GetTaskBufInboundInfo, c *socket.Pla
/**
* 删除任务
*/
func (h Controller) Delete_Task(data *task.DeleteTaskInboundInfo, c *socket.Player) (result *task.DeleteTaskOutboundInfo, err errorcode.ErrorCode) {
func (h Controller) Delete_Task(data *task.DeleteTaskInboundInfo, c *service.Player) (result *task.DeleteTaskOutboundInfo, err errorcode.ErrorCode) {
// if data.Head.CMD == 2205 { //判断不是每日任务

View File

@@ -1,8 +1,8 @@
package controller
import (
"blazing/common/data/socket"
"blazing/common/socket/errorcode"
"blazing/logic/service"
"blazing/logic/service/space"
"context"
@@ -10,7 +10,7 @@ import (
"github.com/jinzhu/copier"
)
func (h Controller) Walk(data *space.InInfo, c *socket.Player) (result *space.OutInfo, err errorcode.ErrorCode) {
func (h Controller) Walk(data *space.InInfo, c *service.Player) (result *space.OutInfo, err errorcode.ErrorCode) {
result = &space.OutInfo{}
err1 := copier.Copy(result, data)
result.UserID = data.Head.UserID

View File

@@ -3,10 +3,11 @@ package main
import (
"blazing/common/rpc"
"blazing/common/socket"
"blazing/common/socket/handler"
"blazing/cool"
"blazing/logic/controller"
"blazing/modules/blazing/service"
"blazing/logic/service"
blservice "blazing/modules/blazing/service"
"fmt"
"log"
@@ -62,7 +63,7 @@ func isPortAvailable(port int) bool {
// 如果id是0,那就是login server
func Start(serverid uint16) {
//ants.NewPool(100)
head := handler.NewTomeeHandler()
head := service.NewTomeeHandler()
head.Callback = controller.Recv
if serverid != 0 { //logic服务器
// 确定端口
@@ -77,7 +78,7 @@ func Start(serverid uint16) {
controller.Maincontroller.RPCClient = *t //将RPC赋值Start
controller.Maincontroller.Port = uint16(port) //赋值服务器ID
service.NewLoginServiceService().SetServerID(serverid, gconv.Uint16(port), t)
blservice.NewLoginServiceService().SetServerID(serverid, gconv.Uint16(port), t)
socket.
NewServer(
socket.WithCORS(),

View File

@@ -1,7 +1,6 @@
package handler
package service
import (
"blazing/common/data/socket"
"blazing/common/utils/bytearray"
"bytes"
@@ -37,7 +36,7 @@ func NewTomeeHeader(cmd uint32, userid uint32) *TomeeHeader {
}
type TomeeHandler struct {
Callback func(conn *socket.Conn, data TomeeHeader)
Callback func(conn *Conn, data TomeeHeader)
}
func NewTomeeHandler() *TomeeHandler {
@@ -60,7 +59,7 @@ func (h *TomeeHandler) Handle(c gnet.Conn, data []byte) { //处理接收到的
header.Result, _ = tempdata.ReadUInt32()
header.Data = tempdata.BytesAvailable()
//fmt.Println("接收封包", header)
h.Callback(socket.NewConn(c), header)
h.Callback(NewConn(c), header)
//return header
}

View File

@@ -1,9 +1,9 @@
package commendsvr
import (
"blazing/common/socket/handler"
"blazing/cool"
"blazing/modules/base/service"
"blazing/logic/service"
baseservice "blazing/modules/base/service"
"blazing/modules/blazing/model"
"github.com/butoften/array"
@@ -12,7 +12,7 @@ import (
//var _ entity.Blazingservice = (*SidInfo)(nil)
type SidInfo struct { //这里直接使用组合来实现将传入的原始头部数据和结构体参数序列化
Head handler.TomeeHeader `cmd:"105" struc:"[0]pad"` //玩家登录
Head service.TomeeHeader `cmd:"105" struc:"[0]pad"` //玩家登录
Sid []byte `struc:"[20]byte"` // 登录会话ID固定长度16字节
ret []byte `struc:"[0]pad"`
@@ -22,7 +22,7 @@ type SidInfo struct { //这里直接使用组合来实现将传入的原始头
// CommendSvrInfo 初始连接请求信息结构体
type CommendSvrInfo struct {
//Handler handler.TomeeHeader //` struc:"[0]pad"` //消息头 ,这里为传入的头部数据,遍历此头部实现解析CommendSvrInfo
//Handler service.TomeeHeader //` struc:"[0]pad"` //消息头 ,这里为传入的头部数据,遍历此头部实现解析CommendSvrInfo
MaxOnlineID uint32 `struc:"sizeof=ServerList"` // 最大连接数
IsVip uint32 // 建议为0
ServerInfoLen uint32 `struc:"sizeof=ServerList"` // 服务器信息长度 ServerInfo
@@ -38,7 +38,7 @@ type CommendSvrInfo struct {
// IsVip 和 ServerInfoLen 字段被初始化为 0
func NewInInfo() *CommendSvrInfo {
return &CommendSvrInfo{
// Handler: handler.TomeeHeader{},
// Handler: service.TomeeHeader{},
// MaxOnlineID: 100,
IsVip: 0,
ServerInfoLen: 0,
@@ -84,7 +84,7 @@ func GetServerInfoList() []ServerInfo {
t.Structs(&ret)
//fmt.Println(t)
var ret1 []ServerInfo
ip := service.NewBaseSysConfService().GetValue("server_ip")
ip := baseservice.NewBaseSysConfService().GetValue("server_ip")
for _, v := range ret {
tt := newServerInfo()

143
logic/service/fight.go Normal file
View File

@@ -0,0 +1,143 @@
package service
import (
"blazing/logic/service/fight/info"
"blazing/modules/blazing/model"
"github.com/jinzhu/copier"
)
type PlayerI interface {
ID() uint32
MapID() uint32
GetInfo() model.PlayerInfo
SendPack(b []byte) error
SendReadyToFightInfo(info.FightStartOutboundInfo)
SendNoteReadyToFightInfo(info.NoteReadyToFightInfo)
}
type FightC struct {
Info info.NoteReadyToFightInfo
Our PlayerI
Opp PlayerI
}
// var FightCache = make(map[string]*info.NoteReadyToFightInfo) //默认our是房主
func (f *FightC) ReadyFight(c PlayerI) {
// tt, _ := FightCache[c.FightID]
rett := info.FightStartOutboundInfo{}
copier.Copy(&rett.Info1, &f.Info.OurPetList[0]) //复制自己的信息
switch f.Info.FightId { //判断战斗类型
case 1:
//1v1
if c == f.Our { //这个时候是房主发来的消息
f.Info.AFinished = true
if f.Info.BFinished {
copier.Copy(&rett.Info2, &f.Info.OpponentPetList[0]) //复制对方信息
// f.Our.SendPack(t1.Pack(&rett)) //给自己发
// f.Opp.SendPack(t1.Pack(&rett)) //给对方发
}
} else {
f.Our = c
f.Info.BFinished = true
if f.Info.AFinished { //如果房主完成
copier.Copy(&rett.Info2, &f.Info.OurPetList[0]) //复制房主信息,因为这时候不是房主发来的消息
// f.Our.SendPack(t1.Pack(&rett)) //给自己发
// f.Our.SendPack(t1.Pack(&rett)) //给房主发
}
}
case 3: //野怪战斗
copier.Copy(&rett.Info2, &f.Info.OpponentPetList[0])
rett.Info1.UserID = f.Info.OurInfo.UserID
// f.Our.SendPack(t1.Pack(&rett))
}
f.Our.SendReadyToFightInfo(rett)
f.Opp.SendReadyToFightInfo(rett)
}
func (f *FightC) NewFight(i *info.NoteReadyToFightInfo, plays PlayerI) {
f.Our = plays
// t12, _ := uuid.NewV7()
// uuid := strings.Replace(t12.String(), "-", "", -1) //绑定战斗ID
// /FightCache[uuid] = i
//先发送战斗准备包
f.Info.FightId = i.FightId
switch i.FightId {
case 1:
//1v1
case 3: //野怪战斗
plays.SendNoteReadyToFightInfo(*i)
// t1 := handler.NewTomeeHeader(2503, f.Info.OurInfo.UserID)
// 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 // 被拦截
// }
// }
}
}

View File

@@ -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 // 被拦截
// }
// }
}
}

View File

@@ -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
}

View File

@@ -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<ReadyFightPetInfo>,使用切片模拟动态列表
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"`

View File

@@ -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" `

View File

@@ -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

View File

@@ -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字节

View File

@@ -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字节

View File

@@ -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 表示地图热度的出站消息

View File

@@ -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)
}

View File

@@ -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 {

View File

@@ -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())
}

View File

@@ -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"`

View File

@@ -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"`

View File

@@ -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"`
}

View File

@@ -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
}

View File

@@ -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"`

View File

@@ -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
}

View File

@@ -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 {

View File

@@ -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
})
}

View File

@@ -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"` //玩家登录
}

View File

@@ -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
}

View File

@@ -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注解
}

View File

@@ -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
}

View File

@@ -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 {

View File

@@ -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
}

View File

@@ -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
}
}

View File

@@ -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

View File

@@ -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"` // 精灵王胜场

View File

@@ -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) {