fix(binary): 修复零值处理导致的结构体打包异常

在 binaryFallback 的 Sizeof 和 Pack 方法中增加对 IsZero 值的判断,
避免空值参与序列化计算引发错误。同时调整了 struc 包相关逻辑以正确
处理空值情况,并打印调试日志辅助排查。

feat(fight): 完善玩家 PVP 对战胜负统计逻辑

修正 PET_MELEE 与 PET_King 模式下胜利归属判定问题,确保只有实际胜出
者才累计胜利次数。此外优化了战斗邀请流程,移除冗余状态控制字段并增强
邀请有效性校验,提升 PvP 流程稳定性。

refactor(pack): 简化数据组包逻辑并提高兼容性

重构 TomeeHeader.Pack 方法,去除反射相关的复杂类型判断,统一使用 struc
进行编码,强化对 nil、interface{} 及多级指针的支持。另外更新了客户端发包
记录日志内容以便追踪调试。

style(code): 规范代码格式并清理无用注释和字段

删除多个文件中的无效或过时注释,如 PlayerID 字段标记废弃、无意义的日志输出等;
同步更新结构体字段命名一致性(如 NonoColor),并对部分函数参数及条件表达式做
可读性优化,整体提升代码整洁度和维护性。
```
This commit is contained in:
2025-11-20 15:19:13 +08:00
parent 53d6db7e17
commit 9f89f9f259
27 changed files with 164 additions and 158 deletions

View File

@@ -30,6 +30,9 @@ func (b binaryFallback) String() string {
}
func (b binaryFallback) Sizeof(val reflect.Value, options *Options) int {
if val.IsZero() {
return 0
}
return binary.Size(val.Interface())
}
@@ -39,6 +42,9 @@ func (b binaryFallback) Pack(buf []byte, val reflect.Value, options *Options) (i
if options.Order != nil {
order = options.Order
}
if val.IsZero() {
return tmp.pos, nil
}
err := binary.Write(tmp, order, val.Interface())
return tmp.pos, err
}

View File

@@ -77,6 +77,11 @@ func PackWithOptions(w io.Writer, data interface{}, options *Options) error {
val = val.Convert(reflect.TypeOf([]byte{}))
}
size := packer.Sizeof(val, options)
if size == 0 {
fmt.Println("size==0")
}
buf := make([]byte, size)
if _, err := packer.Pack(buf, val, options); err != nil {
return err

View File

@@ -70,6 +70,11 @@ func (h Controller) PlayerFightBoss(data *fight.ChallengeBossInboundInfo, c *pla
return nil, errorcode.ErrorCodes.ErrPokemonNotExists
}
for _, bc := range mdata.Bosses {
if bc.Id == nil {
bc.Id = gconv.PtrInt(0)
}
if (bc.Id == nil && data.BossId == 0) || uint32(*bc.Id) == data.BossId { //打默认第一个boss
for _, bm := range bc.BossMon {

View File

@@ -15,12 +15,16 @@ func (h Controller) PET_MELEE(data *fight.StartPetWarInboundInfo, c *player.Play
c.Fightinfo.Mode = info.BattleMode.PET_MELEE
c.Fightinfo.Status = info.BattleStatus.FIGHT_WITH_PLAYER
c.Fightinfo.PlayerID = 0
err = c.JoinFight(func(p common.PlayerI) bool {
fight.NewFight(p, c, func(foi *info.FightOverInfo) {
if foi.Reason == 0 && foi.WinnerId == c.GetInfo().UserID { //我放获胜
if foi.Reason == 0 { //我放获胜
c.Info.MessWin += 1
if foi.WinnerId == c.GetInfo().UserID {
c.Info.MessWin += 1
} else {
p.GetInfo().MessWin += 1
}
}
@@ -34,7 +38,7 @@ func (h Controller) PET_MELEE(data *fight.StartPetWarInboundInfo, c *player.Play
func (h Controller) PET_King(data *fight.PetKingJoinInboundInfo, c *player.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
c.Fightinfo.Status = info.BattleStatus.FIGHT_WITH_PLAYER
c.Fightinfo.PlayerID = 0
switch data.Type {
case 5:
c.Fightinfo.Mode = info.BattleMode.SINGLE_MODE
@@ -43,9 +47,12 @@ func (h Controller) PET_King(data *fight.PetKingJoinInboundInfo, c *player.Playe
}
err = c.JoinFight(func(p common.PlayerI) bool {
fight.NewFight(p, c, func(foi *info.FightOverInfo) {
if foi.Reason == 0 && foi.WinnerId == c.GetInfo().UserID { //我放获胜
c.Info.MonKingWin += 1
if foi.Reason == 0 { //我放获胜
if foi.WinnerId == c.GetInfo().UserID {
c.Info.MonKingWin += 1
} else {
p.GetInfo().MonKingWin += 1
}
}
}) ///开始对战,房主方以及被邀请方

View File

@@ -17,45 +17,65 @@ func (h Controller) OnPlayerHandleFightInvite(data *fight.HandleFightInviteInbou
return nil, errorcode.ErrorCodes.ErrInBattle
}
c.Fightinfo.PlayerID = c.Info.UserID
//c.Fightinfo.PlayerID = c.Info.UserID
c.Fightinfo.Mode = data.Mode
c.Fightinfo.Status = 1
c.Fightinfo.Type = 0
err = c.AgreeBattle(data.UserID, data.Flag, func(p common.PlayerI) bool {
resp := &info.S2C_NOTE_HANDLE_FIGHT_INVITE{
UserID: c.Info.UserID,
Nick: c.Info.Nick,
}
_, err = fight.NewFight(p, c, func(foi *info.FightOverInfo) {
for _, v := range c.HavePVPinfo {
if v.GetInfo().UserID == data.UserID {
resp.Result = data.Flag
// 检查邀请者的邀请是否有效(对方已取消邀请)
if v.Getfightinfo().Status == 0 {
resp.Result = 4 // 邀请已取消
v.SendPackCmd(2502, &resp)
atomic.StoreUint32(&c.Fightinfo.Status, 0)
return
}
})
return err <= 0
})
_, err = fight.NewFight(v, c, func(foi *info.FightOverInfo) {
})
if err <= 0 { //成功发起对战
c.HavePVPinfo = make([]common.PlayerI, 0)
return
} else {
resp.Result = 3
v.SendPackCmd(2502, &resp)
atomic.StoreUint32(&c.Fightinfo.Status, 0)
return
}
}
}
atomic.StoreUint32(&c.Fightinfo.Status, 0)
return
}
// 邀请其他人进行战斗
func (h Controller) OnPlayerInviteOtherFight(data *fight.InviteToFightInboundInfo, c *player.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
//进入邀请,以及确认对战模式
// if !atomic.CompareAndSwapUint32(&c.Fightinfo.PlayerID, 0, data.UserID) { //邀请前提是自己没邀请别人
// return nil, errorcode.ErrorCodes.ErrCannotPerformAction
// }
c.Fightinfo.PlayerID = data.UserID
// c.Fightinfo.PlayerID = data.UserID
c.Fightinfo.Mode = data.Mode
c.Fightinfo.Status = 1
c.Fightinfo.Type = 0
c.InvitePlayerToBattle()
// c.Fightinfo.Type = 0
v, ok := c.GetSpace().User.Load(data.UserID)
if ok {
v.InvitePlayer(c)
}
return nil, 0
}
// 取消队列
func (h Controller) OnPlayerCanceledOtherInviteFight(data *fight.InviteFightCancelInboundInfo, c *player.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
if atomic.LoadUint32(&c.Fightinfo.Status) != 0 { //如果没有战斗状态,则不做任何处理
atomic.StoreUint32(&c.Fightinfo.Status, 0) //设置状态为0
return nil, 0
}
//否则报错
return nil, errorcode.ErrorCodes.ErrCannotCancelBattle
atomic.StoreUint32(&c.Fightinfo.Status, 0) //设置状态为0
return
}

View File

@@ -27,7 +27,7 @@ func (h Controller) UserSimInfo(data *user.SimUserInfoInboundInfo, c *player.Pla
func (h Controller) UserMoreInfo(data *user.MoreUserInfoInboundInfo, c *player.Player) (result *user.MoreUserInfoOutboundInfo, err errorcode.ErrorCode) {
ret := &user.MoreUserInfoOutboundInfo{}
info := c.Service.Info.Person(data.UserId)
copier.Copy(ret, info)
copier.CopyWithOption(ret, info, copier.Option{IgnoreEmpty: true, DeepCopy: true})
//todo 待实现
return ret, 0
@@ -92,7 +92,7 @@ func (h Controller) ChangePlayerDoodle(data *user.ChangeDoodleInboundInfo, c *pl
}
func (h Controller) ChangeNONOColor(data *user.ChangeNONOColorInboundInfo, c *player.Player) (result *user.ChangeNONOColorOutboundInfo, err errorcode.ErrorCode) {
//c.Info.Coins -= 200
c.Info.NONO.Color = data.Color
c.Info.NONO.NonoColor = data.Color
result = &user.ChangeNONOColorOutboundInfo{
Sataus: c.Info.UserID,

View File

@@ -4,7 +4,6 @@ import (
"bytes"
"encoding/binary"
"fmt"
"reflect"
"github.com/lunixbochs/struc"
)
@@ -35,43 +34,18 @@ func NewTomeeHeader(cmd uint32, userid uint32) *TomeeHeader {
// Pack 组包方法手动编码字节流兼容interface{}、nil、多层指针/接口
func (h *TomeeHeader) Pack(data any) []byte {
//h.Result = 0//默认置0
//t := reflect.TypeOf(data)
tv := reflect.ValueOf(data)
var datar []byte
// 处理指针类型
if tv.Kind() == reflect.Ptr {
//tv = t.Elem() // 获取指针指向的类型
tv = tv.Elem() // 获取指针指向的值
}
switch tv.Kind() {
case reflect.String:
datar = []byte(tv.String())
case reflect.Slice:
datar = data.([]byte)
//p.Conn.Write(p.pack(cmd, data.([]byte))) //写入数据
case reflect.Struct:
var data1 bytes.Buffer
err := struc.Pack(&data1, data)
if err != nil {
fmt.Println(err)
}
datar = data1.Bytes()
default:
datar = []byte{}
// fmt.Println(err, datar)
// p.Conn.Write(p.pack(cmd, data))
if data == nil {
return h.packHeaderWithData([]byte{})
}
var data1 bytes.Buffer
err := struc.Pack(&data1, data)
if err != nil {
fmt.Println(err)
}
//datar = data1.Bytes()
// 4. 手动打包包头+数据体
return h.packHeaderWithData(datar)
return h.packHeaderWithData(data1.Bytes())
}
// packHeaderWithData 手动编码包头和数据体(静态指定偏移量,无自增变量)

View File

@@ -209,16 +209,18 @@ func (f *FightC) handleNPCFightSpecial(startInfo *info.FightStartOutboundInfo) {
// startBattle 启动战斗核心逻辑:提交战斗循环任务并通知双方
func (f *FightC) startBattle(startInfo info.FightStartOutboundInfo) {
// 提交战斗循环到战斗池(处理战斗池容量问题)
if err := Fightpool.Submit(f.battleLoop); err != nil {
log.Panic(context.Background(), "战斗循环提交失败", "error", err)
}
f.Broadcast(func(ff *input.Input) {
f.startl.Do(func() {
// 提交战斗循环到战斗池(处理战斗池容量问题)
if err := Fightpool.Submit(f.battleLoop); err != nil {
log.Panic(context.Background(), "战斗循环提交失败", "error", err)
}
f.Broadcast(func(ff *input.Input) {
// 通知双方玩家准备完成,即将开始战斗
// 通知双方玩家准备完成,即将开始战斗
ff.Player.SendPackCmd(2504, &startInfo)
ff.Player.SendPackCmd(2504, &startInfo)
})
})
}

View File

@@ -21,7 +21,7 @@ func (e *Effect130) OnSkill() bool {
return true
}
if e.Ctx().Opp.CurrentPet.PetInfo.Gender == e.Args()[0] {
if e.Ctx().Opp.CurrentPet.PetInfo.Gender != e.Args()[0] {
return true
}
// 4. 附加固定伤害从SideEffectArgs[0]获取伤害值)

View File

@@ -24,9 +24,9 @@ func (e *Effect35) Skill_Hit() bool {
switch e.Ctx().SkillEntity.Category() {
case info.Category.PHYSICAL:
e.Ctx().SkillEntity.Power += e.Ctx().Opp.GetProp(0, true) + e.Ctx().Opp.GetProp(1, true)
e.Ctx().SkillEntity.Power += (e.Ctx().Opp.GetProp(0, true) + e.Ctx().Opp.GetProp(1, true)) * 20
case info.Category.SPECIAL:
e.Ctx().SkillEntity.Power += e.Ctx().Opp.GetProp(2, true) + e.Ctx().Opp.GetProp(3, true)
e.Ctx().SkillEntity.Power += (e.Ctx().Opp.GetProp(2, true) + e.Ctx().Opp.GetProp(3, true)) * 20
}
return true

View File

@@ -55,7 +55,7 @@ type Effect38_sub struct {
func (e *Effect38_sub) Alive(t ...bool) bool {
if !e.GetBool(t...) { //说明到了回合结束取消节点,那么就将变化过的属性变化回来
if e.BoolisFalse(t...) { //说明到了回合结束取消节点,那么就将变化过的属性变化回来
//还原属性
e.Ctx().Our.CurrentPet.Info.MaxHp = e.oldtype
}

View File

@@ -43,7 +43,7 @@ func (e *Effect45) SetArgs(t *input.Input, a ...int) {
func (e *Effect45) Alive(t ...bool) bool {
if !e.GetBool(t...) && e.Hit() { //说明到了回合结束取消节点,那么就将变化过的属性变化回来
if e.BoolisFalse(t...) && e.Hit() { //说明到了回合结束取消节点,那么就将变化过的属性变化回来
//还原属性
e.Ctx().Our.CurrentPet.Info.Prop[1] = e.oldtype
}

View File

@@ -34,7 +34,7 @@ func (e *Effect51) SetArgs(t *input.Input, a ...int) {
func (e *Effect51) Alive(t ...bool) bool {
if !e.GetBool(t...) && e.Hit() { //说明到了回合结束取消节点,那么就将变化过的属性变化回来
if e.BoolisFalse(t...) && e.Hit() { //说明到了回合结束取消节点,那么就将变化过的属性变化回来
//还原属性
e.Ctx().Our.CurrentPet.Info.Prop[0] = e.oldtype
}

View File

@@ -32,7 +32,7 @@ func (e *Effect55) SetArgs(t *input.Input, a ...int) {
func (e *Effect55) Alive(t ...bool) bool {
if !e.GetBool(t...) && e.Hit() { //说明到了回合结束取消节点,那么就将变化过的属性变化回来
if e.BoolisFalse(t...) && e.Hit() { //说明到了回合结束取消节点,那么就将变化过的属性变化回来
//还原属性
e.Ctx().Our.CurrentPet.PetInfo.Type, e.Ctx().Opp.CurrentPet.PetInfo.Type = e.Ctx().Opp.CurrentPet.PetInfo.Type, e.Ctx().Our.CurrentPet.PetInfo.Type
}

View File

@@ -34,7 +34,7 @@ func (e *Effect56) SetArgs(t *input.Input, a ...int) {
func (e *Effect56) Alive(t ...bool) bool {
if !e.GetBool(t...) && e.Hit() { //说明到了回合结束取消节点,那么就将变化过的属性变化回来
if e.BoolisFalse(t...) && e.Hit() { //说明到了回合结束取消节点,那么就将变化过的属性变化回来
//还原属性
e.Ctx().Our.CurrentPet.PetInfo.Type = e.oldtype
}

View File

@@ -324,18 +324,20 @@ func (f *FightC) enterturn(fattack, sattack *action.SelectSkillAction) {
FAttack: *f.First.AttackValue,
SAttack: *f.Second.AttackValue,
}
//因为切完才能广播,所以必须和回合结束分开结算
f.Broadcast(func(ff *input.Input) {
for _, v := range f.Switch {
if ff.Player.GetInfo().UserID != v.PlayerID {
if ff.Player.GetInfo().UserID != v.Reason.UserId {
ff.Player.SendPackCmd(2407, &v.Reason)
}
}
f.Switch = []*action.ActiveSwitchAction{}
ff.Player.SendPackCmd(2505, &ret)
})
f.Switch = []*action.ActiveSwitchAction{}
f.Broadcast(func(ff *input.Input) {
ff.Player.SendPackCmd(2505, &ret)
})
}

View File

@@ -44,7 +44,7 @@ type S2C_NOTE_HANDLE_FIGHT_INVITE struct {
Result uint32
}
type Fightinfo struct {
PlayerID uint32
///PlayerID uint32
// 战斗模式 1 = 1v1 2 = 6v6 3大乱斗
Mode uint32
Type uint32 //战斗类型

View File

@@ -3,6 +3,7 @@ package fight
import (
"blazing/common/socket/errorcode"
"blazing/cool"
"fmt"
"blazing/logic/service/common"
"blazing/logic/service/fight/action"
@@ -17,14 +18,14 @@ import (
)
type FightC struct {
ReadyInfo info.NoteReadyToFightInfo
Info info.Fightinfo
IsReady bool
ownerID uint32 // 战斗发起者ID
Our *input.Input //始终等于房主ID
Opp *input.Input //对手ID
Switch []*action.ActiveSwitchAction
ReadyInfo info.NoteReadyToFightInfo
Info info.Fightinfo
IsReady bool
ownerID uint32 // 战斗发起者ID
Our *input.Input //始终等于房主ID
Opp *input.Input //对手ID
Switch []*action.ActiveSwitchAction
startl sync.Once
rand *rand.Rand
StartTime time.Time
actionChan chan action.BattleActionI // 所有操作统一从这里进入
@@ -186,6 +187,8 @@ func initfightready(in *input.Input) (info.FightUserInfo, []info.ReadyFightPetIn
// 创建新战斗,邀请方和被邀请方,或者玩家和野怪方
func NewFight(p1, p2 common.PlayerI, fn func(*info.FightOverInfo)) (*FightC, errorcode.ErrorCode) {
fmt.Println("NewFight", p1.GetInfo().UserID)
f := &FightC{}
f.ownerID = p1.GetInfo().UserID
f.callback = fn //战斗结束的回调
@@ -235,7 +238,7 @@ func NewFight(p1, p2 common.PlayerI, fn func(*info.FightOverInfo)) (*FightC, err
var t time.Duration
// 60秒后判断战斗是否开始
switch f.Info.Status {
switch f.Info.Mode {
case info.BattleMode.PET_MELEE:
t = 120 * time.Second

View File

@@ -71,7 +71,7 @@ func (f *FightC) battleLoop() {
//待退出玩家战斗状态
})
//close(f.actionChan)
// close(f.actionChan)
fmt.Println("战斗循环结束")
close(f.over)
@@ -81,7 +81,7 @@ func (f *FightC) battleLoop() {
func (f *FightC) collectPlayerActions(ourID, oppID uint32) map[uint32]action.BattleActionI {
actions := make(map[uint32]action.BattleActionI)
waitr := time.Duration(f.waittime)*time.Millisecond*10 + 30*time.Second
waitr := time.Duration(f.waittime)*time.Millisecond*10 + 60*time.Second
//fmt.Println("开始收集玩家动作", waitr)
timeout := time.After(waitr)
for len(actions) < 2 {

View File

@@ -105,10 +105,14 @@ func (e *EffectNode) AttackTime(*input.Input, *input.Input) bool {
func (e *EffectNode) Prop_Befer(in *input.Input, prop int8, level int8, ptype info.EnumAbilityOpType) bool {
return true
}
func (e *EffectNode) GetBool(t ...bool) bool {
func (e *EffectNode) BoolisFalse(t ...bool) bool {
if len(t) > 0 {
return t[0]
if t[0] == false {
return true
}
return false
}
return false
}

View File

@@ -1,8 +1,14 @@
package player
import "blazing/logic/service/common"
import (
"blazing/cool"
"blazing/logic/service/common"
"context"
)
func (p *Player) SendPackCmd(cmd uint32, b any) {
cool.Loger.Debug(context.Background(), "发送数据", p.Info.UserID, cmd)
p.SendPack(common.NewTomeeHeader(cmd, p.Info.UserID).Pack(b))
}

View File

@@ -4,30 +4,8 @@ import (
"blazing/common/socket/errorcode"
"blazing/logic/service/common"
"blazing/logic/service/fight/info"
"sync/atomic"
)
// 邀请玩家加入战斗 邀请者,被邀请者,邀请模式
func (p *Player) InvitePlayerToBattle() {
p.GetSpace().User.Range(func(key uint32, v common.PlayerI) bool {
if key == atomic.LoadUint32(&p.Fightinfo.PlayerID) { //说明这里是针对玩家邀请的
v.InvitePlayer(p)
v.SendPackCmd(2501, &info.NoteInviteToFightOutboundInfo{
UserID: p.Info.UserID,
Nick: p.Info.Nick,
Mode: p.Fightinfo.Mode,
})
return true
}
return false
})
}
func (p *Player) JoinFight(fn func(p common.PlayerI) bool) errorcode.ErrorCode {
if !p.CanFight() {
return errorcode.ErrorCodes.ErrNoEligiblePokemon
@@ -74,36 +52,3 @@ func (p *Player) SendLoadPercent(b info.LoadPercentOutboundInfo) {
//
// bool是否成功仅同意且符合条件时为true
// common.PlayerI对应的邀请者玩家成功时有效
func (p *Player) AgreeBattle(userid, flag uint32, fn func(p common.PlayerI) bool) errorcode.ErrorCode {
// 处理完毕后清空收到的邀请列表原defer逻辑保留
resp := &info.S2C_NOTE_HANDLE_FIGHT_INVITE{
UserID: p.Info.UserID,
Nick: p.Info.Nick,
}
for _, o := range p.HavePVPinfo {
if o != nil && o.Getfightinfo() == p.Fightinfo {
resp.Result = flag
// 检查邀请者的邀请是否有效(对方已取消邀请)
if o.Getfightinfo().PlayerID == 0 {
resp.Result = 4 // 邀请已取消
}
//把不在线和不满足出战要求放到战斗检测里
//flasg本身就是00
if fn(o) { //发起成功
p.HavePVPinfo = make([]common.PlayerI, 0)
return -1 //返回
} else { //发起失败
resp.Result = 3
o.SendPackCmd(2502, &resp)
return -1 //返回
}
}
}
return errorcode.ErrorCodes.ErrSystemError
}

View File

@@ -5,6 +5,7 @@ import (
"blazing/cool"
"blazing/logic/service/common"
"encoding/binary"
"encoding/hex"
"sync"
"context"
@@ -113,8 +114,10 @@ func (h *ClientData) Recv(data common.TomeeHeader) {
}
t1 := data.Pack(ret[0].Interface())
cool.Loger.Debug(context.Background(), "发送数据_回包", data.UserID, data.CMD, ret[0].Interface(), hex.EncodeToString(t1))
//data.Version = 49
t.SendPack(data.Pack(ret[0].Interface()))
t.SendPack(t1)
}

View File

@@ -91,6 +91,12 @@ func (p *Player) GetAction() {
func (f *Player) InvitePlayer(ff common.PlayerI) {
f.HavePVPinfo = append(f.HavePVPinfo, ff)
tt := common.NewTomeeHeader(2501, f.GetInfo().UserID)
f.SendPack(tt.Pack(&info.NoteInviteToFightOutboundInfo{
UserID: ff.GetInfo().UserID,
Nick: ff.GetInfo().Nick,
Mode: ff.Getfightinfo().Mode,
}))
}
func (p *Player) Getfightinfo() info.Fightinfo {
@@ -99,7 +105,7 @@ func (p *Player) Getfightinfo() info.Fightinfo {
func (p *Player) QuitFight() {
//将战斗标记设置为0 这里的标记是
atomic.StoreUint32(&p.Fightinfo.Status, 0)
atomic.StoreUint32(&p.Fightinfo.PlayerID, 0)
p.FightC = nil
}
@@ -153,6 +159,7 @@ func (p *Player) SendPack(b []byte) error {
}
_, ok := p.MainConn.Context().(*ClientData)
if ok {
return p.MainConn.Context().(*ClientData).SendPack(b)
}

View File

@@ -54,6 +54,7 @@ func (s *Space) EnterMap(c common.PlayerI) {
out := info.NewOutInfo()
copier.CopyWithOption(out, c.GetInfo(), copier.Option{DeepCopy: true})
s.User.Store(c.GetInfo().UserID, c)
s.UserInfo.Store(c.GetInfo().UserID, *out)
s.Broadcast(c, 2001, out)

View File

@@ -23,6 +23,22 @@ import (
func main() {
// element.TestAllScenarios()
// for i := 0; i < 1000000; i++ {
// go func() {
// ff := &info.LeaveMapOutboundInfo{
// 10001,
// }
// t := common.NewTomeeHeader(2002, 10001).Pack(ff)
// if len(t) != 21 {
// panic(t)
// }
// }()
// }
//service.TestSendVerificationCode()
// t := model.GenPetInfo(1, 31, 1, 1, 1, 1)

View File

@@ -140,7 +140,7 @@ type PlayerInfo struct {
HasNono uint32 `struc:"uint32" default:"1" json:"has_nono"` // 玩家是否有nono
SuperNono uint32 `struc:"uint32" default:"1" json:"super_nono"` // 玩家是否有超能nono
NonoState uint32 `struc:"uint32" default:"4294967295" json:"nono_state"` // 默认-1
Color uint32 `struc:"uint32" json:"nono_color"` // nono颜色
NonoColor uint32 `struc:"uint32" json:"nono_color"` // nono颜色
Nick string `struc:"[16]byte" default:"nono" json:"nono_nick"` // nono名字16字节
}