From fe89620efbf93b147269584b18a81e8ee17dea17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=98=94=E5=BF=B5?= <1@72wo.cn> Date: Sat, 13 Dec 2025 21:47:07 +0800 Subject: [PATCH] =?UTF-8?q?```=20feat(item):=20=E5=87=BA=E5=94=AE=E7=89=A9?= =?UTF-8?q?=E5=93=81=E5=90=8E=E5=87=8F=E5=B0=91=E8=83=8C=E5=8C=85=E4=B8=AD?= =?UTF-8?q?=E5=AF=B9=E5=BA=94=E7=89=A9=E5=93=81=E6=95=B0=E9=87=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 在处理物品出售逻辑时,增加调用 SubItem 方法以正确扣减玩家背包中的物品数量。 feat(map): 玩家离开地图时重置 Canmon 标志位 通过 atomic.StoreUint32 将玩家的 Canmon 状态设置为 0,确保线程安全。 fix(pet): 调整宠物经验增加逻辑并修复技能学习问题 重构 AddPetExp 方法逻辑,优化升级流程、技能学习机制,并修正经验显示 --- logic/controller/fight_tawor.go | 30 +++++++++++++++++++++++ logic/controller/item_sale.go | 1 + logic/controller/map.go | 2 +- logic/controller/pet_info.go | 2 +- logic/service/fight/cmd.go | 20 ++++++++++++++++ logic/service/item/petuse.go | 2 +- logic/service/player/pet.go | 41 ++++++++++++++++---------------- modules/blazing/model/pet.go | 27 +++++++-------------- modules/blazing/model/petinfo.go | 12 ++++++++-- modules/blazing/model/player.go | 2 +- modules/blazing/service/info.go | 2 ++ 11 files changed, 96 insertions(+), 45 deletions(-) create mode 100644 logic/controller/fight_tawor.go diff --git a/logic/controller/fight_tawor.go b/logic/controller/fight_tawor.go new file mode 100644 index 000000000..15be8e248 --- /dev/null +++ b/logic/controller/fight_tawor.go @@ -0,0 +1,30 @@ +package controller + +import ( + "blazing/common/socket/errorcode" + "blazing/common/utils" + "blazing/logic/service/fight" + "blazing/logic/service/player" + "sync/atomic" +) + +func (h Controller) FRESH_CHOICE_FIGHT_LEVEL(data *fight.C2S_FRESH_CHOICE_FIGHT_LEVEL, c *player.Player) (result *fight.S2C_FreshChoiceLevelRequestInfo, err errorcode.ErrorCode) { + + result = &fight.S2C_FreshChoiceLevelRequestInfo{} + + switch data.Head.CMD { + case 2428: //试炼之塔 + c.Info.CurrentFreshStage = utils.Max(c.Info.CurrentFreshStage, 1) + result.CurFightLevel = uint(c.Info.CurrentFreshStage) + case 2414: //勇者之塔 + c.Info.CurrentStage = utils.Max(c.Info.CurrentStage, 1) + result.CurFightLevel = uint(c.Info.CurrentStage) + } + result.BossId = []uint32{10} + atomic.StoreUint32(&c.Canmon, 0) + return result, 0 +} +func (h Controller) FRESH_LEAVE_FIGHT_LEVEL(data *fight.FRESH_LEAVE_FIGHT_LEVEL, c *player.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) { + + return result, 0 +} diff --git a/logic/controller/item_sale.go b/logic/controller/item_sale.go index 205d96991..8752f6ab4 100644 --- a/logic/controller/item_sale.go +++ b/logic/controller/item_sale.go @@ -17,5 +17,6 @@ func (h Controller) ITEM_SALE(data *item.C2S_ITEM_SALE, c *player.Player) (resul c.Info.Coins += uint32(int64(data.Amount) * int64(xmlres.ItemsMAP[int(data.ItemId)].SellPrice)) } + c.Service.Item.SubItem(data.ItemId, data.Amount) return result, 0 } diff --git a/logic/controller/map.go b/logic/controller/map.go index f7cbb4869..1f0103096 100644 --- a/logic/controller/map.go +++ b/logic/controller/map.go @@ -37,7 +37,7 @@ func (h Controller) MapHot(data *maphot.InInfo, c *player.Player) (result *mapho return } func (h *Controller) MapLeave(data *space.LeaveMapInboundInfo, c *player.Player) (result *info.LeaveMapOutboundInfo, err errorcode.ErrorCode) { //这个时候player应该是空的 - + atomic.StoreUint32(&c.Canmon, 0) //data.Broadcast(c.Info.MapID, info.LeaveMapOutboundInfo{UserID: c.Info.UserID}) //同步广播 result = &info.LeaveMapOutboundInfo{ UserID: c.Info.UserID, diff --git a/logic/controller/pet_info.go b/logic/controller/pet_info.go index e7a2c472c..8f4e07c68 100644 --- a/logic/controller/pet_info.go +++ b/logic/controller/pet_info.go @@ -229,7 +229,7 @@ func (h Controller) SetPetExp(data *pet.PetSetExpInboundInfo, c *player.Player) _, onpet, ok := c.FindPet(data.CatchTime) if ok && onpet.Level < 100 { - defer c.AddPetExp(onpet, data.Exp) + c.AddPetExp(onpet, data.Exp) return &pet.PetSetExpOutboundInfo{ Exp: c.Info.ExpPool, }, 0 diff --git a/logic/service/fight/cmd.go b/logic/service/fight/cmd.go index c66e59414..7aa6a3f92 100644 --- a/logic/service/fight/cmd.go +++ b/logic/service/fight/cmd.go @@ -124,3 +124,23 @@ type ChatInfo struct { MessageLen uint32 `struc:"sizeof=Message"` Message string `json:"message" fieldDescription:"消息内容, 结束符为utf-8的数字0"` // 消息内容,包含utf-8空字符('\x00')作为结束符 } +type C2S_FRESH_CHOICE_FIGHT_LEVEL struct { + Head common.TomeeHeader `cmd:"2428|2414" struc:"skip"` + // Level 挑战层数选择标识 + // 0: 继续挑战(从数据库存储的当前通关层数开始) + // 1: 从1层开始 + // 2: 从11层开始 + // 3: 从21层开始 + // 4: 从31层开始 + Level uint `json:"level"` // 若使用JSON序列化,添加tag;若用protobuf可替换为对应的tag +} +type S2C_FreshChoiceLevelRequestInfo struct { + // CurFightLevel 当前战斗层数(对应前端 curFightLevel 字段) + CurFightLevel uint `json:"curFightLevel"` // JSON序列化tag,保证字段名与前端一致 + BossIdLen uint32 `struc:"sizeof=BossId"` + // BossId 当前层数的精灵ID数组(对应前端 bossId 字段,C# List 对应Go []uint切片) + BossId []uint32 `json:"bossId"` +} +type FRESH_LEAVE_FIGHT_LEVEL struct { + Head common.TomeeHeader `cmd:"2430|2416" struc:"skip"` +} diff --git a/logic/service/item/petuse.go b/logic/service/item/petuse.go index 780df970c..8d795f220 100644 --- a/logic/service/item/petuse.go +++ b/logic/service/item/petuse.go @@ -164,7 +164,7 @@ func init() { onpet.Downgrade(1) onpet.NextLvExp = 0 - onpet.Update_EXP() + onpet.Update(false) onpet.Ev = [6]uint32{} onpet.Dv = uint32(grand.Intn(32)) onpet.Nature = (onpet.Nature + uint32(grand.Intn(25))) % 25 diff --git a/logic/service/player/pet.go b/logic/service/player/pet.go index f68d1bf70..1b14d2ee7 100644 --- a/logic/service/player/pet.go +++ b/logic/service/player/pet.go @@ -18,23 +18,22 @@ func (p *Player) AddPetExp(petinfo *model.PetInfo, addExp uint32) { addExp = utils.Min(addExp, p.Info.ExpPool) originalLevel := petinfo.Level Exp := petinfo.Exp + addExp - - petinfo.Update_EXP() - petinfo.Update() p.Info.ExpPool -= addExp //减去已使用的经验 + gainexp := Exp //已获得的经验 for Exp >= petinfo.NextLvExp { + petinfo.Level++ - petinfo.Update_EXP() - petinfo.Update() + petinfo.Update(true) Exp -= petinfo.LvExp + if originalLevel < 100 && petinfo.Level == 100 { //升到100了 p.Info.ExpPool += Exp //减去已使用的经验 + gainexp -= Exp Exp = 0 break //停止升级 } } - petinfo.Exp = Exp // 重新计算面板 if originalLevel != petinfo.Level { @@ -42,27 +41,26 @@ func (p *Player) AddPetExp(petinfo *model.PetInfo, addExp uint32) { petinfo.Cure() p.Info.PetMaxLevel = utils.Max(petinfo.Level, p.Info.PetMaxLevel) - } + // 处理技能学习 + canLearnSkillList := utils.LastFourElements(petinfo.GetLevelRangeCanLearningSkills(originalLevel, petinfo.Level), 4) //获取最后四个技能,如果不足,那就取全部技能 - // 处理技能学习 - canLearnSkillList := utils.LastFourElements(petinfo.GetLevelRangeCanLearningSkills(originalLevel, petinfo.Level), 4) //获取最后四个技能,如果不足,那就取全部技能 + for i := 0; i < 4; i++ { - for i := 0; i < 4; i++ { + if len(canLearnSkillList) != 0 { + skid := canLearnSkillList[len(canLearnSkillList)-1] + petinfo.SkillList = append(petinfo.SkillList, model.SkillInfo{ - if len(canLearnSkillList) != 0 { - skid := canLearnSkillList[len(canLearnSkillList)-1] - petinfo.SkillList = append(petinfo.SkillList, model.SkillInfo{ + ID: skid, + PP: uint32(xmlres.SkillMap[int(skid)].MaxPP), + }) - ID: skid, - PP: uint32(xmlres.SkillMap[int(skid)].MaxPP), - }) + canLearnSkillList = canLearnSkillList[:len(canLearnSkillList)-1] + } - canLearnSkillList = canLearnSkillList[:len(canLearnSkillList)-1] } - - } - if len(petinfo.SkillList) > 4 { - petinfo.SkillList = petinfo.SkillList[:4] //归正到4 + if len(petinfo.SkillList) > 4 { + petinfo.SkillList = petinfo.SkillList[:4] //归正到4 + } } t1 := common.NewTomeeHeader(2508, p.Info.UserID) @@ -71,6 +69,7 @@ func (p *Player) AddPetExp(petinfo *model.PetInfo, addExp uint32) { var petinfwo info.UpdatePropInfo copier.Copy(&petinfwo, petinfo) + petinfwo.Exp = gainexp rrr.Data = append(rrr.Data, petinfwo) p.SendPack(t1.Pack(rrr)) //准备包由各自发,因为协议不一样 // 发送经验更新消息 diff --git a/modules/blazing/model/pet.go b/modules/blazing/model/pet.go index 14c3bd652..dd56dfb75 100644 --- a/modules/blazing/model/pet.go +++ b/modules/blazing/model/pet.go @@ -270,8 +270,8 @@ func (pet *PetInfo) Downgrade(level uint32) { } -// 执行进化逻辑 -func (petinfo *PetInfo) Update() { +// 执行进化逻辑 ,是否进化 +func (petinfo *PetInfo) Update(isup bool) { // 最大进化次数限制(防止配置表闭环导致死循环) maxEvolveTimes := 10 @@ -283,14 +283,18 @@ func (petinfo *PetInfo) Update() { if evolveCount >= maxEvolveTimes { break } - + // 进化完成后,统一更新经验(原逻辑保留) + petinfo.LvExp = petinfo.NextLvExp // 获取当前宠物形态的配置 basic, ok := xmlres.PetMAP[int(petinfo.ID)] // 配置不存在,直接退出循环 if !ok { break } - + petinfo.NextLvExp = calculateExperience(petinfo.Level, basic.GetBasic()) + if !isup { + return + } // 检查是否满足进化条件 canEvolve := basic.EvolvesTo != 0 && // 有明确的进化目标 int(petinfo.Level) >= basic.EvolvingLv && // 等级达到进化要求 @@ -308,19 +312,6 @@ func (petinfo *PetInfo) Update() { } -// 传入bool则不升级 -// Update 改造为循环进化:直到宠物无法再进化为止,再更新经验 -// t ...bool:原参数逻辑,len(t)==0时触发进化检查,否则仅更新经验 - -func (petinfo *PetInfo) Update_EXP() { - - // 进化完成后,统一更新经验(原逻辑保留) - petinfo.LvExp = petinfo.NextLvExp - // 获取最终形态的宠物配置,计算下一等级经验 - basic := xmlres.PetMAP[int(petinfo.ID)] - petinfo.NextLvExp = calculateExperience(petinfo.Level, basic.GetBasic()) -} - // calculateExperience 计算指定等级和种族值所需的经验值 // level: 当前等级 // baseValue: 种族值 @@ -485,7 +476,7 @@ func GenPetInfo( // ---- 属性计算 ---- p.CalculatePetPane(true) - p.Update_EXP() + p.Update(false) return p } diff --git a/modules/blazing/model/petinfo.go b/modules/blazing/model/petinfo.go index 13eec66ae..1e1d012a6 100644 --- a/modules/blazing/model/petinfo.go +++ b/modules/blazing/model/petinfo.go @@ -2,7 +2,6 @@ package model import ( "blazing/common/data/xmlres" - "blazing/common/utils" ) // 实现获取等级范围内可学习的技能 @@ -35,7 +34,16 @@ func (c *PetInfo) calculatePetPanelSize(base, ev uint32, natureCorrect float64) // 计算生成面板,只允许第一次生成超过100,比如boss,不允许额外超过 func (p *PetInfo) CalculatePetPane(frist bool) { if !frist { - p.Level = utils.Min(p.Level, 100) + + if p.Level > 100 { + + oldlveel := p.Level + p.Level = 100 + defer func() { + p.Level = oldlveel + }() + } + } naxml := xmlres.NatureRootMap[int(p.Nature)] petxml := xmlres.PetMAP[int(p.ID)] diff --git a/modules/blazing/model/player.go b/modules/blazing/model/player.go index bd06df29f..3e6130f67 100644 --- a/modules/blazing/model/player.go +++ b/modules/blazing/model/player.go @@ -158,7 +158,7 @@ type PlayerInfo struct { 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" json:"current_stage"` // 勇者之塔层数 + CurrentStage uint32 `struc:"uint32" default:"1" json:"current_stage"` // 勇者之塔层数 MaxStage uint32 `struc:"uint32" json:"max_stage"` // 试炼之塔最高层 CurrentFreshStage uint32 `struc:"uint32" json:"current_fresh_stage"` // 当前试炼层数 MaxFreshStage uint32 `struc:"uint32" json:"max_fresh_stage"` // 最高试炼层 diff --git a/modules/blazing/service/info.go b/modules/blazing/service/info.go index ef5f1477d..24f94664f 100644 --- a/modules/blazing/service/info.go +++ b/modules/blazing/service/info.go @@ -151,6 +151,8 @@ func NewInfoService(id uint32) *InfoService { Service: &cool.Service{Model: model.NewPlayer(), UniqueKey: map[string]string{ "player_id": "角色名称不能重复", + }, PageQueryOp: &cool.QueryOp{ + FieldEQ: []string{"player_id"}, }}, }, }