Merge pull request #5433 from RoosterDragon/main-loop-alloc
Reduce memory allocations in the main loop.
This commit is contained in:
@@ -81,9 +81,6 @@ namespace OpenRA
|
||||
health = Exts.Lazy(() => TraitOrDefault<Health>());
|
||||
effectiveOwner = Exts.Lazy(() => TraitOrDefault<IEffectiveOwner>());
|
||||
|
||||
applyIRender = (x, wr) => x.Render(this, wr);
|
||||
applyRenderModifier = (m, p, wr) => p.ModifyRender(this, wr, m);
|
||||
|
||||
Bounds = Exts.Lazy(() =>
|
||||
{
|
||||
var si = Info.Traits.GetOrDefault<SelectableInfo>();
|
||||
@@ -112,14 +109,19 @@ namespace OpenRA
|
||||
get { return currentActivity == null; }
|
||||
}
|
||||
|
||||
// note: these delegates are cached to avoid massive allocation.
|
||||
Func<IRender, WorldRenderer, IEnumerable<IRenderable>> applyIRender;
|
||||
Func<IEnumerable<IRenderable>, IRenderModifier, WorldRenderer, IEnumerable<IRenderable>> applyRenderModifier;
|
||||
public IEnumerable<IRenderable> Render(WorldRenderer wr)
|
||||
{
|
||||
var mods = TraitsImplementing<IRenderModifier>();
|
||||
var sprites = TraitsImplementing<IRender>().SelectMany(x => applyIRender(x, wr));
|
||||
return mods.Aggregate(sprites, (m, p) => applyRenderModifier(m, p, wr));
|
||||
var renderables = Renderables(wr);
|
||||
foreach (var modifier in TraitsImplementing<IRenderModifier>())
|
||||
renderables = modifier.ModifyRender(this, wr, renderables);
|
||||
return renderables;
|
||||
}
|
||||
|
||||
IEnumerable<IRenderable> Renderables(WorldRenderer wr)
|
||||
{
|
||||
foreach (var render in TraitsImplementing<IRender>())
|
||||
foreach (var renderable in render.Render(this, wr))
|
||||
yield return renderable;
|
||||
}
|
||||
|
||||
public bool IsInWorld { get; internal set; }
|
||||
|
||||
@@ -49,13 +49,16 @@ namespace OpenRA.Graphics
|
||||
|
||||
public IEnumerable<IRenderable> Render(WPos pos, WVec offset, int zOffset, PaletteReference palette, float scale)
|
||||
{
|
||||
var imageRenderable = new SpriteRenderable(Image, pos, offset, CurrentSequence.ZOffset + zOffset, palette, scale, IsDecoration);
|
||||
|
||||
if (CurrentSequence.ShadowStart >= 0)
|
||||
{
|
||||
var shadow = CurrentSequence.GetShadow(CurrentFrame, facingFunc());
|
||||
yield return new SpriteRenderable(shadow, pos, offset, CurrentSequence.ShadowZOffset + zOffset, palette, scale, true);
|
||||
var shadowRenderable = new SpriteRenderable(shadow, pos, offset, CurrentSequence.ShadowZOffset + zOffset, palette, scale, true);
|
||||
return new IRenderable[] { shadowRenderable, imageRenderable };
|
||||
}
|
||||
|
||||
yield return new SpriteRenderable(Image, pos, offset, CurrentSequence.ZOffset + zOffset, palette, scale, IsDecoration);
|
||||
return new IRenderable[] { imageRenderable };
|
||||
}
|
||||
|
||||
public IEnumerable<IRenderable> Render(WPos pos, PaletteReference palette)
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace OpenRA.Traits
|
||||
|
||||
public class FrozenActor
|
||||
{
|
||||
public readonly IEnumerable<CPos> Footprint;
|
||||
public readonly CPos[] Footprint;
|
||||
public readonly WPos CenterPosition;
|
||||
public readonly Rectangle Bounds;
|
||||
readonly Actor actor;
|
||||
@@ -41,7 +41,7 @@ namespace OpenRA.Traits
|
||||
public FrozenActor(Actor self, IEnumerable<CPos> footprint)
|
||||
{
|
||||
actor = self;
|
||||
Footprint = footprint;
|
||||
Footprint = footprint.ToArray();
|
||||
CenterPosition = self.CenterPosition;
|
||||
Bounds = self.Bounds.Value;
|
||||
}
|
||||
@@ -54,7 +54,13 @@ namespace OpenRA.Traits
|
||||
int flashTicks;
|
||||
public void Tick(World world, Shroud shroud)
|
||||
{
|
||||
Visible = !Footprint.Any(c => shroud.IsVisible(c));
|
||||
Visible = false;
|
||||
foreach (var pos in Footprint)
|
||||
if (shroud.IsVisible(pos))
|
||||
{
|
||||
Visible = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (flashTicks > 0)
|
||||
flashTicks--;
|
||||
|
||||
@@ -237,10 +237,11 @@ namespace OpenRA.Widgets
|
||||
|
||||
public virtual Rectangle GetEventBounds()
|
||||
{
|
||||
return Children
|
||||
.Where(c => c.IsVisible())
|
||||
.Select(c => c.GetEventBounds())
|
||||
.Aggregate(EventBounds, Rectangle.Union);
|
||||
var bounds = EventBounds;
|
||||
foreach (var child in Children)
|
||||
if (child.IsVisible())
|
||||
bounds = Rectangle.Union(bounds, child.GetEventBounds());
|
||||
return bounds;
|
||||
}
|
||||
|
||||
public bool HasMouseFocus { get { return Ui.MouseFocusWidget == this; } }
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace OpenRA.Mods.RA
|
||||
[Sync] public int VisibilityHash;
|
||||
|
||||
bool initialized, startsRevealed;
|
||||
IEnumerable<CPos> footprint;
|
||||
readonly CPos[] footprint;
|
||||
Lazy<IToolTip> tooltip;
|
||||
Lazy<Health> health;
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace OpenRA.Mods.RA
|
||||
{
|
||||
// Spawned actors (e.g. building husks) shouldn't be revealed
|
||||
startsRevealed = info.StartsRevealed && !init.Contains<ParentActorInit>();
|
||||
footprint = FootprintUtils.Tiles(init.self);
|
||||
footprint = FootprintUtils.Tiles(init.self).ToArray();
|
||||
tooltip = Exts.Lazy(() => init.self.TraitsImplementing<IToolTip>().FirstOrDefault());
|
||||
tooltip = Exts.Lazy(() => init.self.TraitsImplementing<IToolTip>().FirstOrDefault());
|
||||
health = Exts.Lazy(() => init.self.TraitOrDefault<Health>());
|
||||
@@ -63,8 +63,15 @@ namespace OpenRA.Mods.RA
|
||||
VisibilityHash = 0;
|
||||
foreach (var p in self.World.Players)
|
||||
{
|
||||
visible[p] = footprint.Any(c => p.Shroud.IsVisible(c));
|
||||
if (visible[p])
|
||||
var isVisible = false;
|
||||
foreach (var pos in footprint)
|
||||
if (p.Shroud.IsVisible(pos))
|
||||
{
|
||||
isVisible = true;
|
||||
break;
|
||||
}
|
||||
visible[p] = isVisible;
|
||||
if (isVisible)
|
||||
VisibilityHash += p.ClientIndex;
|
||||
}
|
||||
|
||||
@@ -106,11 +113,15 @@ namespace OpenRA.Mods.RA
|
||||
if (self.Destroyed || !initialized || !visible.Any(v => v.Value))
|
||||
return;
|
||||
|
||||
// Force a copy of the underlying data
|
||||
var renderables = self.Render(wr).Select(rr => rr).ToArray();
|
||||
IRenderable[] renderables = null;
|
||||
foreach (var player in self.World.Players)
|
||||
if (visible[player])
|
||||
{
|
||||
// Lazily generate a copy of the underlying data.
|
||||
if (renderables == null)
|
||||
renderables = self.Render(wr).ToArray();
|
||||
frozen[player].Renderables = renderables;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<IRenderable> ModifyRender(Actor self, WorldRenderer wr, IEnumerable<IRenderable> r)
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user