All checks were successful
ci/woodpecker/push/my-first-workflow Pipeline was successful
fix(fight): 修复单输入战斗中效果处理逻辑错误 - 在Effect201的OnSkill方法中调整了多输入战斗检查的位置, 确保单输入战斗中的单目标效果被正确忽略 - 添加了针对单输入战斗中单目标效果的测试用例 - 移除了重复的多输入战斗检查代码 feat(fight): 添加战斗初始化时捕获标识设置功能 - 在initfightready函数中添加对CanCapture字段的处理 将玩家的捕获能力信息传递到战斗准备信息中 - 在ReadyFightPetInfo结构体中添加IsCapture字段用于 标识宠物是否为捕获类型 refactor(fight): 调整战斗初始化顺序确保数据一致性 - 将ReadyInfo初始化移到绑定输入上下文之后执行 确保团队视图链接完成后再进行准备信息构建 fix(player): 增加宠物血量检查避免无效匹配 - 在玩家匹配检测中增加首只宠物血量检查 当首只宠物血量为0时不参与匹配以防止异常情况 ```
195 lines
7.9 KiB
Go
195 lines
7.9 KiB
Go
package model
|
||
|
||
import (
|
||
"blazing/common/data"
|
||
"blazing/cool"
|
||
|
||
"github.com/gogf/gf/v2/os/gtime"
|
||
"github.com/tnnmigga/enum"
|
||
)
|
||
|
||
// 表名常量
|
||
const TableNamePlayerPVP = "player_pvp"
|
||
const Curpvp = 0
|
||
|
||
// PVP 对应数据库表 player_pvp,用于记录用户PVP赛季数据及场次统计
|
||
type PVP struct {
|
||
*cool.Model
|
||
PlayerID uint32 `gorm:"not null;index:idx_pvp_player_id;comment:'所属玩家ID'" json:"player_id"`
|
||
//第几赛季
|
||
Season uint32 `gorm:"not null;default:0;comment:'赛季R'" json:"season"`
|
||
//本赛季排名信息'通过下标来确认当前赛季
|
||
RankInfo PVPRankInfo `gorm:"type:jsonb;not null;comment:'赛季核心数据'" json:"rank_info"`
|
||
}
|
||
|
||
func (u *PVP) Less(than *PVP) bool {
|
||
if u.RankInfo.Score == than.RankInfo.Score {
|
||
return u.RankInfo.LastMatchTime.Unix() < than.RankInfo.LastMatchTime.Unix()
|
||
}
|
||
return u.RankInfo.Score < than.RankInfo.Score
|
||
}
|
||
func NewPVP() *PVP {
|
||
return &PVP{
|
||
Model: cool.NewModel(),
|
||
}
|
||
}
|
||
|
||
// PVPSeasonData PVP赛季核心统计数据
|
||
// 聚合维度:总场次、胜负、积分、胜率等
|
||
type PVPRankInfo struct {
|
||
Rank uint32 `json:"rank"` // 本赛季全服排名(0=未上榜)
|
||
Score int `json:"score"` // 当前积分
|
||
WinStreak uint32 `json:"win_streak"` // 当前连胜场次
|
||
TotalMatch uint32 `json:"total_match"` // 本赛季总场次
|
||
WinMatch uint32 `json:"win_match"` // 本赛季胜利场次
|
||
LoseMatch uint32 `json:"lose_match"` // 本赛季失败场次
|
||
DrawMatch uint32 `json:"draw_match"` // 本赛季平局场次
|
||
TotalScore int32 `json:"total_score"` // 本赛季总积分(胜加负减)
|
||
HighestScore int32 `json:"highest_score"` // 本赛季最高积分
|
||
ContinuousWin uint32 `json:"continuous_win"` // 本赛季最高连胜次数
|
||
LastMatchTime *gtime.Time `json:"last_match_time"` // 最后一场PVP时间(时间戳)
|
||
}
|
||
|
||
// func (u *PVPRankInfo) Key() uint32 {
|
||
// return uint32(u.ID)
|
||
// }
|
||
|
||
// 如果分数不对的话,就按时间排序
|
||
|
||
// NoteReadyToFightInfo 战斗准备就绪消息结构体,NoteReadyToFightInfo
|
||
type NoteReadyToFightInfo struct {
|
||
//MAXPET uint32 `struc:"skip"` // 最大精灵数 struc:"skip"`
|
||
// 战斗类型ID(与野怪战斗为3,与人战斗为1,前端似乎未使用)
|
||
Status uint32 `fieldDesc:"战斗类型ID 但前端好像没有用到 与野怪战斗为3,与人战斗似乎是1" `
|
||
//Mode uint32 `struc:"skip"`
|
||
// 我方信息
|
||
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"`
|
||
// 敌方的精灵信息
|
||
// 野怪战斗时:客户端接收此包前已生成精灵PetInfo,将部分信息写入该列表
|
||
OpponentPetList []ReadyFightPetInfo `fieldDesc:"敌方的精灵信息 如果是野怪 那么再给客户端发送这个包体时就提前生成好了这只精灵的PetInfo,然后把从PetInfo中把部分信息写入到这个敌方的精灵信息中再发送这个包结构体" serialize:"lengthFirst,lengthType=uint16,type=structArray"`
|
||
}
|
||
type FightUserInfo struct {
|
||
// 用户ID(野怪为0)
|
||
UserID uint32 `fieldDesc:"userID 如果为野怪则为0" `
|
||
|
||
// 玩家名称(野怪为UTF-8的'-',固定16字节)
|
||
// 使用[16]byte存储固定长度的字节数组
|
||
Nick string `struc:"[16]byte"`
|
||
}
|
||
|
||
// ReadyFightPetInfo 准备战斗的精灵信息结构体,ReadyFightPetInfo类
|
||
type ReadyFightPetInfo struct {
|
||
// 精灵ID
|
||
ID uint32 `fieldDesc:"精灵ID" `
|
||
|
||
// 精灵等级
|
||
Level uint32 `fieldDesc:"精灵等级" `
|
||
|
||
// 精灵当前HP
|
||
Hp uint32 `fieldDesc:"精灵HP" `
|
||
|
||
// 精灵最大HP
|
||
MaxHp uint32 `fieldDesc:"最大HP" `
|
||
SkillListLen uint32 `struc:"sizeof=SkillList"`
|
||
// 技能信息列表(固定4个元素,技能ID和剩余PP,无技能则为0)
|
||
// List<SkillInfo>,初始化容量为4
|
||
SkillList []SkillInfo `fieldDesc:"技能信息 技能ID跟剩余PP 固定32字节 没有给0" serialize:"fixedLength=4,type=structArray"`
|
||
|
||
// 精灵捕获时间
|
||
CatchTime uint32 `fieldDesc:"精灵捕获时间" `
|
||
|
||
// 捕捉地图(固定给0)
|
||
CatchMap uint32 `fieldDesc:"捕捉地图 给0" `
|
||
|
||
// 固定给0
|
||
CatchRect uint32 `fieldDesc:"给0" `
|
||
|
||
// 固定给0
|
||
CatchLevel uint32 `fieldDesc:"给0" `
|
||
SkinID uint32 `fieldDesc:"精灵皮肤ID" `
|
||
ShinyLen uint32 `json:"-" struc:"sizeof=ShinyInfo"`
|
||
ShinyInfo []data.GlowFilter `json:"ShinyInfo,omitempty"`
|
||
IsCapture uint8 `struc:"uint8" json:"isCapture"`
|
||
}
|
||
type FightOverInfo struct {
|
||
//0 正常结束
|
||
//1=isPlayerLost 对方玩家退出
|
||
// 2=isOvertime 超时
|
||
// 3=isDraw 双方平手
|
||
// 4=isSysError 系统错误
|
||
// 5=isNpcEscape 精灵主动逃跑
|
||
|
||
Winpet *PetInfo `struc:"skip"`
|
||
Round uint32 `struc:"skip"`
|
||
// Duration uint32 `struc:"skip"` // 对局时长(秒)
|
||
//7 切磋结束
|
||
Reason EnumBattleOverReason // 固定值0
|
||
WinnerId uint32 // 胜者的米米号 野怪为0
|
||
TwoTimes uint32 // 双倍经验剩余次数
|
||
ThreeTimes uint32 // 三倍经验剩余次数
|
||
AutoFightTimes uint32 // 自动战斗剩余次数
|
||
EnergyTime uint32 // 能量吸收器剩余次数
|
||
LearnTimes uint32 // 双倍学习器剩余次数
|
||
}
|
||
|
||
// 战斗结束原因枚举
|
||
type EnumBattleOverReason int
|
||
|
||
var BattleOverReason = enum.New[struct {
|
||
PlayerOffline EnumBattleOverReason `enum:"1"` //掉线
|
||
PlayerOVerTime EnumBattleOverReason `enum:"2"` //超时
|
||
NOTwind EnumBattleOverReason `enum:"3"` //打成平手
|
||
DefaultEnd EnumBattleOverReason `enum:"4"` //默认结束
|
||
PlayerEscape EnumBattleOverReason `enum:"5"` //逃跑
|
||
Cacthok EnumBattleOverReason `enum:"6"`
|
||
}]()
|
||
|
||
// AttackValue 战斗中的攻击数值信息
|
||
type AttackValue struct {
|
||
UserID uint32 `json:"userId" fieldDescription:"玩家的米米号 与野怪对战userid = 0"`
|
||
ActorIndex uint32 `json:"actorIndex" fieldDescription:"当前动作所属战斗位"`
|
||
TargetIndex uint32 `json:"targetIndex" fieldDescription:"当前动作目标战斗位"`
|
||
SkillID uint32 `json:"skillId" fieldDescription:"使用技能的id"`
|
||
AttackTime uint32 `json:"attackTime" fieldDescription:"是否击中 如果为0 则miss 如果为1 则击中,2为必中"`
|
||
LostHp uint32 `json:"lostHp" fieldDescription:"我方造成的伤害"`
|
||
GainHp int32 `json:"gainHp" fieldDescription:"我方获得血量"`
|
||
RemainHp int32 `json:"remainHp" fieldDescription:"我方剩余血量"`
|
||
MaxHp uint32 `json:"maxHp" fieldDescription:"我方最大血量"`
|
||
//颜色
|
||
State uint32 `json:"state" `
|
||
SkillListLen uint32 `struc:"sizeof=SkillList"`
|
||
SkillList []SkillInfo `json:"skillList" fieldDescription:"根据精灵的数据插入技能 最多4条 不定长"`
|
||
IsCritical uint32 `json:"isCritical" fieldDescription:"是否暴击"`
|
||
Status [20]int8 //精灵的状态
|
||
// 攻击,防御,特供,特防,速度,命中
|
||
Prop [6]int8
|
||
Offensive float32
|
||
// OwnerMaxShield uint32 `json:"ownerMaxShield" fieldDescription:"我方最大护盾"`
|
||
// OwnerCurrentShield uint32 `json:"ownerCurrentShield" fieldDescription:"我方当前护盾"`
|
||
}
|
||
|
||
// TableName 返回表名
|
||
func (*PVP) TableName() string {
|
||
return TableNamePlayerPVP
|
||
}
|
||
|
||
// GroupName 返回表组名
|
||
func (*PVP) GroupName() string {
|
||
return "default"
|
||
}
|
||
|
||
// init 程序启动时自动创建表
|
||
func init() {
|
||
cool.CreateTable(&PVP{})
|
||
}
|