2026-01-19 18:51:56 +08:00
|
|
|
|
package model
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
|
"blazing/cool"
|
|
|
|
|
|
"fmt"
|
|
|
|
|
|
"math"
|
|
|
|
|
|
|
|
|
|
|
|
"github.com/creasty/defaults"
|
|
|
|
|
|
"github.com/gogf/gf/v2/os/gtime"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
const TableNamePlayerInfo = "player_info"
|
|
|
|
|
|
|
|
|
|
|
|
type Player struct {
|
|
|
|
|
|
*cool.Model
|
2026-03-05 14:56:28 +08:00
|
|
|
|
PlayerID uint64 `gorm:"not null;uniqueIndex;index:idx_pet_by_player_id;comment:'所属玩家ID'" json:"player_id"`
|
|
|
|
|
|
LastResetTime *gtime.Time `struc:"skip" json:"last_reset_time"` // 重置时间,比如电池和每日任务
|
2026-03-05 23:51:07 +08:00
|
|
|
|
WeekLastResetTime *gtime.Time `struc:"skip" json:"week_last_reset_time"`
|
2026-03-05 14:56:28 +08:00
|
|
|
|
Data PlayerInfo `gorm:"type:jsonb;not null;comment:'全部数据'" json:"data"`
|
2026-01-19 18:51:56 +08:00
|
|
|
|
}
|
2026-02-07 20:09:02 +08:00
|
|
|
|
|
2026-01-19 18:51:56 +08:00
|
|
|
|
type Pos struct {
|
|
|
|
|
|
X uint32 `struc:"uint32" default:"0"`
|
|
|
|
|
|
Y uint32 `struc:"uint32" default:"0"`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 计算两个uint32的差值绝对值(转为int64避免溢出)
|
|
|
|
|
|
func absDiff(a, b uint32) int64 {
|
|
|
|
|
|
return int64(math.Abs(float64(int64(a) - int64(b))))
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 判断两个Pos的X和Y差值的绝对值是否均小于50
|
|
|
|
|
|
func bothDiffsLessThan50(pos1, pos2 Pos) bool {
|
|
|
|
|
|
xDiff := absDiff(pos1.X, pos2.X)
|
|
|
|
|
|
yDiff := absDiff(pos1.Y, pos2.Y)
|
|
|
|
|
|
return xDiff < 50 && yDiff < 50
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (p Pos) BothLessThan50(t Pos) bool {
|
|
|
|
|
|
|
|
|
|
|
|
return bothDiffsLessThan50(p, t)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// PeopleItemInfo 穿戴装备信息结构(PeopleItemInfo)
|
|
|
|
|
|
type PeopleItemInfo struct {
|
|
|
|
|
|
ID uint32 `struc:"uint32"` // 装备id
|
|
|
|
|
|
Level uint32 `struc:"uint32" default:"1"` // 未知字段(默认值1,@Builder.Default)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// InitDefaults 初始化默认值(确保默认值正确赋值)
|
|
|
|
|
|
func (p *PeopleItemInfo) InitDefaults() {
|
|
|
|
|
|
p.Level = 1 // 未知字段默认值1,与Java的@Builder.Default保持一致
|
|
|
|
|
|
}
|
|
|
|
|
|
func NewPlayerInfo() PlayerInfo {
|
|
|
|
|
|
l := PlayerInfo{
|
|
|
|
|
|
|
2026-04-02 02:33:05 +08:00
|
|
|
|
Clothes: make([]PeopleItemInfo, 0),
|
|
|
|
|
|
PetList: make([]PetInfo, 0),
|
|
|
|
|
|
BackupPetList: make([]PetInfo, 0),
|
2026-01-19 18:51:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 自动填充 struct tag 里的 default 值
|
|
|
|
|
|
if err := defaults.Set(&l); err != nil {
|
|
|
|
|
|
panic(err) // 方便发现 default 设置错误
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return l
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// TaskStatus 任务状态(与 AS3 对应)
|
|
|
|
|
|
type TaskStatus uint8
|
|
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
|
Unaccepted TaskStatus = 0 // 未接受(AS3 中 0 或 2 映射至此)
|
|
|
|
|
|
Accepted TaskStatus = 1 // 已接受
|
|
|
|
|
|
Completed TaskStatus = 3 // 已完成
|
|
|
|
|
|
Reserved TaskStatus = 2 // 预留(AS3 中映射为未接受)
|
|
|
|
|
|
)
|
|
|
|
|
|
|
2026-01-25 23:17:46 +08:00
|
|
|
|
// 定义检查函数:判断84-87索引中是否有任意一个元素不等于3
|
|
|
|
|
|
func (lw *PlayerInfo) IsNewPlayer() bool {
|
|
|
|
|
|
// 遍历84到87的索引
|
|
|
|
|
|
for i := 85; i <= 88; i++ {
|
|
|
|
|
|
if lw.GetTask(i) != Completed {
|
|
|
|
|
|
return true // 只要有一个不等于3,就返回true
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return false // 全部等于3则返回false
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-19 18:51:56 +08:00
|
|
|
|
// SetTask 设置第 i 个任务的状态(0 ≤ i < 2000)
|
|
|
|
|
|
func (m *PlayerInfo) SetTask(i int, status TaskStatus) error {
|
|
|
|
|
|
i-- //下标减1
|
|
|
|
|
|
if i < 0 || i >= 4000 {
|
|
|
|
|
|
return fmt.Errorf("index out of range: %d (must be 0-1999)", i)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
byteIdx := i / 4
|
|
|
|
|
|
bitOffset := (i % 4) * 2
|
|
|
|
|
|
|
|
|
|
|
|
// 清除原有 2 位
|
|
|
|
|
|
m.TaskList[byteIdx] &^= 0x3 << bitOffset
|
|
|
|
|
|
|
|
|
|
|
|
// 设置新状态(确保只取低 2 位)
|
|
|
|
|
|
m.TaskList[byteIdx] |= byte(status&0x3) << bitOffset
|
|
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// GetTask 获取第 i 个任务的状态
|
|
|
|
|
|
func (m *PlayerInfo) GetTask(i int) TaskStatus {
|
|
|
|
|
|
i-- //下标减1
|
2026-04-15 03:46:55 +08:00
|
|
|
|
if i < 0 || i >= 4000 {
|
2026-02-08 04:17:25 +08:00
|
|
|
|
return Reserved
|
|
|
|
|
|
}
|
2026-01-19 18:51:56 +08:00
|
|
|
|
|
|
|
|
|
|
byteIdx := i / 4
|
|
|
|
|
|
bitOffset := (i % 4) * 2
|
|
|
|
|
|
|
|
|
|
|
|
return TaskStatus((m.TaskList[byteIdx] >> bitOffset) & 0x3)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
type PlayerInfo struct {
|
2026-02-12 04:28:20 +08:00
|
|
|
|
ExpPool int64 `struc:"skip" json:"exp_pool"` // 累计经验池
|
2026-01-19 18:51:56 +08:00
|
|
|
|
|
2026-02-12 04:28:20 +08:00
|
|
|
|
OnlineTime int64 `struc:"skip" json:"online_time"` //在线分钟数
|
2026-02-13 22:57:05 +08:00
|
|
|
|
//FightTime int64 `struc:"skip" json:"fight_time"` //战斗分钟数
|
2026-01-19 18:51:56 +08:00
|
|
|
|
// OutInfo 字段
|
|
|
|
|
|
UserID uint32 `struc:"uint32" json:"user_id"` // 米米号 通过sid拿到
|
|
|
|
|
|
RegisterTime uint32 `struc:"uint32" json:"register_time"` // 注册时间(秒时间戳)
|
|
|
|
|
|
Nick string `struc:"[16]byte" default:"seer" json:"nick"` // 16字节昵称
|
|
|
|
|
|
Title uint32 `struc:"uint32" json:"title"` // 称号
|
|
|
|
|
|
Vip uint16 `struc:"uint16" json:"vip"` // 固定0
|
|
|
|
|
|
Viped uint16 `struc:"uint16" default:"15" json:"viped"` // 固定15
|
|
|
|
|
|
DSFlag uint32 `struc:"uint32" json:"ds_flag"` // 固定0
|
|
|
|
|
|
Color uint32 `struc:"uint32" json:"color"` // 机器人颜色RGB颜色值(uint32,实际为3个uint8)
|
|
|
|
|
|
Texture uint32 `struc:"uint32" json:"texture"` // 固定0
|
|
|
|
|
|
Energy uint32 `struc:"uint32" default:"3000" json:"energy"` // 固定3000
|
2026-02-12 04:28:20 +08:00
|
|
|
|
Coins int64 `struc:"uint32" json:"coins"` // 赛尔豆
|
|
|
|
|
|
EVPool int64 `struc:"uint32" json:"ev_pool"` //累计学习力
|
2026-01-19 18:51:56 +08:00
|
|
|
|
FightBadge uint32 `struc:"uint32" json:"fight_badge"` // 固定0
|
|
|
|
|
|
MapID uint32 `struc:"uint32" default:"1" json:"map_id"` // 上线地图ID
|
|
|
|
|
|
Pos Pos `json:"pos"` // 坐标
|
2026-02-12 04:28:20 +08:00
|
|
|
|
TimeToday int64 `struc:"uint32" default:"0" json:"time_today"` // 已消耗时间(秒)
|
|
|
|
|
|
TimeLimit int64 `struc:"uint32" default:"43200" json:"time_limit"` // 总电池限制(秒)
|
2026-01-19 18:51:56 +08:00
|
|
|
|
IsClothHalfDay byte `struc:"byte" json:"is_cloth_half_day"` // 活动标志0/1
|
|
|
|
|
|
IsRoomHalfDay byte `struc:"byte" json:"is_room_half_day"` // 活动标志0/1
|
|
|
|
|
|
IFortressHalfDay byte `struc:"byte" json:"i_fortress_half_day"` // 活动标志0/1
|
|
|
|
|
|
IsHQHalfDay byte `struc:"byte" json:"is_hq_half_day"` // 活动标志0/1
|
|
|
|
|
|
LoginCount uint32 `struc:"uint32" json:"login_count"` // 固定0
|
|
|
|
|
|
Inviter uint32 `struc:"uint32" json:"inviter"` // 固定0
|
|
|
|
|
|
NewInviteeCount uint32 `struc:"uint32" json:"new_invitee_count"` // 固定0
|
|
|
|
|
|
VipLevel uint32 `struc:"uint32" default:"8" json:"vip_level"` // 固定8
|
|
|
|
|
|
VipValue uint32 `struc:"uint32" default:"80000" json:"vip_value"` // 固定80000
|
|
|
|
|
|
VipStage uint32 `struc:"uint32" default:"1" json:"vip_stage"` // 超no的外形等级建议固定1
|
|
|
|
|
|
AutoCharge uint32 `struc:"uint32" default:"1" json:"auto_charge"` // nono是否自动充电
|
|
|
|
|
|
VipEndTime uint32 `struc:"uint32" default:"4294967295" json:"vip_end_time"` // 超no的结束时间建议尽可能大
|
|
|
|
|
|
FreshManBonus uint32 `struc:"uint32" json:"fresh_man_bonus"` // 邀请活动建议先给固定值0
|
|
|
|
|
|
//NonoChipList [80]byte `struc:"[80]byte" json:"-"` // 超no芯片列表
|
|
|
|
|
|
DailyResArr [50]byte `struc:"[50]byte" default:"0" json:"daily_res_arr"` // 每日任务状态 40+是谱尼的
|
|
|
|
|
|
Study struct {
|
|
|
|
|
|
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, 虚无 元素 能量 生命 轮回 永恒 圣洁 最高为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"` // 精灵王胜场
|
|
|
|
|
|
MessWin uint32 `struc:"skip" json:"mess_win"` // 大乱斗胜场
|
|
|
|
|
|
CurrentStage uint32 `struc:"uint32" default:"1" json:"current_stage"` // 勇者之塔层数
|
|
|
|
|
|
MaxStage uint32 `struc:"uint32" json:"max_stage"` // 试炼之塔最高层
|
|
|
|
|
|
CurrentFreshStage uint32 `struc:"uint32" default:"1" json:"current_fresh_stage"` // 当前试炼层数
|
|
|
|
|
|
MaxFreshStage uint32 `struc:"uint32" json:"max_fresh_stage"` // 最高试炼层
|
|
|
|
|
|
MaxArenaWins uint32 `struc:"uint32" json:"max_arena_wins"` // 星际擂台连胜
|
2026-03-03 19:28:59 +08:00
|
|
|
|
TwoTimes int32 `struc:"uint32" default:"0" json:"two_times"` // 双倍经验加速器剩余使用次数
|
|
|
|
|
|
ThreeTimes int32 `struc:"uint32" default:"0" json:"three_times"` // 三倍经验加速器剩余使用次数
|
2026-01-19 18:51:56 +08:00
|
|
|
|
AutoFight uint32 `struc:"uint32" default:"0" json:"auto_fight"` // 是否自动战斗
|
|
|
|
|
|
AutoFightTime uint32 `struc:"uint32" default:"0" json:"auto_fight_time"` // 自动战斗剩余的场次
|
2026-03-03 19:28:59 +08:00
|
|
|
|
EnergyTime int32 `struc:"uint32" default:"0" json:"energy_time"` // 能量吸收仪剩余次数
|
2026-01-19 18:51:56 +08:00
|
|
|
|
LearnTimes uint32 `struc:"uint32" default:"0" json:"learn_times"` // 学习力吸收仪剩余次数
|
|
|
|
|
|
MonBattleMedal uint32 `struc:"uint32" default:"0" json:"mon_battle_medal"` // 默认0
|
|
|
|
|
|
RecordCount uint32 `struc:"uint32" default:"0" json:"record_count"` // 默认0
|
|
|
|
|
|
ObtainTm uint32 `struc:"uint32" default:"0" json:"obtain_tm"` // 默认0
|
|
|
|
|
|
SoulBeadItemID uint32 `struc:"uint32" json:"soul_bead_item_id"` // 当前元神珠id
|
|
|
|
|
|
ExpireTm uint32 `struc:"uint32" default:"0" json:"expire_tm"` // 默认0
|
|
|
|
|
|
FuseTimes uint32 `struc:"uint32" default:"0" json:"fuse_times"` // 默认0
|
|
|
|
|
|
|
|
|
|
|
|
NONO struct {
|
|
|
|
|
|
//fieldDescription:"1为跟随 0为收回 且如果为收回 那么后续结构不需要发送, 不序列化"
|
|
|
|
|
|
Flag uint32 `struc:"skip" json:"nono_flag"`
|
|
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
NonoColor uint32 `struc:"uint32" json:"nono_color"` // nono颜色
|
|
|
|
|
|
Nick string `struc:"[16]byte" default:"nono" json:"nono_nick"` // nono名字(16字节)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-13 10:21:13 +08:00
|
|
|
|
TeamInfo TeamInfo `struc:"struct" json:"team_info"` // 战队信息24字节
|
|
|
|
|
|
TeamPkInfo TeamPKInfo `struc:"struct" json:"team_pk_info"` // 8字节
|
|
|
|
|
|
Reserved byte `struc:"byte" json:"reserved"` // 1字节无内容
|
|
|
|
|
|
Badge uint32 `struc:"uint32" default:"0" json:"badge"` // 默认0
|
|
|
|
|
|
Reserved1 [27]byte `struc:"[27]byte" default:"3" json:"reserved1"` // 27字节默认3
|
|
|
|
|
|
TaskList [1000]byte `struc:"[1000]byte" default:"0" json:"task_list"` // 任务状态数组500字节,默认3
|
|
|
|
|
|
PetListLen uint32 `struc:"uint32,sizeof=PetList" json:"-"` // 登录包体中的出战精灵数量
|
|
|
|
|
|
PetList []PetInfo `json:"pet_list"` // 精灵背包内信息
|
|
|
|
|
|
BackupPetListLen uint32 `struc:"uint32,sizeof=BackupPetList" json:"-"` // 登录包体中的备用精灵数量
|
|
|
|
|
|
BackupPetList []PetInfo `json:"backup_pet_list"` // 精灵并列备用列表
|
|
|
|
|
|
ClothesCount uint32 `struc:"sizeof=Clothes" json:"clothes_count"` // 穿戴装备数量
|
|
|
|
|
|
Clothes []PeopleItemInfo ` json:"clothes"` // 穿戴装备
|
2026-01-19 18:51:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// trace("个人装扮是否半价:",MainManager.isClothHalfDay);
|
|
|
|
|
|
// trace("小屋装扮是否半价:",MainManager.isRoomHalfDay);
|
|
|
|
|
|
// trace("要塞装扮是否半价:",MainManager.iFortressHalfDay);
|
|
|
|
|
|
// trace("总部装扮是否半价:",MainManager.isHQHalfDay);
|
|
|
|
|
|
//
|
|
|
|
|
|
// TableName PlayerInfo's table name
|
|
|
|
|
|
func (*Player) TableName() string {
|
|
|
|
|
|
return TableNamePlayerInfo
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// GroupName PlayerInfo's table group
|
|
|
|
|
|
func (*Player) GroupName() string {
|
|
|
|
|
|
return "default"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// NewPlayerInfo create a new PlayerInfo
|
2026-02-07 20:09:02 +08:00
|
|
|
|
func NewPlayer() *Player {
|
|
|
|
|
|
return &Player{
|
|
|
|
|
|
Model: cool.NewModel(),
|
2026-01-19 18:51:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// init 创建表
|
|
|
|
|
|
func init() {
|
|
|
|
|
|
cool.CreateTable(&Player{})
|
|
|
|
|
|
}
|