using GAS.Runtime; using Sog; using UnityEngine.Profiling; namespace CoreGame.Render { public class GaDeathSpec : AbilitySpec, ISptPool { protected TimelineAbilityPlayer player; private CallbackWrapper m_CallbackWrapper = null; public override void Awake(GameplayAbility ability, GameAbilityContext gaCtx) { base.Awake(ability, gaCtx); player = new TimelineAbilityPlayer(); player.Awake(this); gaCtx.asc.RegisterGameplayTagEvent(GTagLib.Event_Dying, EGameplayTagEventType.NewOrRemoved, OnWillDeath); } public override void GrantAbility() { m_CallbackWrapper = CallbackWrapper.New(OnHpChange, this); ctx.ownerEnt.AddEventCallBack(ClientEvent.OnEntityBeKill, m_CallbackWrapper); } public override void UnGrantAbility() { ctx.ownerEnt.RemoveCallback(ClientEvent.OnEntityBeKill, ref m_CallbackWrapper); } public void OnHpChange(object self, int eventId, object value) { var spec = (GaDeathSpec)self; spec.OnWillDeath(default, 1); } public void OnWillDeath(GameplayTag tag, int count) { if (count == 0) // 代表移除 return; if (ctx.ownerEnt.abilitySystem == null) return; // 触发死亡前能力 var b = ctx.ownerEnt.abilitySystem.TryActivateAbilities_WithTag(GTagLib.Event_BeforeDyingGA); if (!b) { // 直接死亡 OnDeath(tag, count); } else { // 等待死亡前能力结束 ctx.asc.RegisterGameplayTagEvent(GTagLib.Event_BeforeDyingGA, EGameplayTagEventType.NewOrRemoved, OnDeath); } } public void OnDeath(GameplayTag tag, int count) { if (count == 0) return; ctx.ownerEnt.abilitySystem.TryActivateAbilities_WithTag(GTagLib.Event_Dying); } private void DisableCmpts() { var ent = ctx.ownerEnt; ent.isDead = true; if (ent.hasCollider2DProxy) { var colliderProxy = ent.collider2DProxy; foreach (var collider in colliderProxy.cs) { ColliderSrv.DisableCollider(collider); } } } private void DestroyLifeBindChildren() { var lifeBindMe = ctx.ownerEnt.lifeBindMe; if (lifeBindMe != null) { for (int i = 0; i < lifeBindMe.children.Count; i++) { var childEid = lifeBindMe.children[i]; var childEnt = Contexts.Combat.GetEntity(childEid); if (childEnt != null) { childEnt.isDead = true; childEnt.isDestroyEnt = true; } } lifeBindMe.children.Clear(); } } private void PushBattleData() { var levelWaveEnt = Contexts.Combat.LevelWave; if (levelWaveEnt == null) return; var levelWave = levelWaveEnt.levelWave; if (ctx.ownerEnt.hasMonster) { if (!ctx.ownerEnt.hasSummon) { var battleWaveData = SptPool.Malloc(); battleWaveData.MonsterKilledCount = 1; battleWaveData.StageId = levelWave.curStageId; CoreUIBridge.CoreGamePushBattleWaveData(battleWaveData); SptPool.Free(ref battleWaveData); } } else if (ctx.ownerEnt.isLocalPlayer) { var isBossContinueBattleRedNameWave = BattleModule.Instance.worldType == WorldType.BossContinueBattle && CoreUIBridge.s_BossBattleParams.waveIsRedName; if (!isBossContinueBattleRedNameWave) { CoreUIBridge.CoreGamePushBattleEndData(levelWave.battleId, CoreUIBridge.BattleEndType.LoseHeroDead); } } } private void MakeLocalPlayerCannotBeHurt() { const int normalBattleParam = 1; const int bossContinueBattleParam = 2; if (ctx.ownerEnt.hasMonster && !ctx.ownerEnt.hasSummon) { var worldType = BattleModule.Instance.worldType; var monsterType = ctx.ownerEnt.monster.monsterType; if (worldType != WorldType.BossContinueBattle) { if (monsterType == MonsterType.Boss) { Contexts.Combat.LocalPlayer.DispatchEvent(ClientEvent.MakeEntityCannotBeHurt, normalBattleParam); } } else { if (monsterType == MonsterType.Boss || monsterType == MonsterType.Intruder) { Contexts.Combat.LocalPlayer.DispatchEvent(ClientEvent.MakeEntityCannotBeHurt, bossContinueBattleParam); } } } } public override void ActivateAbility() { MakeLocalPlayerCannotBeHurt(); player.Stop(); player.Play(); DisableCmpts(); } public override void CancelAbility() { player.Stop(); } public override void EndAbility() { player.Stop(); DestroyLifeBindChildren(); PushBattleData(); } protected override void AbilityTick(Fixed64 dt) { Profiler.BeginSample("GaDeathSpec::AbilityTick()"); player.Tick(dt); Profiler.EndSample(); } public void Reset() { player = null; } } public class GADeath : GameplayAbility { public GADeath(AbilityAsset abilityAsset) : base(abilityAsset) { } public override AbilitySpec CreateSpec(AbilitySystemComponent owner, GameAbilityContext ctx) { var deathAbilitySpec = SptPool.Malloc(); deathAbilitySpec.Awake(this, ctx); return deathAbilitySpec; } public override void FreeSpec(ref AbilitySpec spec) { if (!(spec is GaDeathSpec deathAbilitySpec)) { BattleLogger.LogInfo("DeathAbilitySpec.FreeSpec: spec is not DeathAbilitySpec"); return; } SptPool.Free(ref deathAbilitySpec); } } }