refactor(logic): 重构战斗相关逻辑和数据结构

- 优化了 FightPetInfo 和 AttackValue 结构体,使用更合理的数据类型
- 重新定义了战斗流程中的各种消息结构体
- 改进了宠物信息生成和计算逻辑
- 重构了宠物相关服务和控制器方法
- 优化了数据库操作,提高了代码的可读性和维护性
This commit is contained in:
2025-09-01 01:03:46 +08:00
parent 3b0a7237cc
commit 4b5c6ce129
15 changed files with 208 additions and 90 deletions

View File

@@ -12,5 +12,5 @@ func GDBM(m IModel) *gdb.Model {
// DBM 根据model获取 *gdb.Model
func DBM(m IModel) *gdb.Model {
return g.DB(m.GroupName()).Model(m.TableName()).FieldsEx("id")
return g.DB(m.GroupName()).Model(m.TableName())
}

View File

@@ -168,7 +168,7 @@ func Recv(c *socket.Conn, data handler.TomeeHeader) {
}
// fmt.Println(cmdlister)
glog.Debug(context.Background(), "接收数据", data.UserID, data.CMD)
params := []reflect.Value{}
//funct := cmdlister.Type().NumIn()

View File

@@ -7,6 +7,8 @@ import (
"blazing/logic/service/fight"
"blazing/logic/service/fight/info"
"blazing/modules/blazing/model"
"github.com/jinzhu/copier"
)
func (h Controller) OnPlayerFightNpcMonster(data *fight.FightNpcMonsterInboundInfo, c *socket.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
@@ -16,19 +18,18 @@ func (h Controller) OnPlayerFightNpcMonster(data *fight.FightNpcMonsterInboundIn
OwnerID: data.Head.UserID,
FightId: 3,
}
ttt.OurInfo = info.FightUserInfo{UserID: c.Info.UserID}
ttt.OurInfo = info.FightUserInfo{UserID: c.Info.UserID, Nick: c.Info.Nick}
ttt.OurPetList = []info.ReadyFightPetInfo{{ID: 300,
Level: 100,
MaxHp: 100,
len := len(c.Info.PetList)
ttt.OurPetList = make([]info.ReadyFightPetInfo, len)
for i := 0; i < len; i++ {
Hp: 100,
SkillListLen: 4,
}}
for i := 0; i < 4; i++ {
ttt.OurPetList[0].SkillList[i] = model.SkillInfo{ID: 10001, Pp: 1}
err := copier.CopyWithOption(&ttt.OurPetList[i], &c.Info.PetList[i], copier.Option{IgnoreEmpty: true, DeepCopy: true})
if err != nil {
panic(err)
}
}
ttt.OpponentInfo = info.FightUserInfo{UserID: 0}
ttt.OpponentPetList = []info.ReadyFightPetInfo{{ID: 1,
Level: 100,
@@ -41,23 +42,17 @@ func (h Controller) OnPlayerFightNpcMonster(data *fight.FightNpcMonsterInboundIn
c.SendPack(t1.Pack(&ttt))
return nil, -1
}
// 准备战斗
func (h Controller) OnReadyToFight(data *fight.ReadyToFightInboundInfo, c *socket.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
t1 := handler.NewTomeeHeader(2504, c.Info.UserID)
rett := fight.FightStartOutboundInfo{
IsCanAuto: 0,
Info1: fight.FightPetInfo{PetID: 300,
UserID: c.Info.UserID,
Hp: 1000,
MaxHp: 1000,
Level: 1,
CatchTime: 0,
Catchable: 1,
BattleLV: [6]byte{1, 1, 1, 1, 1, 1},
},
Info2: fight.FightPetInfo{
UserID: 0,
PetID: 1,
ID: 1,
Hp: 1000,
MaxHp: 1000,
Level: 1,
@@ -65,14 +60,36 @@ func (h Controller) OnReadyToFight(data *fight.ReadyToFightInboundInfo, c *socke
Catchable: 1,
BattleLV: [6]byte{1, 1, 1, 1, 1, 1}},
}
copier.Copy(&rett.Info1, &c.Info.PetList[0])
rett.Info1.UserID = c.Info.UserID
c.SendPack(t1.Pack(&rett))
return nil, -1
}
/**
* 接收战斗或者取消战斗的包
*/
// 接收战斗或者取消战斗的包
func (h Controller) OnPlayerHandleFightInvite(data *fight.HandleFightInviteInboundInfo, c *socket.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
return nil, -1
}
// 使用技能包
func (h Controller) UseSkill(data *fight.UseSkillInboundInfo, c *socket.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
return nil, 0
}
// 战斗逃跑
func (h Controller) Escape(data *fight.EscapeFightInboundInfo, c *socket.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
defer func() {
//战斗结束Escape
ttt := handler.NewTomeeHeader(2506, c.Info.UserID)
c.SendPack(ttt.Pack(&fight.FightOverInfo{
Reason: 0,
}))
c.IsFighting = false
}()
return nil, 0
}

13
logic/controller/item.go Normal file
View File

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

View File

@@ -41,8 +41,8 @@ func (h *Controller) Login(data *login.InInfo, c *socket.Conn) (result *login.Ou
if !IsToday(t.Info.LastResetTime) { //判断是否是今天
t.Info.LastResetTime = time.Now()
//每天login时候检查重置时间然后把电池任务挖矿重置
t.Info.TimeToday = 0 //重置电池
for i := 400; i < 500; i++ {//每日任务区段
t.Info.TimeToday = 0 //重置电池
for i := 400; i < 500; i++ { //每日任务区段
t.Info.TaskList[i] = 0 //重置每日任务
}
}
@@ -55,7 +55,7 @@ func (h *Controller) Login(data *login.InInfo, c *socket.Conn) (result *login.Ou
result.PlayerInfo = *t.Info
//result.TaskList = blservice.NewUserService(t.Info.UserID).GenTask()
result.PetList = blservice.NewUserService(t.Info.UserID).GetPetList(1)
//result.PetList = blservice.NewUserService(t.Info.UserID).GetPetList(1)
tt := maps.NewOutInfo()
//copier.Copy(t.Info, tt)

View File

@@ -4,8 +4,8 @@ import (
"blazing/common/data/socket"
"blazing/common/socket/errorcode"
"blazing/logic/service/pet"
"blazing/modules/blazing/model"
"blazing/modules/blazing/service"
blservice "blazing/modules/blazing/service"
)
// 获取精灵信息
@@ -20,6 +20,26 @@ func (h *Controller) GetPetInfo(
}, 0
}
// 获取仓库列表
func (h *Controller) GetPetList(
data *pet.GetPetListInboundEmpty,
c *socket.Player) (result *pet.GetPetListOutboundInfo,
err errorcode.ErrorCode) { //这个时候player应该是空的
result = &pet.GetPetListOutboundInfo{}
tt := blservice.NewUserService(c.Info.UserID).GetPetList(0) //获得未放生的精灵
result.ShortInfoList = make([]pet.PetShortInfo, len(tt))
for i, v := range tt {
result.ShortInfoList[i] = pet.PetShortInfo{
TypeId: v.ID,
CatchTime: v.CatchTime,
}
}
return
}
// 精灵背包仓库切换
func (h *Controller) PetRelease(
data *pet.PetReleaseInboundInfo,
@@ -29,7 +49,8 @@ func (h *Controller) PetRelease(
//放入背包=数据库置1+添加到背包+pet release发包 仓库=数据库置0+移除背包 设置首发等于取到首发精灵后重新排序
//这里只修改,因为添加和移除背包在宠物获取时已经做了
result = &pet.PetReleaseOutboundInfo{}
result.PetInfo = make([]model.PetInfo, 0)
result.Flag = uint32(data.Flag)
t := service.NewUserService(c.Info.UserID).PetM(int(data.CatchTime), int(data.Flag))
switch data.Flag {
case 0:
@@ -45,12 +66,14 @@ func (h *Controller) PetRelease(
if removeIndex != -1 {
c.Info.PetList = append(c.Info.PetList[:removeIndex], c.Info.PetList[removeIndex+1:]...)
}
result.FirstPetTime = c.Info.PetList[0].CatchTime //设置首发
if len(c.Info.PetList) > 0 {
result.FirstPetTime = c.Info.PetList[0].CatchTime //设置首发
}
case 1:
//todo 背包
PetAdd(c, t)
result.PetInfo = append(result.PetInfo, t)
c.Info.PetList = append(c.Info.PetList, t)
result.PetInfo = t
}
//service.NewUserService(c.Info.UserID).PetAdd( *r)

View File

@@ -3,8 +3,6 @@ package controller
import (
"blazing/common/data/socket"
"blazing/common/socket/errorcode"
"blazing/common/socket/handler"
"blazing/logic/service/pet"
"blazing/logic/service/task"
"blazing/modules/blazing/model"
"blazing/modules/blazing/service"
@@ -93,10 +91,10 @@ func (h Controller) Complete_Task(data *task.CompleteTaskInboundInfo, c *socket.
}
if data.TaskId == 86 { //新手注册任务
r := model.GenPetInfo(1, 1, 1, 1, 1, 5)
r := model.GenPetInfo(1, 1, 1, 1006, 1, 5)
result.CaptureTime = r.CatchTime
result.PetTypeId = r.ID
PetAdd(c, *r)
service.NewUserService(c.Info.UserID).PetAdd(*r)
}
if data.TaskId == 87 { //新手注册任务
@@ -137,14 +135,3 @@ func (h Controller) Delete_Task(data *task.DeleteTaskInboundInfo, c *socket.Play
return &task.DeleteTaskOutboundInfo{}, 0
}
// 添加精灵
func PetAdd(c *socket.Player, y model.PetInfo) {
c.Info.PetList = append(c.Info.PetList, y)
service.NewUserService(c.Info.UserID).PetAdd(y)
t := handler.NewTomeeHeader(2304, c.Info.UserID)
c.SendPack(t.Pack(&pet.PetReleaseOutboundInfo{PetInfo: []model.PetInfo{y}}))
//return lw.IsLogin
}

View File

@@ -38,12 +38,9 @@ type FightPetInfo struct {
UserID uint32 `fieldDesc:"用户ID 野怪为0" `
// 当前对战精灵ID@UInt long
PetID uint32 `fieldDesc:"当前对战精灵ID" `
// 空的16字节byte固定长度字符串
// 使用[16]byte匹配固定长度16字节的要求
PetName [16]byte `fieldDesc:"空的16字节byte" serialize:"fixedLength=16,type=byteArray"`
ID uint32 `fieldDesc:"当前对战精灵ID" `
Name string `struc:"[16]byte"`
// 精灵的捕获时间,@UInt long
CatchTime uint32 `fieldDesc:"精灵的捕获时间" `
@@ -66,18 +63,40 @@ type FightPetInfo struct {
// AttackValue 战斗中的攻击数值信息
type AttackValue struct {
UserID uint64 `json:"userId" fieldDescription:"玩家的米米号 与野怪对战userid = 0"`
SkillID uint64 `json:"skillId" fieldDescription:"使用技能的id"`
AttackTime uint64 `json:"attackTime" fieldDescription:"是否击中 如果为0 则miss 如果为1 则击中"`
LostHp uint64 `json:"lostHp" fieldDescription:"我方造成的伤害"`
GainHp uint64 `json:"gainHp" fieldDescription:"我方获得血量"`
RemainHp uint64 `json:"remainHp" fieldDescription:"我方剩余血量"`
MaxHp uint64 `json:"maxHp" fieldDescription:"我方最大血量"`
State uint64 `json:"state" fieldDescription:"固定值0 需要后续测试"`
UserID uint32 `json:"userId" fieldDescription:"玩家的米米号 与野怪对战userid = 0"`
SkillID uint32 `json:"skillId" fieldDescription:"使用技能的id"`
AttackTime uint32 `json:"attackTime" fieldDescription:"是否击中 如果为0 则miss 如果为1 则击中"`
LostHp uint32 `json:"lostHp" fieldDescription:"我方造成的伤害"`
GainHp uint32 `json:"gainHp" fieldDescription:"我方获得血量"`
RemainHp uint32 `json:"remainHp" fieldDescription:"我方剩余血量"`
MaxHp uint32 `json:"maxHp" fieldDescription:"我方最大血量"`
State uint32 `json:"state" fieldDescription:"固定值0 需要后续测试"`
SkillList []model.SkillInfo `json:"skillList" fieldDescription:"根据精灵的数据插入技能 最多4条 不定长"`
IsCritical uint64 `json:"isCritical" fieldDescription:"是否暴击"`
IsCritical uint32 `json:"isCritical" fieldDescription:"是否暴击"`
Status [20]byte `json:"status" fieldDescription:"20个字节 各种状态: 0:\"麻痹\",1:\"中毒\",2:\"烧伤\",4:\"寄生\",5:\"冻伤\",6:\"害怕\",7:\"疲惫\",8:\"睡眠\",9:\"石化\",10:\"混乱\",15:\"冰封\",16:\"流血\""`
BattleLv [6]byte `json:"battleLv" fieldDescription:"6个单字节byte, 内容为buff等级 攻击 速度 特攻 防御 特防命中等. 但具体顺序未知可能需要测试. 具体数值为1-6等级"`
// OwnerMaxShield uint64 `json:"ownerMaxShield" fieldDescription:"我方最大护盾"`
// OwnerCurrentShield uint64 `json:"ownerCurrentShield" fieldDescription:"我方当前护盾"`
// OwnerMaxShield uint32 `json:"ownerMaxShield" fieldDescription:"我方最大护盾"`
// OwnerCurrentShield uint32 `json:"ownerCurrentShield" fieldDescription:"我方当前护盾"`
}
// NoteUseSkillOutboundInfo 战斗技能使用通知的出站信息结构体
type NoteUseSkillOutboundInfo struct {
FirstAttackInfo AttackValue // 本轮先手的精灵在释放技能结束后的状态
SecondAttackInfo AttackValue // 本轮后手的精灵在释放技能结束后的状态
}
// 战斗逃跑
type EscapeFightInboundInfo struct {
Head handler.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 // 双倍学习器剩余次数
}

View File

@@ -10,7 +10,7 @@ type FightUserInfo struct {
// 玩家名称野怪为UTF-8的'-'固定16字节
// 使用[16]byte存储固定长度的字节数组
Nickname [16]byte ` `
Nick string `struc:"[16]byte"`
}
// NoteReadyToFightInfo 战斗准备就绪消息结构体NoteReadyToFightInfo

View File

@@ -17,3 +17,10 @@ type NoteHandleFightInviteOutboundInfo struct {
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
}

View File

@@ -0,0 +1,32 @@
package item
import "blazing/common/socket/handler"
// 实现了入站消息接口Go中通过方法集隐式实现
type ItemListInboundInfo struct {
Head handler.TomeeHeader `cmd:"2605" struc:"[0]pad"`
// 查询物品id的开始对应Java的@UInt long
Param1 uint32 `fieldDesc:"查询物品id的开始" messageType:"Item_List"`
// 查询物品id的结尾对应Java的@UInt long
Param2 uint32 `fieldDesc:"查询物品id的结尾"`
// 默认值2对应Java的@UInt long
Param3 uint32 `fieldDesc:"默认值2"`
}
type ItemListOutboundInfo struct {
// 物品列表,
ItemListLen uint32 `struc:"sizeof=ItemList"`
ItemList []SingleItemInfo `autoCodec:"true" messageType:"Item_List" fieldDesc:"物品列表"`
}
// SingleItemInfo 单个物品信息结构体对应Java的SingleItemInfo类
type SingleItemInfo struct {
// 物品Id
ItemId uint32
// 物品数量,
ItemCnt uint32
// 固定值360000
LeftTime uint32
// 固定值0
ItemLevel uint32
}

17
logic/service/pet/list.go Normal file
View File

@@ -0,0 +1,17 @@
package pet
import "blazing/common/socket/handler"
type GetPetListInboundEmpty struct {
Head handler.TomeeHeader `cmd:"2303" struc:"[0]pad"`
}
type GetPetListOutboundInfo struct {
ShortInfoListLen uint32 `struc:"int32,sizeof=ShortInfoList"`
ShortInfoList []PetShortInfo
}
// PetShortInfo 精灵简要信息结构体
type PetShortInfo struct {
TypeId uint32 // 精灵类型ID
CatchTime uint32 // 精灵生成时间
}

View File

@@ -17,9 +17,10 @@ type OutInfo struct {
// PetReleaseOutboundInfo 宠物释放出站消息
type PetReleaseOutboundInfo struct {
HomeEnergy uint32 `json:"home_energy" fieldDescription:"暂定0" autoCodec:"true" uint:"true"`
FirstPetTime uint32 `json:"first_pet_time" fieldDescription:"精灵生成时间" autoCodec:"true" uint:"true"`
PetInfo []model.PetInfo `json:"pet_info" fieldDescription:"精灵信息" autoCodec:"true"`
HomeEnergy uint32 `json:"home_energy" fieldDescription:"暂定0" autoCodec:"true" uint:"true"`
FirstPetTime uint32 `json:"first_pet_time" fieldDescription:"精灵生成时间" autoCodec:"true" uint:"true"`
Flag uint32
PetInfo model.PetInfo `json:"pet_info" fieldDescription:"精灵信息" autoCodec:"true"`
}
// 放入背包或者加入仓库

View File

@@ -32,13 +32,14 @@ type Pet struct {
func GenPetInfo(id, individual, natureId, abilityTypeEnum, shinyid, level uint32) *PetInfo {
p := &PetInfo{ID: id,
Shiny: shinyid, //闪光
Nature: natureId, //性格
Dv: individual,
AbilityType: abilityTypeEnum, //特性
CatchTime: uint32(time.Now().Unix()),
Level: level} //等级
Shiny: shinyid, //闪光
Nature: natureId, //性格
Dv: individual,
EffectInfo: make([]PetEffectInfo, 0),
CatchTime: uint32(time.Now().Unix()),
Level: level} //等级
p.EffectInfo = append(p.EffectInfo, PetEffectInfo{ItemID: abilityTypeEnum})
petxml := xmlres.PetMAP[int(id)]
naxml := xmlres.NatureRootMap[int(natureId)]
tttt := make([]uint32, 0)
@@ -64,7 +65,7 @@ func GenPetInfo(id, individual, natureId, abilityTypeEnum, shinyid, level uint32
)
attack := p.CalculatePetPanelSize(
p.Attack,
uint32(petxml.Atk),
p.Dv,
p.Level,
p.EvAttack,
@@ -72,7 +73,7 @@ func GenPetInfo(id, individual, natureId, abilityTypeEnum, shinyid, level uint32
)
defense := p.CalculatePetPanelSize(
p.Defence,
uint32(petxml.Def),
p.Dv,
p.Level,
p.EvDefence,
@@ -80,7 +81,7 @@ func GenPetInfo(id, individual, natureId, abilityTypeEnum, shinyid, level uint32
)
specialAttack := p.CalculatePetPanelSize(
p.SpecialAttack,
uint32(petxml.SpAtk),
p.Dv,
p.Level,
p.EvSpecialAttack,
@@ -88,7 +89,7 @@ func GenPetInfo(id, individual, natureId, abilityTypeEnum, shinyid, level uint32
)
specialDefense := p.CalculatePetPanelSize(
p.SpecialDefence,
uint32(petxml.SpDef),
p.Dv,
p.Level,
p.EvSpecialDefense,
@@ -96,7 +97,7 @@ func GenPetInfo(id, individual, natureId, abilityTypeEnum, shinyid, level uint32
)
speed := p.CalculatePetPanelSize(
p.Speed,
uint32(petxml.Spd),
p.Dv,
p.Level,
p.EvSpeed,
@@ -116,17 +117,15 @@ func GenPetInfo(id, individual, natureId, abilityTypeEnum, shinyid, level uint32
// 计算HP面板值无性格修正
func (c *PetInfo) CalculatePetHPPanelSize(base, dv, level, ev uint32) uint32 {
// 实现具体计算逻辑,示例公式:(基础值 + 个体值) * 等级 / 100 + 等级 + 10 + 努力值/4
baseValue := (base*2 + ev/4 + 100 + dv) * (level/100 + 10)
return uint32(baseValue)
return uint32((float64(base)*2+float64(ev)/4.0+float64(dv))*(float64(level)/100.0) + float64(level) + 10)
}
// 计算其他属性面板值(带性格修正)
func (c *PetInfo) CalculatePetPanelSize(base, dv, level, ev uint32, natureCorrect float64) uint32 {
// 实现具体计算逻辑,示例公式:((基础值 + 个体值) * 等级 / 100 + 5 + 努力值/4) * 性格修正
baseValue := (base*2 + ev/4 + dv) * (level/100 + 5)
return uint32(float64(baseValue) * natureCorrect)
base1 := float64((float64(base)*2+float64(ev)/4.0+float64(dv))*(float64(level)/100.0) + 5)
return uint32(float64(base1) * natureCorrect)
}
// PetInfo 精灵信息结构(合并后的优化版本)
@@ -217,8 +216,8 @@ type PetInfo struct {
SkinID uint32 `fieldDesc:"皮肤id默认为0" `
// 是否闪光(@UInt long → uint320=否1=是)
Shiny uint32 `fieldDesc:"是不是闪" `
AbilityType uint32 `struc:"skip"` //特性
Shiny uint32 `fieldDesc:"是不是闪" `
// AbilityType uint32 `struc:"skip"` //特性
}
// PetEffectInfo 精灵特性信息结构

View File

@@ -6,7 +6,7 @@ import (
"encoding/json"
)
// 获取精灵信息 0是仓库,1是背包
// 获取精灵信息 0是仓库,1是背包,2是放生
func (s *UserService) GetPetList(flag int) (ret []model.PetInfo) {
ret = make([]model.PetInfo, 0)
m := cool.DBM(s.pet.Model).Where("player_id", s.userid).Where("in_bag", flag)
@@ -53,7 +53,7 @@ func (s *UserService) PetAdd(y model.PetInfo) {
var player model.Pet
player.PlayerID = s.userid
player.CatchTime = y.CatchTime
player.InBag = 1
player.InBag = 0
tmp, _ := json.Marshal(y)
player.Data = string(tmp)
m1.Insert(player)
@@ -63,10 +63,13 @@ func (s *UserService) PetM(ctime, type1 int) model.PetInfo {
m1 := cool.DBM(s.pet.Model).Where("player_id", s.userid).Where("catch_time", ctime)
var player model.Pet
m1.Scan(&player)
player.InBag = type1
m1.Update(player)
var tt model.PetInfo
json.Unmarshal([]byte(player.Data), &tt)
m1.Update(player)
return tt
}