From f76587f952d8dc92051e123402f5f15cf8ac32f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=98=94=E5=BF=B5?= <1@72wo.cn> Date: Wed, 26 Nov 2025 01:33:48 +0800 Subject: [PATCH] =?UTF-8?q?feat(pet):=20=E5=AE=9E=E7=8E=B0=E7=B2=BE?= =?UTF-8?q?=E7=81=B5=E8=9E=8D=E5=90=88=E5=8A=9F=E8=83=BD=E5=B9=B6=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E7=9B=B8=E5=85=B3=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增精灵融合接口及处理逻辑,支持主副精灵融合生成新精灵,并消耗金币与材料。 同时调整了战斗技能选择流程、修复地图热度统计安全问题以及完善宠物删除机制。 - 添加 `PetFusion` 控制器方法实现融合核心逻辑 - 新增 `C2S_PetFusion` 和 `PetFusionInfo` 结构体用于通信 - 修正战斗中技能随机选取后立即返回的问题 - 修复太空站进入/离开时对地图热度的并发访问风险 - --- logic/controller/PET_FUSION.go | 46 ++++++++++++++++++++++++++++++ logic/controller/pet.go | 3 -- logic/controller/pet_COLLECT.go | 17 +++++++++++ logic/service/fight/input/fight.go | 2 ++ logic/service/fight/loop.go | 8 +++--- logic/service/pet/list.go | 21 ++++++++++++++ logic/service/pet/pet.go | 16 +++++++++++ logic/service/player/base.go | 9 ++++++ logic/service/space/in_out.go | 12 +++++--- logic/service/space/space.go | 10 +++---- modules/blazing/model/pet_ru.go | 45 +++++++++++++++++++++++++++++ modules/blazing/service/pet.go | 7 ++++- modules/blazing/service/re.go | 18 ++++++++++++ public/config/地图配置野怪.xml | 2 +- 14 files changed, 198 insertions(+), 18 deletions(-) create mode 100644 logic/controller/pet_COLLECT.go create mode 100644 modules/blazing/model/pet_ru.go create mode 100644 modules/blazing/service/re.go diff --git a/logic/controller/PET_FUSION.go b/logic/controller/PET_FUSION.go index b0b429f89..3473a8eda 100644 --- a/logic/controller/PET_FUSION.go +++ b/logic/controller/PET_FUSION.go @@ -1 +1,47 @@ package controller + +import ( + "blazing/common/data/xmlres" + "blazing/common/socket/errorcode" + "blazing/logic/service/pet" + "blazing/logic/service/player" + "blazing/modules/blazing/model" +) + +func (h Controller) PetFusion(data *pet.C2S_PetFusion, c *player.Player) (result *pet.PetFusionInfo, err errorcode.ErrorCode) { + if !c.UseCoins(1000) { + return result, errorcode.ErrorCodes.ErrSystemBusy + } + + //防止同一只 + if data.Mcatchtime == data.Auxcatchtime { + return result, errorcode.ErrorCodes.ErrSystemBusy + } + + _, Mcatchpetinfo, ok := c.FindPet(data.Mcatchtime) + if !ok { + return result, errorcode.ErrorCodes.ErrSystemBusy + } + + if xmlres.PetMAP[int(Mcatchpetinfo.ID)].FuseMaster == 0 { + return result, errorcode.ErrorCodes.ErrSystemBusy + } + _, Auxpetinfo, ok := c.FindPet(data.Auxcatchtime) + if !ok { + return result, errorcode.ErrorCodes.ErrSystemBusy + } + + if xmlres.PetMAP[int(Auxpetinfo.ID)].FuseSub == 0 { + return result, errorcode.ErrorCodes.ErrSystemBusy + } + r := model.GenPetInfo(1, -1, -1, -1, -1, 1) + c.Service.Pet.PetAdd(*r) + c.Pet_del(Auxpetinfo.CatchTime) + c.Pet_del(Mcatchpetinfo.CatchTime) + return &pet.PetFusionInfo{ + ObtainTime: r.CatchTime, + SoulID: 1000017, + StarterCpTm: r.ID, + CostItemFlag: 0, + }, 0 +} diff --git a/logic/controller/pet.go b/logic/controller/pet.go index cb4603f42..092224893 100644 --- a/logic/controller/pet.go +++ b/logic/controller/pet.go @@ -186,9 +186,6 @@ func (h *Controller) PetOneCure( return result, errorcode.ErrorCodes.ErrChampionCannotHeal } - if !c.UseCoins(20) { - return result, errorcode.ErrorCodes.ErrSystemBusy - } _, onpet, ok := c.FindPet(data.CatchTime) if ok { onpet.Cure() diff --git a/logic/controller/pet_COLLECT.go b/logic/controller/pet_COLLECT.go new file mode 100644 index 000000000..3579d8864 --- /dev/null +++ b/logic/controller/pet_COLLECT.go @@ -0,0 +1,17 @@ +package controller + +import ( + "blazing/common/socket/errorcode" + "blazing/logic/service/pet" + "blazing/logic/service/player" +) + +func (h *Controller) IS_COLLECT( + data *pet.C2S_IS_COLLECT, c *player.Player) (result *pet.S2C_IS_COLLECT, err errorcode.ErrorCode) { //这个时候player应该是空的 + result = &pet.S2C_IS_COLLECT{ + ID: data.Type, + IsCom: 0, + } + return result, 0 + +} diff --git a/logic/service/fight/input/fight.go b/logic/service/fight/input/fight.go index 480952385..72f9d8ca4 100644 --- a/logic/service/fight/input/fight.go +++ b/logic/service/fight/input/fight.go @@ -267,6 +267,8 @@ func (our *Input) GetAction(opp *Input) { for i := 0; i < len(allSkills); i++ { if randomIdx == int(i) { our.FightC.UseSkill(our.Player, uint32(allSkills[i].ID)) + + return } } diff --git a/logic/service/fight/loop.go b/logic/service/fight/loop.go index 0aeb6093f..5fee130a3 100644 --- a/logic/service/fight/loop.go +++ b/logic/service/fight/loop.go @@ -188,11 +188,11 @@ func (f *FightC) resolveRound(p1Action, p2Action action.BattleActionI) { f.GetInputByAction(a, false).CurrentPet.Info.Hp = 1 } if b2k, ok := b2.(*action.SelectSkillAction); ok { - - if b2k.CD != nil { - f.waittime = *b2k.CD + if b2k.SkillEntity != nil { + if b2k.CD != nil { + f.waittime = *b2k.CD + } } - f.enterturn(b2.(*action.SelectSkillAction), nil) } else { diff --git a/logic/service/pet/list.go b/logic/service/pet/list.go index a36b45c2d..ac6d75a52 100644 --- a/logic/service/pet/list.go +++ b/logic/service/pet/list.go @@ -21,3 +21,24 @@ type PetShortInfo struct { SkinID uint32 // 精灵皮肤ID Shiny uint32 // 精灵是否闪光(0=否,1=是) } + +// C2S_PetFusion 前端(Client)到后端(Server)的精灵融合请求包 +type C2S_PetFusion struct { + Head common.TomeeHeader `cmd:"2351" struc:"skip"` + Mcatchtime uint32 `json:"mcatchtime" msgpack:"mcatchtime"` // 主精灵的时间戳 + Auxcatchtime uint32 `json:"auxcatchtime" msgpack:"auxcatchtime"` // 副精灵的时间戳 + Item1 uint32 `json:"item1" msgpack:"item1"` // 物品序号1 + Item2 uint32 `json:"item2" msgpack:"item2"` // 物品序号2 + Item3 uint32 `json:"item3" msgpack:"item3"` // 物品序号3 + Item4 uint32 `json:"item4" msgpack:"item4"` // 物品序号4 + GoldItem1 uint32 `json:"gold_item1" msgpack:"gold_item1"` // 0代表未放置 金豆物品1(C#:gold_item1) + GoldItem2 uint32 `json:"gold_item2" msgpack:"gold_item2"` // 0代表未放置 金豆物品2(C#:gold_item2) +} + +// PetFusionInfo 精灵融合结果详情(后端回包嵌套结构体) +type PetFusionInfo struct { + ObtainTime uint32 `json:"obtainTime" msgpack:"obtainTime"` // 如果获得时间为0 则代表融合失败 + SoulID uint32 `json:"soulID" msgpack:"soulID"` // 元神珠的id 融合失败为0 + StarterCpTm uint32 `json:"starterCpTm" msgpack:"starterCpTm"` // 融合失败为0 + CostItemFlag uint32 `json:"costItemFlag" msgpack:"costItemFlag"` // 是不是消耗掉了金豆道具 1代表消耗道具 +} diff --git a/logic/service/pet/pet.go b/logic/service/pet/pet.go index 7c361be96..2d54765c2 100644 --- a/logic/service/pet/pet.go +++ b/logic/service/pet/pet.go @@ -78,3 +78,19 @@ type PetDefaultInboundInfo struct { type PetDefaultOutboundInfo struct { IsDefault uint32 `json:"isDefault" fieldDescription:"0: 首发设置失败,1: 首发设置成功" uint:"true" autoCodec:"true" outboundMessageType:"Pet_Default"` } + +// C2S_IS_COLLECT 前端(Client)→后端(Server):精灵收集任务状态查询请求包 +type C2S_IS_COLLECT struct { + Head common.TomeeHeader `cmd:"2313" struc:"skip"` + Type uint32 `json:"type" msgpack:"type"` // 收集类型:301=太空站10胜;1=精灵收集计划一期第一种;2=精灵收集计划一期第二种 +} + +// S2C_IS_COLLECT 后端(Server)→前端(Client):精灵收集任务状态查询回包 +// 补充说明: +// 1. 此包同时适用于「精灵收集计划」和「太空站10胜送主宠」场景 +// 2. isCom=0(未领取)时,才可调用 PRIZE_OF_PETKING(2317) 协议领取精灵 +// 3. isCom=1(已完成/已领取)时,代表奖励已领取,无需再调用领取协议 +type S2C_IS_COLLECT struct { + ID uint32 `json:"id" msgpack:"id"` // 收集类型:301=太空站10胜;1=精灵收集计划一期第一种;2=精灵收集计划一期第二种 + IsCom uint32 `json:"isCom" msgpack:"isCom"` // 是否完成/是否已领取:0=未完成/未领取;1=已完成/已领取 +} diff --git a/logic/service/player/base.go b/logic/service/player/base.go index a1246f317..f34711293 100644 --- a/logic/service/player/base.go +++ b/logic/service/player/base.go @@ -50,6 +50,15 @@ func (f *baseplayer) FindPet(CatchTime uint32) (int, *model.PetInfo, bool) { return item.CatchTime == CatchTime }) } +func (f *Player) Pet_del(CatchTime uint32) { + + index, _, ok := f.FindPet(CatchTime) + if ok { + f.Info.PetList = append(f.Info.PetList[:index], f.Info.PetList[index+1:]...) + } + + f.Service.Pet.Pet_del(CatchTime) +} // // 计算整数的二进制1的个数(Integer.bitCount) // func bitsCount(n int) int { diff --git a/logic/service/space/in_out.go b/logic/service/space/in_out.go index f365aa414..59adaa9ce 100644 --- a/logic/service/space/in_out.go +++ b/logic/service/space/in_out.go @@ -46,8 +46,10 @@ func (s *Space) LeaveMap(c common.PlayerI) { s.User.Delete(c.GetInfo().UserID) s.UserInfo.Delete(c.GetInfo().UserID) - - atomic.AddInt32(maphot[s.Super], -1) + _, ok := maphot[s.Super] + if ok { + atomic.AddInt32(maphot[s.Super], -1) + } } @@ -59,8 +61,10 @@ func (s *Space) EnterMap(c common.PlayerI) { s.User.Store(c.GetInfo().UserID, c) s.UserInfo.Store(c.GetInfo().UserID, *out) s.Broadcast(c, 2001, out) - - atomic.AddInt32(maphot[s.Super], 1) + _, ok := maphot[s.Super] + if ok { + atomic.AddInt32(maphot[s.Super], 1) + } } func (s *Space) GetInfo() []maps.OutInfo { diff --git a/logic/service/space/space.go b/logic/service/space/space.go index fe761e942..17e3d9c42 100644 --- a/logic/service/space/space.go +++ b/logic/service/space/space.go @@ -74,11 +74,11 @@ func GetSpace(id uint32) *Space { for _, v := range xmlres.MapConfig.Maps { if v.ID == int(id) { //找到这个地图 - // t.Super = uint32(v.Super) - // if t.Super == 0 { - // t.Super = uint32(v.ID) - // } - t.Super = uint32(v.ID) + t.Super = uint32(v.Super) + if t.Super == 0 { + t.Super = uint32(v.ID) + } + _, ok := maphot[t.Super] if !ok { var t1 int32 diff --git a/modules/blazing/model/pet_ru.go b/modules/blazing/model/pet_ru.go new file mode 100644 index 000000000..880d4710b --- /dev/null +++ b/modules/blazing/model/pet_ru.go @@ -0,0 +1,45 @@ +package model + +import ( + "blazing/cool" +) + +const ( + TableNamePetFusionConfig = "pet_fusion_config" // 宠物融合配置表(尼尔/闪皮融合规则) +) + +// PetFusionConfig 宠物融合配置模型(对应尼尔/闪皮融合卡鲁/闪尼的规则) +type PetFusionConfig struct { + *cool.Model + + MainPetID int32 `gorm:"not null;comment:'主精灵ID(尼尔)'" json:"main_pet_id"` + AuxPetID int32 `gorm:"not null;comment:'副精灵ID(闪皮)'" json:"aux_pet_id"` + FusionMaterial1 int32 `gorm:"not null;default:0;comment:'融合材料1编号'" json:"fusion_material1"` + FusionMaterial2 int32 `gorm:"not null;default:0;comment:'融合材料2编号'" json:"fusion_material2"` + FusionMaterial3 int32 `gorm:"not null;default:0;comment:'融合材料3编号'" json:"fusion_material3"` + FusionMaterial4 int32 `gorm:"not null;default:0;comment:'融合材料4编号'" json:"fusion_material4"` + FusionProbability float64 `gorm:"not null;comment:'融合成功概率(百分比,0-100)'" json:"fusion_probability"` + ResultPetID int32 `gorm:"not null;comment:'融合结果精灵ID(卡鲁/闪尼)'" json:"result_pet_id"` +} + +// TableName PetFusionConfig's table name +func (*PetFusionConfig) TableName() string { + return TableNamePetFusionConfig +} + +// GroupName PetFusionConfig's table group +func (*PetFusionConfig) GroupName() string { + return "default" // 与原模型保持一致的分组名 +} + +// NewPetFusionConfig create a new PetFusionConfig +func NewPetFusionConfig() *PetFusionConfig { + return &PetFusionConfig{ + Model: cool.NewModel(), + } +} + +// 初始化表结构(与原模型保持一致的初始化方式) +func init() { + cool.CreateTable(&PetFusionConfig{}) +} diff --git a/modules/blazing/service/pet.go b/modules/blazing/service/pet.go index d95531a50..d5d0668e3 100644 --- a/modules/blazing/service/pet.go +++ b/modules/blazing/service/pet.go @@ -36,7 +36,7 @@ func (s *PetService) PetInfo_One_exec(cachetime uint32, t func(*model.PetEX)) { } tt.Data.CatchTime = tt.CatchTime t(&tt) - _,err := m.OnConflict("catch_time").Update(tt) + _, err := m.OnConflict("catch_time").Update(tt) if err != nil { panic(err) } @@ -50,6 +50,11 @@ func (s *PetService) PetInfo_One(cachetime uint32) model.PetEX { tt.Data.CatchTime = tt.CatchTime return tt } +func (s *PetService) Pet_del(cachetime uint32) { + + cool.DBM(s.Model).Where("player_id", s.userid).Where("catch_time", cachetime).Delete() + +} func (s *PetService) PetAdd(y model.PetInfo) { for { diff --git a/modules/blazing/service/re.go b/modules/blazing/service/re.go new file mode 100644 index 000000000..596e848d3 --- /dev/null +++ b/modules/blazing/service/re.go @@ -0,0 +1,18 @@ +package service + +import ( + "blazing/cool" + "blazing/modules/blazing/model" +) + +type FusionService struct { + *cool.Service +} + +func NewFusionService() *FusionService { + return &FusionService{ + &cool.Service{ + Model: model.NewPetFusionConfig(), + }, + } +} diff --git a/public/config/地图配置野怪.xml b/public/config/地图配置野怪.xml index 6a3ca148d..82b60f977 100644 --- a/public/config/地图配置野怪.xml +++ b/public/config/地图配置野怪.xml @@ -431,7 +431,7 @@ eg: - +