Explodes performance optimization

Cache armaments on creation, avoid LINQ.

Also merge and put first the DamageThreshold == 0
check in Damaged, because the common default IS 0,
so most of the time the IsTraitDisabled and
IsInWorld checks are redundant.
This commit is contained in:
reaperrr
2020-05-28 00:15:03 +02:00
committed by Paul Chote
parent 034c6824de
commit 6d0fbfa21f

View File

@@ -82,6 +82,9 @@ namespace OpenRA.Mods.Common.Traits
{ {
readonly IHealth health; readonly IHealth health;
BuildingInfo buildingInfo; BuildingInfo buildingInfo;
Armament[] armaments;
bool anyArmaments;
public Explodes(ExplodesInfo info, Actor self) public Explodes(ExplodesInfo info, Actor self)
: base(info) : base(info)
@@ -92,6 +95,9 @@ namespace OpenRA.Mods.Common.Traits
protected override void Created(Actor self) protected override void Created(Actor self)
{ {
buildingInfo = self.Info.TraitInfoOrDefault<BuildingInfo>(); buildingInfo = self.Info.TraitInfoOrDefault<BuildingInfo>();
armaments = self.TraitsImplementing<Armament>().ToArray();
anyArmaments = armaments.Length > 0;
base.Created(self); base.Created(self);
} }
@@ -100,13 +106,14 @@ namespace OpenRA.Mods.Common.Traits
if (IsTraitDisabled || !self.IsInWorld) if (IsTraitDisabled || !self.IsInWorld)
return; return;
if (self.World.SharedRandom.Next(100) > Info.Chance) var sharedRandom = self.World.SharedRandom.Next(100);
if (sharedRandom > Info.Chance)
return; return;
if (!Info.DeathTypes.IsEmpty && !e.Damage.DamageTypes.Overlaps(Info.DeathTypes)) if (!Info.DeathTypes.IsEmpty && !e.Damage.DamageTypes.Overlaps(Info.DeathTypes))
return; return;
var weapon = ChooseWeaponForExplosion(self); var weapon = ChooseWeaponForExplosion(self, sharedRandom);
if (weapon == null) if (weapon == null)
return; return;
@@ -127,24 +134,24 @@ namespace OpenRA.Mods.Common.Traits
weapon.Impact(Target.FromPos(self.CenterPosition), source); weapon.Impact(Target.FromPos(self.CenterPosition), source);
} }
WeaponInfo ChooseWeaponForExplosion(Actor self) WeaponInfo ChooseWeaponForExplosion(Actor self, int sharedRandom)
{ {
var armaments = self.TraitsImplementing<Armament>(); if (!anyArmaments)
if (!armaments.Any())
return Info.WeaponInfo; return Info.WeaponInfo;
else if (sharedRandom > Info.LoadedChance)
return Info.EmptyWeaponInfo;
// TODO: EmptyWeapon should be removed in favour of conditions // PERF: Avoid LINQ
var shouldExplode = !armaments.All(a => a.IsReloading); foreach (var a in armaments)
var useFullExplosion = self.World.SharedRandom.Next(100) <= Info.LoadedChance; if (!a.IsReloading)
return (shouldExplode && useFullExplosion) ? Info.WeaponInfo : Info.EmptyWeaponInfo; return Info.WeaponInfo;
return Info.EmptyWeaponInfo;
} }
void INotifyDamage.Damaged(Actor self, AttackInfo e) void INotifyDamage.Damaged(Actor self, AttackInfo e)
{ {
if (IsTraitDisabled || !self.IsInWorld) if (Info.DamageThreshold == 0 || IsTraitDisabled || !self.IsInWorld)
return;
if (Info.DamageThreshold == 0)
return; return;
if (!Info.DeathTypes.IsEmpty && !e.Damage.DamageTypes.Overlaps(Info.DeathTypes)) if (!Info.DeathTypes.IsEmpty && !e.Damage.DamageTypes.Overlaps(Info.DeathTypes))