Files
OpenRA/OpenRA.Game/Traits/Player/FrozenActorLayer.cs
RoosterDragon a0db80cb6a 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.
2014-05-23 14:48:11 +01:00

160 lines
3.5 KiB
C#
Executable File

#region Copyright & License Information
/*
* Copyright 2007-2013 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using OpenRA.Graphics;
namespace OpenRA.Traits
{
public class FrozenActorLayerInfo : ITraitInfo
{
public object Create(ActorInitializer init) { return new FrozenActorLayer(init.self); }
}
public class FrozenActor
{
public readonly CPos[] Footprint;
public readonly WPos CenterPosition;
public readonly Rectangle Bounds;
readonly Actor actor;
public IRenderable[] Renderables { set; private get; }
public Player Owner;
public string TooltipName;
public Player TooltipOwner;
public int HP;
public DamageState DamageState;
public bool Visible;
public FrozenActor(Actor self, IEnumerable<CPos> footprint)
{
actor = self;
Footprint = footprint.ToArray();
CenterPosition = self.CenterPosition;
Bounds = self.Bounds.Value;
}
public uint ID { get { return actor.ActorID; } }
public bool IsValid { get { return Owner != null; } }
public ActorInfo Info { get { return actor.Info; } }
public Actor Actor { get { return !actor.IsDead() ? actor : null; } }
int flashTicks;
public void Tick(World world, Shroud shroud)
{
Visible = false;
foreach (var pos in Footprint)
if (shroud.IsVisible(pos))
{
Visible = true;
break;
}
if (flashTicks > 0)
flashTicks--;
}
public void Flash()
{
flashTicks = 5;
}
public IEnumerable<IRenderable> Render(WorldRenderer wr)
{
if (Renderables == null)
return SpriteRenderable.None;
if (flashTicks > 0 && flashTicks % 2 == 0)
{
var highlight = wr.Palette("highlight");
return Renderables.Concat(Renderables.Where(r => !r.IsDecoration)
.Select(r => r.WithPalette(highlight)));
}
return Renderables;
}
public bool HasRenderables { get { return Renderables != null; } }
public override string ToString()
{
return "{0} {1}{2}".F(Info.Name, ID, IsValid ? "" : " (invalid)");
}
}
public class FrozenActorLayer : IRender, ITick, ISync
{
[Sync] public int VisibilityHash;
[Sync] public int FrozenHash;
readonly World world;
readonly Player owner;
Dictionary<uint, FrozenActor> frozen;
public FrozenActorLayer(Actor self)
{
world = self.World;
owner = self.Owner;
frozen = new Dictionary<uint, FrozenActor>();
}
public void Add(FrozenActor fa)
{
frozen.Add(fa.ID, fa);
world.ScreenMap.Add(owner, fa);
}
public void Tick(Actor self)
{
var remove = new List<uint>();
VisibilityHash = 0;
FrozenHash = 0;
foreach (var kv in frozen)
{
FrozenHash += (int)kv.Key;
kv.Value.Tick(self.World, self.Owner.Shroud);
if (kv.Value.Visible)
VisibilityHash += (int)kv.Key;
if (!kv.Value.Visible && kv.Value.Actor == null)
remove.Add(kv.Key);
}
foreach (var r in remove)
{
world.ScreenMap.Remove(owner, frozen[r]);
frozen.Remove(r);
}
}
public virtual IEnumerable<IRenderable> Render(Actor self, WorldRenderer wr)
{
return world.ScreenMap.FrozenActorsInBox(owner, wr.Viewport.TopLeft, wr.Viewport.BottomRight)
.Where(f => f.Visible)
.SelectMany(ff => ff.Render(wr));
}
public FrozenActor FromID(uint id)
{
FrozenActor ret;
if (!frozen.TryGetValue(id, out ret))
return null;
return ret;
}
}
}