From 5f5634d999893b23650cba92f2914be2cc895049 Mon Sep 17 00:00:00 2001 From: xinian Date: Sat, 11 Apr 2026 09:39:00 +0800 Subject: [PATCH] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E6=88=98=E6=96=97?= =?UTF-8?q?=E9=80=BB=E8=BE=91=E6=80=A7=E8=83=BD=E4=B8=8E=E5=86=85=E5=AD=98?= =?UTF-8?q?=E5=88=86=E9=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- logic/service/fight/action.go | 40 +++++++++++++++++++---- logic/service/fight/fightc.go | 7 +---- logic/service/fight/input.go | 10 ++---- logic/service/fight/input/effect.go | 49 ++++++++++++++++++++++------- logic/service/fight/input/input.go | 49 +++++++++++++++++++++-------- logic/service/fight/node/node.go | 19 ++++++----- 6 files changed, 122 insertions(+), 52 deletions(-) diff --git a/logic/service/fight/action.go b/logic/service/fight/action.go index 8e177971b..388ee9df7 100644 --- a/logic/service/fight/action.go +++ b/logic/service/fight/action.go @@ -44,6 +44,7 @@ func (f *FightC) openActionWindow() { f.actionMu.Lock() f.acceptActions = true f.pendingActions = f.pendingActions[:0] + f.pendingHead = 0 f.actionRound.Store(uint32(f.Round)) f.actionMu.Unlock() } @@ -52,6 +53,7 @@ func (f *FightC) closeActionWindow() { f.actionMu.Lock() f.acceptActions = false f.pendingActions = f.pendingActions[:0] + f.pendingHead = 0 f.actionRound.Store(0) f.actionMu.Unlock() @@ -73,8 +75,10 @@ func (f *FightC) submitAction(act action.BattleActionI) { f.actionMu.Unlock() return } + f.compactPendingActionsLocked() replaceIndex := -1 - for i, pending := range f.pendingActions { + for i := f.pendingHead; i < len(f.pendingActions); i++ { + pending := f.pendingActions[i] if pending == nil || actionSlotKeyFromAction(pending) != actionSlotKeyFromAction(act) { continue } @@ -105,15 +109,23 @@ func (f *FightC) submitAction(act action.BattleActionI) { func (f *FightC) nextAction() action.BattleActionI { f.actionMu.Lock() - if len(f.pendingActions) == 0 { + if f.pendingHead >= len(f.pendingActions) { + f.pendingActions = f.pendingActions[:0] + f.pendingHead = 0 f.actionMu.Unlock() return nil } - act := f.pendingActions[0] - copy(f.pendingActions, f.pendingActions[1:]) - f.pendingActions = f.pendingActions[:len(f.pendingActions)-1] - hasMore := len(f.pendingActions) > 0 + act := f.pendingActions[f.pendingHead] + f.pendingActions[f.pendingHead] = nil + f.pendingHead++ + hasMore := f.pendingHead < len(f.pendingActions) + if !hasMore { + f.pendingActions = f.pendingActions[:0] + f.pendingHead = 0 + } else { + f.compactPendingActionsLocked() + } notify := f.actionNotify f.actionMu.Unlock() @@ -127,6 +139,22 @@ func (f *FightC) nextAction() action.BattleActionI { return act } +func (f *FightC) compactPendingActionsLocked() { + if f.pendingHead == 0 { + return + } + if f.pendingHead < len(f.pendingActions)/2 && len(f.pendingActions) < cap(f.pendingActions) { + return + } + remaining := len(f.pendingActions) - f.pendingHead + copy(f.pendingActions, f.pendingActions[f.pendingHead:]) + for i := remaining; i < len(f.pendingActions); i++ { + f.pendingActions[i] = nil + } + f.pendingActions = f.pendingActions[:remaining] + f.pendingHead = 0 +} + // 玩家逃跑/无响应/掉线 func (f *FightC) Over(c common.PlayerI, res model.EnumBattleOverReason) { if f.closefight { diff --git a/logic/service/fight/fightc.go b/logic/service/fight/fightc.go index e8c5cbc43..e440a6c54 100644 --- a/logic/service/fight/fightc.go +++ b/logic/service/fight/fightc.go @@ -467,12 +467,7 @@ func (f *FightC) TURNOVER(cur *input.Input) { if cur == nil { return } - for _, pet := range cur.BenchPets() { - if pet != nil && pet.Info.Hp > 0 { - _hasBackup = true - break - } - } + _hasBackup = cur.HasLivingBench() f.sendLegacySpriteDie(cur, _hasBackup) f.Broadcast(func(ff *input.Input) { diff --git a/logic/service/fight/input.go b/logic/service/fight/input.go index 4728b4224..88e167564 100644 --- a/logic/service/fight/input.go +++ b/logic/service/fight/input.go @@ -39,6 +39,7 @@ type FightC struct { actionNotify chan struct{} acceptActions bool pendingActions []action.BattleActionI // 待处理动作队列,同一战斗位最多保留一个动作 + pendingHead int actionRound atomic.Uint32 quit chan struct{} @@ -250,20 +251,13 @@ func (f *FightC) sideHasActionableSlots(side int) bool { } func (f *FightC) slotNeedsAction(in *input.Input) bool { - var bench []*info.BattlePetEntity if in == nil { return false } if current := in.CurrentPet(); current != nil && current.Info.Hp > 0 { return true } - bench = in.BenchPets() - for _, pet := range bench { - if pet != nil && pet.Info.Hp > 0 { - return true - } - } - return false + return in.HasLivingBench() } func (f *FightC) setActionAttackValue(act action.BattleActionI) { diff --git a/logic/service/fight/input/effect.go b/logic/service/fight/input/effect.go index 99fee5fa2..483abea97 100644 --- a/logic/service/fight/input/effect.go +++ b/logic/service/fight/input/effect.go @@ -107,18 +107,14 @@ func (our *Input) GetProp(id int) alpacadecimal.Decimal { } func (our *Input) GetEffect(etype EnumEffectType, id int) Effect { - var ret []Effect pr := EffectIDCombiner{} pr.Combine(etype, 0, gconv.Uint16(id)) - - for _, v := range our.Effects { - if v.ID().Base == pr.Base && v.Alive() { - ret = append(ret, v) + our.ensureEffectIndex() + bucket := our.effectsByBase[pr.Base] + for i := len(bucket) - 1; i >= 0; i-- { + if bucket[i] != nil && bucket[i].Alive() { + return bucket[i] } - - } - if len(ret) > 0 { - return ret[len(ret)-1] } return nil } @@ -178,6 +174,7 @@ func (our *Input) AddEffect(in *Input, e Effect) Effect { if e == nil { return nil } + our.ensureEffectIndex() ctx := e.Ctx() if ctx != nil { if ctx.Source == nil { @@ -204,7 +201,7 @@ func (our *Input) AddEffect(in *Input, e Effect) Effect { //TODO 先激活 //fmt.Println("产生回合数", e.ID(), e.Duration()) // 如果已有同 ID 的效果,尝试叠加 - for _, v := range our.Effects { + for _, v := range our.effectsByBase[e.ID().Base] { if v == e { return nil //完全相同,跳过执行 } @@ -219,7 +216,7 @@ func (our *Input) AddEffect(in *Input, e Effect) Effect { if !v.CanStack() { //说明进行了替换 v.Alive(false) //不允许叠层,取消效果 e.Duration(utils.Max(e.Duration(), v.Duration())) - our.Effects = append(our.Effects, e) + our.appendEffect(e) return v //这里把V替换掉了 } else { //默认给叠一层 @@ -237,7 +234,7 @@ func (our *Input) AddEffect(in *Input, e Effect) Effect { } //无限叠加,比如能力提升类buff // 如果没有同 ID 的效果,直接添加 - our.Effects = append(our.Effects, e) + our.appendEffect(e) return nil } @@ -309,6 +306,34 @@ func (our *Input) CancelTurn(in *Input) { } +func (our *Input) ensureEffectIndex() { + if our == nil { + return + } + if our.effectsByBase == nil { + our.effectsByBase = make(map[int64][]Effect, len(our.Effects)) + } + if our.indexedEffects > len(our.Effects) { + our.effectsByBase = make(map[int64][]Effect, len(our.Effects)) + our.indexedEffects = 0 + } + for our.indexedEffects < len(our.Effects) { + effect := our.Effects[our.indexedEffects] + if effect != nil { + our.effectsByBase[effect.ID().Base] = append(our.effectsByBase[effect.ID().Base], effect) + } + our.indexedEffects++ + } +} + +func (our *Input) appendEffect(effect Effect) { + if our == nil || effect == nil { + return + } + our.Effects = append(our.Effects, effect) + our.ensureEffectIndex() +} + // // 消除全部 断回合效果,但是我放下场的时候应该断掉所有的回合类效果 // func (our *Input) CancelAll() { // our.Effects = make([]Effect, 0) diff --git a/logic/service/fight/input/input.go b/logic/service/fight/input/input.go index 7f19a2508..1dc23b264 100644 --- a/logic/service/fight/input/input.go +++ b/logic/service/fight/input/input.go @@ -15,6 +15,13 @@ import ( "github.com/jinzhu/copier" ) +var statusBonuses = map[info.EnumPetStatus]float64{ + info.PetStatus.Paralysis: 1.5, + info.PetStatus.Poisoned: 1.5, + info.PetStatus.Sleep: 2.0, + // /info.BattleStatus.Frozen: 2.0, +} + type Input struct { CanChange uint32 //是否可以死亡切换CanChange // CanAction bool //是否可以行动 @@ -27,9 +34,11 @@ type Input struct { CanCapture int Finished bool //是否加载完成 // info.BattleActionI - Effects []Effect //effects 实际上全局就是effect无限回合 //effects容器 技能的 - EffectCache []Effect //这里是命中前执行的容器,也就是命中前执行的所有逻辑相关,理论上一个effect被激活,就应该同时将其他的effect取消激活 - EffectLost []Effect + Effects []Effect //effects 实际上全局就是effect无限回合 //effects容器 技能的 + EffectCache []Effect //这里是命中前执行的容器,也就是命中前执行的所有逻辑相关,理论上一个effect被激活,就应该同时将其他的effect取消激活 + EffectLost []Effect + effectsByBase map[int64][]Effect + indexedEffects int // 删掉伤害记录,可以在回调中记录,而不是每次调用记录 *model.AttackValue FightC common.FightI @@ -57,6 +66,7 @@ func NewInput(c common.FightI, p common.PlayerI) *Input { ret := &Input{FightC: c, Player: p} ret.Effects = make([]Effect, 0) ret.CurPet = make([]*info.BattlePetEntity, 0) + ret.effectsByBase = make(map[int64][]Effect) // t := Geteffect(EffectType.Damage, 0) // t.Effect.SetArgs(ret) @@ -115,6 +125,27 @@ func (our *Input) BenchPets() []*info.BattlePetEntity { return bench } +func (our *Input) HasLivingBench() bool { + if our == nil { + return false + } + current := our.CurrentPet() + currentCatchTime := uint32(0) + if current != nil { + currentCatchTime = current.Info.CatchTime + } + for _, pet := range our.AllPet { + if pet == nil || pet.Info.Hp == 0 { + continue + } + if current != nil && pet.Info.CatchTime == currentCatchTime { + continue + } + return true + } + return false +} + func (our *Input) OpponentSlots() []*Input { if our == nil { return nil @@ -299,20 +330,12 @@ func (our *Input) GetPet(id uint32) (ii *info.BattlePetEntity, Reason info.Chang // GetStatusBonus 获取最高的状态倍率 // 遍历状态数组,返回存在的状态中最高的倍率(无状态则返回1.0) func (our *Input) GetStatusBonus() float64 { - // 异常状态倍率映射表(状态索引 -> 倍率) - var statusBonuses = map[info.EnumPetStatus]float64{ - info.PetStatus.Paralysis: 1.5, - info.PetStatus.Poisoned: 1.5, - info.PetStatus.Sleep: 2.0, - // /info.BattleStatus.Frozen: 2.0, - } maxBonus := 1.0 // 默认无状态倍率 for statusIdx := 0; statusIdx < 20; statusIdx++ { - t := our.InitEffect(EffectType.Status, statusIdx) + t := our.GetEffect(EffectType.Status, statusIdx) - // 检查状态是否存在(数组中值为1表示存在该状态) - if t != nil && t.Stack() > 0 { + if t != nil && t.Alive() { if bonus, exists := statusBonuses[info.EnumPetStatus(statusIdx)]; exists && bonus > maxBonus { maxBonus = bonus } diff --git a/logic/service/fight/node/node.go b/logic/service/fight/node/node.go index 93627a8d0..2a555d638 100644 --- a/logic/service/fight/node/node.go +++ b/logic/service/fight/node/node.go @@ -24,6 +24,7 @@ type EffectNode struct { canStack bool // 最大叠加层数 ,正常都是不允许叠加的,除了衰弱特殊效果 ,异常和能力的叠层 isFirst bool SideEffectArgs []int // 附加效果参数 + cachedArgs []alpacadecimal.Decimal // owner bool //是否作用自身 Success bool // 是否执行成功 成功XXX,失败XXX arget bool // 传出作用对象,默认0是自身,1是作用于对面 @@ -240,18 +241,22 @@ func (e *EffectNode) SetArgs(t *input.Input, a ...int) { e.Input = t if len(a) > 0 { e.SideEffectArgs = a + e.cachedArgs = e.cachedArgs[:0] + for _, v := range a { + e.cachedArgs = append(e.cachedArgs, alpacadecimal.NewFromInt(int64(v))) + } } } func (e *EffectNode) Args() []alpacadecimal.Decimal { - var ret []alpacadecimal.Decimal - - for _, v := range e.SideEffectArgs { - ret = append(ret, alpacadecimal.NewFromInt(int64(v))) - + if len(e.cachedArgs) == len(e.SideEffectArgs) { + return e.cachedArgs } - - return ret + e.cachedArgs = e.cachedArgs[:0] + for _, v := range e.SideEffectArgs { + e.cachedArgs = append(e.cachedArgs, alpacadecimal.NewFromInt(int64(v))) + } + return e.cachedArgs }