From 1e08cdd0f1f9e4f79a378048c56644a4330532f9 Mon Sep 17 00:00:00 2001 From: Designer225 Date: Sat, 30 Dec 2023 13:35:43 -0800 Subject: [PATCH] Reworked agent add/remove from behavior oversight --- BattleRegen/BattleRegen.csproj | 2 +- BattleRegen/BattleRegenAgentData.cs | 17 +++-- BattleRegen/BattleRegenerationBehavior.cs | 87 +++++++++++++---------- SubModule.xml | 2 +- 4 files changed, 61 insertions(+), 47 deletions(-) diff --git a/BattleRegen/BattleRegen.csproj b/BattleRegen/BattleRegen.csproj index b939a9c..b70c10d 100644 --- a/BattleRegen/BattleRegen.csproj +++ b/BattleRegen/BattleRegen.csproj @@ -11,7 +11,7 @@ false false True - 2.2.2.90 + 2.2.3.100 full ..\bin\Win64_Shipping_Client\BattleRegen.xml $(OutputPath) diff --git a/BattleRegen/BattleRegenAgentData.cs b/BattleRegen/BattleRegenAgentData.cs index 5cb5df8..711143b 100644 --- a/BattleRegen/BattleRegenAgentData.cs +++ b/BattleRegen/BattleRegenAgentData.cs @@ -187,36 +187,39 @@ public readonly void GiveXpToHealers( case TroopType.Mount: case TroopType.Animal: float riderXpGain = xpGain * settings.XpGain; - Hero? rider = (agent.MountAgent.Character as CharacterObject)?.HeroObject; + var rider = (agent.MountAgent?.Character as CharacterObject)?.HeroObject; if (rider != null) xpGains.Push((rider, riderXpGain)); - if (settings.VerboseDebug) - messages.Enqueue($"[BattleRegeneration] rider agent {agent.MountAgent.Name} has received {riderXpGain} xp"); + if (settings.VerboseDebug && rider != null) + messages.Enqueue($"[BattleRegeneration] rider agent {rider} has received {riderXpGain} xp"); break; default: float selfXpGain = xpGain * settings.XpGain; - Hero? hero = (agent.Character as CharacterObject)?.HeroObject; + var hero = (agent.Character as CharacterObject)?.HeroObject; if (hero != null) xpGains.Push((hero, selfXpGain)); if (settings.VerboseDebug) messages.Enqueue($"[BattleRegeneration] agent {agent.Name} has received {selfXpGain} xp"); float cdrXpGain = xpGain * settings.CommanderXpGain; - Hero? commander = default; + var commander = default(Hero); switch (troopType) { case TroopType.Player: case TroopType.Companion: case TroopType.Subordinate: case TroopType.PlayerTroop: - commander = (Agent.Main.Character as CharacterObject)?.HeroObject; + commander = (Agent.Main?.Character as CharacterObject)?.HeroObject; + commander ??= (Mission.Current?.MainAgent?.Character as CharacterObject)?.HeroObject; + commander ??= (Mission.Current?.PlayerTeam?.ActiveAgents?.Find(x => x.IsPlayerUnit)?.Character as CharacterObject)?.HeroObject; + commander ??= Hero.MainHero; break; case TroopType.AlliedHero: case TroopType.AlliedTroop: case TroopType.EnemyHero: case TroopType.EnemyTroop: - commander = (agent.Team.GeneralAgent.Character as CharacterObject)?.HeroObject; + commander = (agent.Team?.GeneralAgent?.Character as CharacterObject)?.HeroObject; break; } if (commander != default) diff --git a/BattleRegen/BattleRegenerationBehavior.cs b/BattleRegen/BattleRegenerationBehavior.cs index 6b7d1b3..ec19df3 100644 --- a/BattleRegen/BattleRegenerationBehavior.cs +++ b/BattleRegen/BattleRegenerationBehavior.cs @@ -23,7 +23,7 @@ sealed class BattleRegenerationBehavior : MissionBehavior private readonly Dictionary _heroXpGainPairs; private readonly Dictionary _agentIndexPairs; private BattleRegenAgentData[] _agentData; - private readonly Stack _freeList; + private Stack<(Agent, bool)> _toAddOrRemove; public override MissionBehaviorType BehaviorType => MissionBehaviorType.Other; @@ -33,7 +33,7 @@ public BattleRegenerationBehavior() _heroXpGainPairs = new Dictionary(); _agentIndexPairs = new Dictionary(AnticipatedAgentCount); _agentData = new BattleRegenAgentData[AnticipatedAgentCount]; - _freeList = new Stack(); + _toAddOrRemove = new Stack<(Agent, bool)>(); Debug.Print("[BattleRegeneration] Mission started, data initialized"); Debug.Print($"[BattleRegeneration] Debug mode on, dumping settings: regen mode: {_settings.RegenModel}, " + @@ -44,35 +44,6 @@ public BattleRegenerationBehavior() $"enemy troops:{_settings.RegenAmountEnemyTroops}, animals:{_settings.RegenAmountAnimals}"); } - private void AddAgent(Agent agent) - { - int index; - if (_freeList.Count > 0) index = _freeList.Pop(); - else - { - EnsureCapacity(); - index = _agentIndexPairs.Count; - } - _agentIndexPairs[agent] = index; - _agentData[index] = new BattleRegenAgentData(agent); - - if (_settings.Debug) - Debug.Print($"[BattleRegen] agent {agent.Name} registered"); - } - - private void RemoveAgent(Agent agent) - { - if (_agentIndexPairs.TryGetValue(agent, out var index)) - { - _agentIndexPairs.Remove(agent); - _agentData[index] = default; - _freeList.Push(index); - - if (_settings.Debug) - Debug.Print($"[BattleRegen] agent {agent.Name} unregistered"); - } - } - private void EnsureCapacity(int add = 1) { int capacity = _agentIndexPairs.Count + add; @@ -84,15 +55,12 @@ private void EnsureCapacity(int add = 1) } } - public override void OnAgentBuild(Agent agent, Banner banner) - { - AddAgent(agent); - } + public override void OnAgentBuild(Agent agent, Banner banner) => _toAddOrRemove.Push((agent, true)); public override void OnAgentRemoved(Agent affectedAgent, Agent affectorAgent, AgentState agentState, KillingBlow blow) - => RemoveAgent(affectedAgent); + => _toAddOrRemove.Push((affectedAgent, false)); - public override void OnAgentDeleted(Agent affectedAgent) => RemoveAgent(affectedAgent); + public override void OnAgentDeleted(Agent affectedAgent) => _toAddOrRemove.Push((affectedAgent, false)); public override void OnRegisterBlow(Agent attacker, Agent victim, GameEntity realHitEntity, Blow b, ref AttackCollisionData collisionData, in MissionWeapon attackerWeapon) { @@ -109,12 +77,19 @@ public override void OnRegisterBlow(Agent attacker, Agent victim, GameEntity rea public override void OnMissionTick(float dt) { + while (_toAddOrRemove.Count > 0) + { + var (agent, addIfTrue) = _toAddOrRemove.Pop(); + if (addIfTrue) AddAgent(agent); + else RemoveAgent(agent); + } + var arenaController = Mission.GetMissionBehavior(); if (arenaController != default && arenaController.AfterPractice) return; int messageCount = 0; const int infoMessageCap = 10, messageCap = 100; - foreach (var (messages, xpGains) in _agentIndexPairs.Values.AsParallel().Select(x => _agentData[x].AttemptRegeneration(dt, _settings))) + foreach (var (messages, xpGains) in ParallelEnumerable.Range(0, _agentIndexPairs.Count).Select(x => _agentData[x].AttemptRegeneration(dt, _settings))) { if (messages != null) for (; messageCount < messageCap; ++messageCount) @@ -137,6 +112,42 @@ public override void OnMissionTick(float dt) } } + private void AddAgent(Agent agent) + { + EnsureCapacity(); + int index = _agentIndexPairs.Count; + _agentIndexPairs[agent] = index; + _agentData[index] = new BattleRegenAgentData(agent); + + if (_settings.Debug) + Debug.Print($"[BattleRegen] agent {agent.Name} registered"); + } + + private void RemoveAgent(Agent agent) + { + if (_agentIndexPairs.TryGetValue(agent, out var index)) + { + _agentIndexPairs.Remove(agent); + ref var dataRef = ref _agentData[index]; + // since index < Count always, after removal from dictionary index <= Count always. + // we do not need to swap if index == Count (since the last item removed is the last added) + // otherwise we swap and update accordingly + var lastIndex = _agentIndexPairs.Count; + if (index < lastIndex) + { + // swap with last item + ref var lastDataRef = ref _agentData[lastIndex]; + dataRef = lastDataRef; + lastDataRef = default; + _agentIndexPairs[dataRef.Agent] = index; + } + else dataRef = default; + + if (_settings.Debug) + Debug.Print($"[BattleRegen] agent {agent.Name} unregistered"); + } + } + protected override void OnEndMission() { base.OnEndMission(); diff --git a/SubModule.xml b/SubModule.xml index 96d9bcf..7520440 100644 --- a/SubModule.xml +++ b/SubModule.xml @@ -1,7 +1,7 @@ - +