HitShape, query trait via actor cached targetable positions.

This commit is contained in:
Vapre
2022-08-04 21:42:14 +02:00
committed by Matthias Mailänder
parent f88b6d78ff
commit e3aa2dc6c0
6 changed files with 61 additions and 29 deletions

View File

@@ -68,6 +68,7 @@ namespace OpenRA
public IEffectiveOwner EffectiveOwner { get; } public IEffectiveOwner EffectiveOwner { get; }
public IOccupySpace OccupiesSpace { get; } public IOccupySpace OccupiesSpace { get; }
public ITargetable[] Targetables { get; } public ITargetable[] Targetables { get; }
public IEnumerable<ITargetablePositions> EnabledTargetablePositions { get; private set; }
public bool IsIdle => CurrentActivity == null; public bool IsIdle => CurrentActivity == null;
public bool IsDead => Disposed || (health != null && health.IsDead); public bool IsDead => Disposed || (health != null && health.IsDead);
@@ -114,7 +115,6 @@ namespace OpenRA
readonly IDefaultVisibility defaultVisibility; readonly IDefaultVisibility defaultVisibility;
readonly INotifyBecomingIdle[] becomingIdles; readonly INotifyBecomingIdle[] becomingIdles;
readonly INotifyIdle[] tickIdles; readonly INotifyIdle[] tickIdles;
readonly IEnumerable<ITargetablePositions> enabledTargetablePositions;
readonly IEnumerable<WPos> enabledTargetableWorldPositions; readonly IEnumerable<WPos> enabledTargetableWorldPositions;
bool created; bool created;
@@ -192,8 +192,8 @@ namespace OpenRA
tickIdles = tickIdlesList.ToArray(); tickIdles = tickIdlesList.ToArray();
Targetables = targetablesList.ToArray(); Targetables = targetablesList.ToArray();
var targetablePositions = targetablePositionsList.ToArray(); var targetablePositions = targetablePositionsList.ToArray();
enabledTargetablePositions = targetablePositions.Where(Exts.IsTraitEnabled); EnabledTargetablePositions = targetablePositions.Where(Exts.IsTraitEnabled);
enabledTargetableWorldPositions = enabledTargetablePositions.SelectMany(tp => tp.TargetablePositions(this)); enabledTargetableWorldPositions = EnabledTargetablePositions.SelectMany(tp => tp.TargetablePositions(this));
SyncHashes = syncHashesList.ToArray(); SyncHashes = syncHashesList.ToArray();
} }
} }
@@ -530,7 +530,7 @@ namespace OpenRA
public IEnumerable<WPos> GetTargetablePositions() public IEnumerable<WPos> GetTargetablePositions()
{ {
if (enabledTargetablePositions.Any()) if (EnabledTargetablePositions.Any())
return enabledTargetableWorldPositions; return enabledTargetableWorldPositions;
return new[] { CenterPosition }; return new[] { CenterPosition };

View File

@@ -11,7 +11,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using OpenRA.GameRules; using OpenRA.GameRules;
using OpenRA.Graphics; using OpenRA.Graphics;
using OpenRA.Mods.Common.Effects; using OpenRA.Mods.Common.Effects;
@@ -336,8 +335,10 @@ namespace OpenRA.Mods.Common.Projectiles
continue; continue;
// If the impact position is within any actor's HitShape, we have a direct hit // If the impact position is within any actor's HitShape, we have a direct hit
var activeShapes = victim.TraitsImplementing<HitShape>().Where(Exts.IsTraitEnabled); // PERF: Avoid using TraitsImplementing<HitShape> that needs to find the actor in the trait dictionary.
if (activeShapes.Any(i => i.DistanceFromEdge(victim, pos).Length <= 0)) foreach (var targetPos in victim.EnabledTargetablePositions)
if (targetPos is HitShape h)
if (h.DistanceFromEdge(victim, pos).Length <= 0)
return true; return true;
} }

View File

@@ -50,8 +50,14 @@ namespace OpenRA.Mods.Common.Warheads
if (!IsValidAgainst(victim, firedBy)) if (!IsValidAgainst(victim, firedBy))
return; return;
var closestActiveShape = victim.TraitsImplementing<HitShape>().Where(Exts.IsTraitEnabled) // PERF: Avoid using TraitsImplementing<HitShape> that needs to find the actor in the trait dictionary.
.MinByOrDefault(t => t.DistanceFromEdge(victim, victim.CenterPosition)); var closestActiveShape = (HitShape)victim.EnabledTargetablePositions.MinByOrDefault(t =>
{
if (t is HitShape h)
return h.DistanceFromEdge(victim, victim.CenterPosition);
else
return WDist.MaxValue;
});
// Cannot be damaged without an active HitShape // Cannot be damaged without an active HitShape
if (closestActiveShape == null) if (closestActiveShape == null)

View File

