Merge pull request #9734 from RoosterDragon/auto-target-perf

Improve AutoTarget performance
This commit is contained in:
Oliver Brakmann
2015-12-20 19:53:17 +01:00
18 changed files with 174 additions and 89 deletions

View File

@@ -44,6 +44,7 @@ namespace OpenRA
public Rectangle VisualBounds { get; private set; }
public IEffectiveOwner EffectiveOwner { get; private set; }
public IOccupySpace OccupiesSpace { get; private set; }
public ITargetable[] Targetables { get; private set; }
public bool IsIdle { get { return currentActivity == null; } }
public bool IsDead { get { return Disposed || (health != null && health.IsDead); } }
@@ -110,6 +111,7 @@ namespace OpenRA
disables = TraitsImplementing<IDisable>().ToArray();
visibilityModifiers = TraitsImplementing<IVisibilityModifier>().ToArray();
defaultVisibility = Trait<IDefaultVisibility>();
Targetables = TraitsImplementing<ITargetable>().ToArray();
}
Rectangle DetermineBounds()
@@ -334,6 +336,33 @@ namespace OpenRA
return defaultVisibility.IsVisible(this, player);
}
public IEnumerable<string> GetAllTargetTypes()
{
// PERF: Avoid LINQ.
foreach (var targetable in Targetables)
foreach (var targetType in targetable.TargetTypes)
yield return targetType;
}
public IEnumerable<string> GetEnabledTargetTypes()
{
// PERF: Avoid LINQ.
foreach (var targetable in Targetables)
if (targetable.IsTraitEnabled())
foreach (var targetType in targetable.TargetTypes)
yield return targetType;
}
public bool IsTargetableBy(Actor byActor)
{
// PERF: Avoid LINQ.
foreach (var targetable in Targetables)
if (targetable.IsTraitEnabled() && targetable.TargetableBy(this, byActor))
return true;
return false;
}
#region Scripting interface
Lazy<ScriptActorInterface> luaInterface;

View File

@@ -127,14 +127,17 @@ namespace OpenRA.GameRules
/// <summary>Checks if the weapon is valid against (can target) the actor.</summary>
public bool IsValidAgainst(Actor victim, Actor firedBy)
{
var targetable = victim.TraitsImplementing<ITargetable>().Where(Exts.IsTraitEnabled);
if (!IsValidTarget(targetable.SelectMany(t => t.TargetTypes)))
var targetTypes = victim.GetEnabledTargetTypes();
if (!IsValidTarget(targetTypes))
return false;
if (!Warheads.Any(w => w.IsValidAgainst(victim, firedBy)))
return false;
// PERF: Avoid LINQ.
foreach (var warhead in Warheads)
if (warhead.IsValidAgainst(victim, firedBy))
return true;
return true;
return false;
}
/// <summary>Checks if the weapon is valid against (can target) the frozen actor.</summary>

View File

@@ -159,13 +159,27 @@ namespace OpenRA
public bool CanTargetActor(Actor a)
{
if (HasFogVisibility && fogVisibilities.Any(f => f.IsVisible(a)))
return true;
// PERF: Avoid LINQ.
if (HasFogVisibility)
foreach (var fogVisibility in fogVisibilities)
if (fogVisibility.IsVisible(a))
return true;
return CanViewActor(a);
}
public bool HasFogVisibility { get { return fogVisibilities.Any(f => f.HasFogVisibility()); } }
public bool HasFogVisibility
{
get
{
// PERF: Avoid LINQ.
foreach (var fogVisibility in fogVisibilities)
if (fogVisibility.HasFogVisibility())
return true;
return false;
}
}
#region Scripting interface

View File

@@ -62,7 +62,7 @@ namespace OpenRA.Traits
CenterPosition = self.CenterPosition;
Bounds = self.Bounds;
TargetTypes = self.TraitsImplementing<ITargetable>().Where(Exts.IsTraitEnabled).SelectMany(t => t.TargetTypes).ToHashSet();
TargetTypes = self.GetEnabledTargetTypes().ToHashSet();
UpdateVisibility();
}

View File

@@ -22,7 +22,6 @@ namespace OpenRA.Traits
TargetType type;
Actor actor;
IEnumerable<ITargetable> targetable;
FrozenActor frozen;
WPos pos;
int generation;
@@ -48,7 +47,6 @@ namespace OpenRA.Traits
return new Target
{
actor = a,
targetable = a.TraitsImplementing<ITargetable>(),
type = TargetType.Actor,
generation = a.Generation,
};
@@ -83,8 +81,7 @@ namespace OpenRA.Traits
if (targeter == null || Type == TargetType.Invalid)
return false;
var targeted = this.actor;
if (targeted != null && !targetable.Any(t => t.IsTraitEnabled() && t.TargetableBy(targeted, targeter)))
if (actor != null && !actor.IsTargetableBy(targeter))
return false;
return true;
@@ -94,7 +91,25 @@ namespace OpenRA.Traits
// TODO: either replace based on target type or put in singleton trait
public bool RequiresForceFire
{
get { return targetable != null && targetable.Any(Exts.IsTraitEnabled) && targetable.Where(Exts.IsTraitEnabled).All(t => t.RequiresForceFire); }
get
{
if (actor == null)
return false;
// PERF: Avoid LINQ.
var isTargetable = false;
foreach (var targetable in actor.Targetables)
{
if (!targetable.IsTraitEnabled())
continue;
isTargetable = true;
if (!targetable.RequiresForceFire)
return false;
}
return isTargetable;
}
}
// Representative position - see Positions for the full set of targetable positions.
@@ -126,8 +141,7 @@ namespace OpenRA.Traits
switch (Type)
{
case TargetType.Actor:
var targetable = actor.TraitsImplementing<ITargetable>().Where(Exts.IsTraitEnabled);
if (!targetable.Any())
if (!actor.Targetables.Any(Exts.IsTraitEnabled))
return new[] { actor.CenterPosition };
var targetablePositions = actor.TraitOrDefault<ITargetablePositions>();