Cache *Notify traits in Health where applicable

During heated battles, those TraitsImplementing look-ups in Health might cause bursty CPU load on warhead impacts. Caching the notify traits of the actor + owner can reduce the trait look-ups per impact by more than half.
This commit is contained in:
reaperrr
2018-09-18 01:25:54 +02:00
committed by Paul Chote
parent 13769d48a1
commit 1f7edf9f0b

View File

@@ -32,9 +32,16 @@ namespace OpenRA.Mods.Common.Traits
} }
} }
public class Health : IHealth, ISync, ITick public class Health : IHealth, ISync, ITick, INotifyCreated, INotifyOwnerChanged
{ {
public readonly HealthInfo Info; public readonly HealthInfo Info;
INotifyDamageStateChanged[] notifyDamageStateChanged;
INotifyDamage[] notifyDamage;
INotifyDamage[] notifyDamagePlayer;
IDamageModifier[] damageModifiers;
IDamageModifier[] damageModifiersPlayer;
INotifyKilled[] notifyKilled;
INotifyKilled[] notifyKilledPlayer;
[Sync] int hp; [Sync] int hp;
@@ -80,6 +87,24 @@ namespace OpenRA.Mods.Common.Traits
} }
} }
void INotifyCreated.Created(Actor self)
{
notifyDamageStateChanged = self.TraitsImplementing<INotifyDamageStateChanged>().ToArray();
notifyDamage = self.TraitsImplementing<INotifyDamage>().ToArray();
notifyDamagePlayer = self.Owner.PlayerActor.TraitsImplementing<INotifyDamage>().ToArray();
damageModifiers = self.TraitsImplementing<IDamageModifier>().ToArray();
damageModifiersPlayer = self.Owner.PlayerActor.TraitsImplementing<IDamageModifier>().ToArray();
notifyKilled = self.TraitsImplementing<INotifyKilled>().ToArray();
notifyKilledPlayer = self.Owner.PlayerActor.TraitsImplementing<INotifyKilled>().ToArray();
}
void INotifyOwnerChanged.OnOwnerChanged(Actor self, Player oldOwner, Player newOwner)
{
notifyDamagePlayer = newOwner.PlayerActor.TraitsImplementing<INotifyDamage>().ToArray();
damageModifiersPlayer = newOwner.PlayerActor.TraitsImplementing<IDamageModifier>().ToArray();
notifyKilledPlayer = newOwner.PlayerActor.TraitsImplementing<INotifyKilled>().ToArray();
}
public void Resurrect(Actor self, Actor repairer) public void Resurrect(Actor self, Actor repairer)
{ {
if (!IsDead) if (!IsDead)
@@ -95,17 +120,21 @@ namespace OpenRA.Mods.Common.Traits
PreviousDamageState = DamageState.Dead, PreviousDamageState = DamageState.Dead,
}; };
foreach (var nd in self.TraitsImplementing<INotifyDamage>() foreach (var nd in notifyDamage)
.Concat(self.Owner.PlayerActor.TraitsImplementing<INotifyDamage>())) nd.Damaged(self, ai);
foreach (var nd in notifyDamagePlayer)
nd.Damaged(self, ai); nd.Damaged(self, ai);
foreach (var nd in self.TraitsImplementing<INotifyDamageStateChanged>()) foreach (var nd in notifyDamageStateChanged)
nd.DamageStateChanged(self, ai); nd.DamageStateChanged(self, ai);
if (Info.NotifyAppliedDamage && repairer != null && repairer.IsInWorld && !repairer.IsDead) if (Info.NotifyAppliedDamage && repairer != null && repairer.IsInWorld && !repairer.IsDead)
foreach (var nd in repairer.TraitsImplementing<INotifyAppliedDamage>() {
.Concat(repairer.Owner.PlayerActor.TraitsImplementing<INotifyAppliedDamage>())) foreach (var nd in repairer.TraitsImplementing<INotifyAppliedDamage>())
nd.AppliedDamage(repairer, self, ai); nd.AppliedDamage(repairer, self, ai);
foreach (var nd in repairer.Owner.PlayerActor.TraitsImplementing<INotifyAppliedDamage>())
nd.AppliedDamage(repairer, self, ai);
}
} }
public void InflictDamage(Actor self, Actor attacker, Damage damage, bool ignoreModifiers) public void InflictDamage(Actor self, Actor attacker, Damage damage, bool ignoreModifiers)
@@ -119,8 +148,8 @@ namespace OpenRA.Mods.Common.Traits
// Apply any damage modifiers // Apply any damage modifiers
if (!ignoreModifiers && damage.Value > 0) if (!ignoreModifiers && damage.Value > 0)
{ {
var modifiers = self.TraitsImplementing<IDamageModifier>() var modifiers = damageModifiers
.Concat(self.Owner.PlayerActor.TraitsImplementing<IDamageModifier>()) .Concat(damageModifiersPlayer)
.Select(t => t.GetDamageModifier(attacker, damage)); .Select(t => t.GetDamageModifier(attacker, damage));
damage = new Damage(Util.ApplyPercentageModifiers(damage.Value, modifiers), damage.DamageTypes); damage = new Damage(Util.ApplyPercentageModifiers(damage.Value, modifiers), damage.DamageTypes);
@@ -136,23 +165,28 @@ namespace OpenRA.Mods.Common.Traits
PreviousDamageState = oldState, PreviousDamageState = oldState,
}; };
foreach (var nd in self.TraitsImplementing<INotifyDamage>() foreach (var nd in notifyDamage)
.Concat(self.Owner.PlayerActor.TraitsImplementing<INotifyDamage>())) nd.Damaged(self, ai);
foreach (var nd in notifyDamagePlayer)
nd.Damaged(self, ai); nd.Damaged(self, ai);
if (DamageState != oldState) if (DamageState != oldState)
foreach (var nd in self.TraitsImplementing<INotifyDamageStateChanged>()) foreach (var nd in notifyDamageStateChanged)
nd.DamageStateChanged(self, ai); nd.DamageStateChanged(self, ai);
if (Info.NotifyAppliedDamage && attacker != null && attacker.IsInWorld && !attacker.IsDead) if (Info.NotifyAppliedDamage && attacker != null && attacker.IsInWorld && !attacker.IsDead)
foreach (var nd in attacker.TraitsImplementing<INotifyAppliedDamage>() {
.Concat(attacker.Owner.PlayerActor.TraitsImplementing<INotifyAppliedDamage>())) foreach (var nd in attacker.TraitsImplementing<INotifyAppliedDamage>())
nd.AppliedDamage(attacker, self, ai); nd.AppliedDamage(attacker, self, ai);
foreach (var nd in attacker.Owner.PlayerActor.TraitsImplementing<INotifyAppliedDamage>())
nd.AppliedDamage(attacker, self, ai);
}
if (hp == 0) if (hp == 0)
{ {
foreach (var nd in self.TraitsImplementing<INotifyKilled>() foreach (var nd in notifyKilled)
.Concat(self.Owner.PlayerActor.TraitsImplementing<INotifyKilled>())) nd.Killed(self, ai);
foreach (var nd in notifyKilledPlayer)
nd.Killed(self, ai); nd.Killed(self, ai);
if (RemoveOnDeath) if (RemoveOnDeath)