@@ -63,20 +63,32 @@ namespace OpenRA.Mods.Common.Warheads
if (!IsValidAgainst(victim, firedBy)) if (!IsValidAgainst(victim, firedBy))
continue; continue;
var closestActiveShape = victim.TraitsImplementing<HitShape>() HitShape closestActiveShape = null;
.Where(Exts.IsTraitEnabled) var closestDistance = int.MaxValue;
.Select(s => (HitShape: s, Distance: s.DistanceFromEdge(victim, pos)))
.MinByOrDefault(s => s.Distance); // PERF: Avoid using TraitsImplementing<HitShape> that needs to find the actor in the trait dictionary.
foreach (var targetPos in victim.EnabledTargetablePositions)
{
if (targetPos is HitShape h)
{
var distance = h.DistanceFromEdge(victim, pos).Length;
if (distance < closestDistance)
{
closestDistance = distance;
closestActiveShape = h;
}
}
}
// Cannot be damaged without an active HitShape. // Cannot be damaged without an active HitShape.
if (closestActiveShape.HitShape == null) if (closestActiveShape == null)
continue; continue;
var falloffDistance = 0; var falloffDistance = 0;
switch (DamageCalculationType) switch (DamageCalculationType)
{ {
case DamageCalculationType.HitShape: case DamageCalculationType.HitShape:
falloffDistance = closestActiveShape.Distance.Length; falloffDistance = closestDistance;
break; break;
case DamageCalculationType.ClosestTargetablePosition: case DamageCalculationType.ClosestTargetablePosition:
falloffDistance = victim.GetTargetablePositions().Select(x => (x - pos).Length).Min(); falloffDistance = victim.GetTargetablePositions().Select(x => (x - pos).Length).Min();
@@ -108,7 +120,7 @@ namespace OpenRA.Mods.Common.Warheads
ImpactOrientation = impactOrientation, ImpactOrientation = impactOrientation,
}; };
InflictDamage(victim, firedBy, closestActiveShape.HitShape, updatedWarheadArgs); InflictDamage(victim, firedBy, closestActiveShape, updatedWarheadArgs);
} }
} }

View File

@@ -9,7 +9,6 @@
*/ */
#endregion #endregion
using System.Linq;
using OpenRA.GameRules; using OpenRA.GameRules;
using OpenRA.Mods.Common.Traits; using OpenRA.Mods.Common.Traits;
using OpenRA.Traits; using OpenRA.Traits;
@@ -36,20 +35,32 @@ namespace OpenRA.Mods.Common.Warheads
if (!IsValidAgainst(victim, firedBy)) if (!IsValidAgainst(victim, firedBy))
continue; continue;
var closestActiveShape = victim.TraitsImplementing<HitShape>() HitShape closestActiveShape = null;
.Where(Exts.IsTraitEnabled) var closestDistance = int.MaxValue;
.Select(s => (HitShape: s, Distance: s.DistanceFromEdge(victim, pos)))
.MinByOrDefault(s => s.Distance); // PERF: Avoid using TraitsImplementing<HitShape> that needs to find the actor in the trait dictionary.
foreach (var targetPos in victim.EnabledTargetablePositions)
{
if (targetPos is HitShape hitshape)
{
var distance = hitshape.DistanceFromEdge(victim, pos).Length;
if (distance < closestDistance)
{
closestDistance = distance;
closestActiveShape = hitshape;
}
}
}
// Cannot be damaged without an active HitShape. // Cannot be damaged without an active HitShape.
if (closestActiveShape.HitShape == null) if (closestActiveShape == null)
continue; continue;
// Cannot be damaged if HitShape is outside Spread. // Cannot be damaged if HitShape is outside Spread.
if (closestActiveShape.Distance > Spread) if (closestDistance > Spread.Length)
continue; continue;
InflictDamage(victim, firedBy, closestActiveShape.HitShape, args); InflictDamage(victim, firedBy, closestActiveShape, args);
} }
} }
} }

View File

@@ -9,8 +9,8 @@
*/ */
#endregion #endregion
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using OpenRA.Mods.Common.Traits; using OpenRA.Mods.Common.Traits;
namespace OpenRA.Mods.Common namespace OpenRA.Mods.Common
@@ -49,9 +49,11 @@ namespace OpenRA.Mods.Common
foreach (var currActor in actorsInSquare) foreach (var currActor in actorsInSquare)
{ {
var actorWidth = 0; var actorWidth = 0;
var shapes = currActor.TraitsImplementing<HitShape>().Where(Exts.IsTraitEnabled);
if (shapes.Any()) // PERF: Avoid using TraitsImplementing<HitShape> that needs to find the actor in the trait dictionary.
actorWidth = shapes.Max(h => h.Info.Type.OuterRadius.Length); foreach (var targetPos in currActor.EnabledTargetablePositions)
if (targetPos is HitShape hitshape)
actorWidth = Math.Max(actorWidth, hitshape.Info.Type.OuterRadius.Length);
var projection = lineStart.MinimumPointLineProjection(lineEnd, currActor.CenterPosition); var projection = lineStart.MinimumPointLineProjection(lineEnd, currActor.CenterPosition);
var distance = (currActor.CenterPosition - projection).HorizontalLength; var distance = (currActor.CenterPosition - projection).HorizontalLength;