Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HitShape, query trait via actor cached targetable positions. #20165

Merged
merged 1 commit into from Sep 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 4 additions & 4 deletions OpenRA.Game/Actor.cs
Expand Up @@ -68,6 +68,7 @@ public Activity CurrentActivity
public IEffectiveOwner EffectiveOwner { get; }
public IOccupySpace OccupiesSpace { get; }
public ITargetable[] Targetables { get; }
public IEnumerable<ITargetablePositions> EnabledTargetablePositions { get; private set; }

public bool IsIdle => CurrentActivity == null;
public bool IsDead => Disposed || (health != null && health.IsDead);
Expand Down Expand Up @@ -114,7 +115,6 @@ class ConditionState
readonly IDefaultVisibility defaultVisibility;
readonly INotifyBecomingIdle[] becomingIdles;
readonly INotifyIdle[] tickIdles;
readonly IEnumerable<ITargetablePositions> enabledTargetablePositions;
readonly IEnumerable<WPos> enabledTargetableWorldPositions;
bool created;

Expand Down Expand Up @@ -192,8 +192,8 @@ internal Actor(World world, string name, TypeDictionary initDict)
tickIdles = tickIdlesList.ToArray();
Targetables = targetablesList.ToArray();
var targetablePositions = targetablePositionsList.ToArray();
enabledTargetablePositions = targetablePositions.Where(Exts.IsTraitEnabled);
enabledTargetableWorldPositions = enabledTargetablePositions.SelectMany(tp => tp.TargetablePositions(this));
EnabledTargetablePositions = targetablePositions.Where(Exts.IsTraitEnabled);
enabledTargetableWorldPositions = EnabledTargetablePositions.SelectMany(tp => tp.TargetablePositions(this));
SyncHashes = syncHashesList.ToArray();
}
}
Expand Down Expand Up @@ -530,7 +530,7 @@ public bool IsTargetableBy(Actor byActor)

public IEnumerable<WPos> GetTargetablePositions()
{
if (enabledTargetablePositions.Any())
if (EnabledTargetablePositions.Any())
return enabledTargetableWorldPositions;

return new[] { CenterPosition };
Expand Down
9 changes: 5 additions & 4 deletions OpenRA.Mods.Common/Projectiles/Bullet.cs
Expand Up @@ -11,7 +11,6 @@

using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.GameRules;
using OpenRA.Graphics;
using OpenRA.Mods.Common.Effects;
Expand Down Expand Up @@ -336,9 +335,11 @@ bool AnyValidTargetsInRadius(World world, WPos pos, WDist radius, Actor firedBy,
continue;

// If the impact position is within any actor's HitShape, we have a direct hit
var activeShapes = victim.TraitsImplementing<HitShape>().Where(Exts.IsTraitEnabled);
if (activeShapes.Any(i => i.DistanceFromEdge(victim, pos).Length <= 0))
return true;
// 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)
if (h.DistanceFromEdge(victim, pos).Length <= 0)
return true;
}

return false;
Expand Down
10 changes: 8 additions & 2 deletions OpenRA.Mods.Common/Warheads/DamageWarhead.cs
Expand Up @@ -50,8 +50,14 @@ public override void DoImpact(in Target target, WarheadArgs args)
if (!IsValidAgainst(victim, firedBy))
return;

var closestActiveShape = victim.TraitsImplementing<HitShape>().Where(Exts.IsTraitEnabled)
.MinByOrDefault(t => t.DistanceFromEdge(victim, victim.CenterPosition));
// PERF: Avoid using TraitsImplementing<HitShape> that needs to find the actor in the trait dictionary.
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
if (closestActiveShape == null)
Expand Down
26 changes: 19 additions & 7 deletions OpenRA.Mods.Common/Warheads/SpreadDamageWarhead.cs
Expand Up @@ -63,20 +63,32 @@ protected override void DoImpact(WPos pos, Actor firedBy, WarheadArgs args)
if (!IsValidAgainst(victim, firedBy))
continue;

var closestActiveShape = victim.TraitsImplementing<HitShape>()
.Where(Exts.IsTraitEnabled)
.Select(s => (HitShape: s, Distance: s.DistanceFromEdge(victim, pos)))
.MinByOrDefault(s => s.Distance);
HitShape closestActiveShape = null;
var closestDistance = int.MaxValue;

// 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.
if (closestActiveShape.HitShape == null)
if (closestActiveShape == null)
continue;

var falloffDistance = 0;
switch (DamageCalculationType)
{
case DamageCalculationType.HitShape:
falloffDistance = closestActiveShape.Distance.Length;
falloffDistance = closestDistance;
break;
case DamageCalculationType.ClosestTargetablePosition:
falloffDistance = victim.GetTargetablePositions().Select(x => (x - pos).Length).Min();
Expand Down Expand Up @@ -108,7 +120,7 @@ protected override void DoImpact(WPos pos, Actor firedBy, WarheadArgs args)
ImpactOrientation = impactOrientation,
};

InflictDamage(victim, firedBy, closestActiveShape.HitShape, updatedWarheadArgs);
InflictDamage(victim, firedBy, closestActiveShape, updatedWarheadArgs);
}
}

Expand Down
27 changes: 19 additions & 8 deletions OpenRA.Mods.Common/Warheads/TargetDamageWarhead.cs
Expand Up @@ -9,7 +9,6 @@
*/
#endregion

using System.Linq;
using OpenRA.GameRules;
using OpenRA.Mods.Common.Traits;
using OpenRA.Traits;
Expand All @@ -36,20 +35,32 @@ protected override void DoImpact(WPos pos, Actor firedBy, WarheadArgs args)
if (!IsValidAgainst(victim, firedBy))
continue;

var closestActiveShape = victim.TraitsImplementing<HitShape>()
.Where(Exts.IsTraitEnabled)
.Select(s => (HitShape: s, Distance: s.DistanceFromEdge(victim, pos)))
.MinByOrDefault(s => s.Distance);
HitShape closestActiveShape = null;
var closestDistance = int.MaxValue;

// 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.
if (closestActiveShape.HitShape == null)
if (closestActiveShape == null)
continue;

// Cannot be damaged if HitShape is outside Spread.
if (closestActiveShape.Distance > Spread)
if (closestDistance > Spread.Length)
continue;

InflictDamage(victim, firedBy, closestActiveShape.HitShape, args);
InflictDamage(victim, firedBy, closestActiveShape, args);
}
}
}
Expand Down
10 changes: 6 additions & 4 deletions OpenRA.Mods.Common/WorldExtensions.cs
Expand Up @@ -9,8 +9,8 @@
*/
#endregion

using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Mods.Common.Traits;

namespace OpenRA.Mods.Common
Expand Down Expand Up @@ -49,9 +49,11 @@ public static IEnumerable<Actor> FindActorsOnLine(this World world, WPos lineSta
foreach (var currActor in actorsInSquare)
{
var actorWidth = 0;
var shapes = currActor.TraitsImplementing<HitShape>().Where(Exts.IsTraitEnabled);
if (shapes.Any())
actorWidth = shapes.Max(h => h.Info.Type.OuterRadius.Length);

// PERF: Avoid using TraitsImplementing<HitShape> that needs to find the actor in the trait dictionary.
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 distance = (currActor.CenterPosition - projection).HorizontalLength;
Expand Down