Changes to reduce allocations in the main loop.

Targeted some methods that generated allocated a lot of memory in the main game loop:
- Actor.Render - Changed LINQ calls into equivalent loops. No allocation for delegates.
- Animation.Render - Returned an array rather than a yield expression. The array uses less memory than the complier generated enumerable.
- FrozenActor and FrozenUnderFog - Materialize the footprint into an array: The enumerable is not-trivial to evaluate is and evaluated many times inside the Tick function. The memory needed is minimal. Changed LINQ into equivalent loops to prevent delegate allocation. Should result in overall much faster calls.
- Widget.GetEventBounds - Changed LINQ calls into equivalent loops.
- MobileInfo.CanEnterCell - Changed LINQ calls into equivalent loops. Don't materialize list of blocking actors every time, instead enumerate them and only when they need to be checked.
- FrozenUnderFog.TickRender - Generate the renderables lazily and also remove a no-op Select call.
This commit is contained in:
RoosterDragon
2014-05-23 14:48:11 +01:00
parent db08357e36
commit a0db80cb6a
6 changed files with 63 additions and 37 deletions

View File

@@ -121,21 +121,24 @@ namespace OpenRA.Mods.RA.Move
if (SharesCell && world.ActorMap.HasFreeSubCell(cell))
return true;
var blockingActors = world.ActorMap.GetUnitsAt(cell)
.Where(x => x != ignoreActor)
// Neutral/enemy units are blockers. Allied units that are moving are not blockers.
.Where(x => blockedByMovers || (self == null || self.Owner.Stances[x.Owner] != Stance.Ally || !IsMovingInMyDirection(self, x)))
.ToList();
if (checkTransientActors && blockingActors.Count > 0)
if (checkTransientActors)
{
// Non-sharable unit can enter a cell with shareable units only if it can crush all of them
if (self == null || Crushes == null)
return false;
bool canIgnoreMovingAllies = self != null && !blockedByMovers;
bool needsCellExclusively = self == null || Crushes == null;
foreach(var a in world.ActorMap.GetUnitsAt(cell))
{
if (a == ignoreActor) continue;
if (blockingActors.Any(a => !(a.HasTrait<ICrushable>() &&
a.TraitsImplementing<ICrushable>().Any(b => b.CrushableBy(Crushes, self.Owner)))))
return false;
// Neutral/enemy units are blockers. Allied units that are moving are not blockers.
if (canIgnoreMovingAllies && self.Owner.Stances[a.Owner] == Stance.Ally && IsMovingInMyDirection(self, a)) continue;
// Non-sharable unit can enter a cell with shareable units only if it can crush all of them.
if (needsCellExclusively) return false;
if (!a.HasTrait<ICrushable>()) return false;
foreach (var crushable in a.TraitsImplementing<ICrushable>())
if (!crushable.CrushableBy(Crushes, self.Owner))
return false;
}
}
return true;