Update ScreenMap state in a single pass at the end of the tick.

This commit is contained in:
Paul Chote
2017-12-05 17:37:18 +00:00
committed by reaperrr
parent 373aaee004
commit 46f6263061
5 changed files with 82 additions and 18 deletions

View File

@@ -62,6 +62,11 @@ namespace OpenRA.Primitives
return true; return true;
} }
public bool Contains(T item)
{
return itemBounds.ContainsKey(item);
}
Dictionary<T, Rectangle> BinAt(int row, int col) Dictionary<T, Rectangle> BinAt(int row, int col)
{ {
return itemBoundsBins[row * cols + col]; return itemBoundsBins[row * cols + col];

View File

@@ -210,7 +210,7 @@ namespace OpenRA.Traits
public void Add(FrozenActor fa) public void Add(FrozenActor fa)
{ {
frozenActorsById.Add(fa.ID, fa); frozenActorsById.Add(fa.ID, fa);
world.ScreenMap.Add(owner, fa); world.ScreenMap.AddOrUpdate(owner, fa);
partitionedFrozenActorIds.Add(fa.ID, FootprintBounds(fa)); partitionedFrozenActorIds.Add(fa.ID, FootprintBounds(fa));
} }

View File

@@ -35,6 +35,13 @@ namespace OpenRA.Traits
readonly Cache<Player, SpatiallyPartitioned<FrozenActor>> partitionedFrozenActors; readonly Cache<Player, SpatiallyPartitioned<FrozenActor>> partitionedFrozenActors;
readonly SpatiallyPartitioned<Actor> partitionedActors; readonly SpatiallyPartitioned<Actor> partitionedActors;
readonly SpatiallyPartitioned<IEffect> partitionedEffects; readonly SpatiallyPartitioned<IEffect> partitionedEffects;
// Updates are done in one pass to ensure all bound changes have been applied
readonly HashSet<Actor> addOrUpdateActors = new HashSet<Actor>();
readonly HashSet<Actor> removeActors = new HashSet<Actor>();
readonly Cache<Player, HashSet<FrozenActor>> addOrUpdateFrozenActors;
readonly Cache<Player, HashSet<FrozenActor>> removeFrozenActors;
WorldRenderer worldRenderer; WorldRenderer worldRenderer;
public ScreenMap(World world, ScreenMapInfo info) public ScreenMap(World world, ScreenMapInfo info)
@@ -44,6 +51,10 @@ namespace OpenRA.Traits
var height = world.Map.MapSize.Y * size.Height; var height = world.Map.MapSize.Y * size.Height;
partitionedFrozenActors = new Cache<Player, SpatiallyPartitioned<FrozenActor>>( partitionedFrozenActors = new Cache<Player, SpatiallyPartitioned<FrozenActor>>(
_ => new SpatiallyPartitioned<FrozenActor>(width, height, info.BinSize)); _ => new SpatiallyPartitioned<FrozenActor>(width, height, info.BinSize));
addOrUpdateFrozenActors = new Cache<Player, HashSet<FrozenActor>>(_ => new HashSet<FrozenActor>());
removeFrozenActors = new Cache<Player, HashSet<FrozenActor>>(_ => new HashSet<FrozenActor>());
partitionedActors = new SpatiallyPartitioned<Actor>(width, height, info.BinSize); partitionedActors = new SpatiallyPartitioned<Actor>(width, height, info.BinSize);
partitionedEffects = new SpatiallyPartitioned<IEffect>(width, height, info.BinSize); partitionedEffects = new SpatiallyPartitioned<IEffect>(width, height, info.BinSize);
} }
@@ -66,33 +77,30 @@ namespace OpenRA.Traits
return bounds; return bounds;
} }
public void Add(Player viewer, FrozenActor fa) public void AddOrUpdate(Player viewer, FrozenActor fa)
{ {
partitionedFrozenActors[viewer].Add(fa, FrozenActorBounds(fa)); if (removeFrozenActors[viewer].Contains(fa))
removeFrozenActors[viewer].Remove(fa);
addOrUpdateFrozenActors[viewer].Add(fa);
} }
public void Remove(Player viewer, FrozenActor fa) public void Remove(Player viewer, FrozenActor fa)
{ {
partitionedFrozenActors[viewer].Remove(fa); removeFrozenActors[viewer].Add(fa);
} }
public void Add(Actor a) public void AddOrUpdate(Actor a)
{ {
var bounds = ActorBounds(a); if (removeActors.Contains(a))
if (!bounds.Size.IsEmpty) removeActors.Remove(a);
partitionedActors.Add(a, ActorBounds(a));
}
public void Update(Actor a) addOrUpdateActors.Add(a);
{
var bounds = ActorBounds(a);
if (!bounds.Size.IsEmpty)
partitionedActors.Update(a, ActorBounds(a));
} }
public void Remove(Actor a) public void Remove(Actor a)
{ {
partitionedActors.Remove(a); removeActors.Add(a);
} }
public void Add(IEffect effect, WPos position, Size size) public void Add(IEffect effect, WPos position, Size size)
@@ -192,6 +200,56 @@ namespace OpenRA.Traits
return partitionedFrozenActors[p].InBox(r).Where(frozenActorIsValid); return partitionedFrozenActors[p].InBox(r).Where(frozenActorIsValid);
} }
public void Tick()
{
foreach (var a in addOrUpdateActors)
{
var bounds = ActorBounds(a);
if (!bounds.Size.IsEmpty)
{
if (partitionedActors.Contains(a))
partitionedActors.Update(a, bounds);
else
partitionedActors.Add(a, bounds);
}
else
partitionedActors.Remove(a);
}
foreach (var a in removeActors)
partitionedActors.Remove(a);
addOrUpdateActors.Clear();
removeActors.Clear();
foreach (var kv in addOrUpdateFrozenActors)
{
foreach (var fa in kv.Value)
{
var bounds = FrozenActorBounds(fa);
if (!bounds.Size.IsEmpty)
{
if (partitionedFrozenActors[kv.Key].Contains(fa))
partitionedFrozenActors[kv.Key].Update(fa, bounds);
else
partitionedFrozenActors[kv.Key].Add(fa, bounds);
}
else
partitionedFrozenActors[kv.Key].Remove(fa);
}
kv.Value.Clear();
}
foreach (var kv in removeFrozenActors)
{
foreach (var fa in kv.Value)
partitionedFrozenActors[kv.Key].Remove(fa);
kv.Value.Clear();
}
}
public IEnumerable<Rectangle> ItemBounds(Player viewer) public IEnumerable<Rectangle> ItemBounds(Player viewer)
{ {
var bounds = partitionedActors.ItemBounds var bounds = partitionedActors.ItemBounds

View File

@@ -191,7 +191,7 @@ namespace OpenRA
{ {
ActorMap.AddInfluence(self, ios); ActorMap.AddInfluence(self, ios);
ActorMap.AddPosition(self, ios); ActorMap.AddPosition(self, ios);
ScreenMap.Add(self); ScreenMap.AddOrUpdate(self);
} }
public void UpdateMaps(Actor self, IOccupySpace ios) public void UpdateMaps(Actor self, IOccupySpace ios)
@@ -199,7 +199,7 @@ namespace OpenRA
if (!self.IsInWorld) if (!self.IsInWorld)
return; return;
ScreenMap.Update(self); ScreenMap.AddOrUpdate(self);
ActorMap.UpdatePosition(self, ios); ActorMap.UpdatePosition(self, ios);
} }
@@ -353,6 +353,7 @@ namespace OpenRA
ActorsWithTrait<ITick>().DoTimed(x => x.Trait.Tick(x.Actor), "Trait"); ActorsWithTrait<ITick>().DoTimed(x => x.Trait.Tick(x.Actor), "Trait");
effects.DoTimed(e => e.Tick(this), "Effect"); effects.DoTimed(e => e.Tick(this), "Effect");
ScreenMap.Tick();
} }
while (frameEndActions.Count != 0) while (frameEndActions.Count != 0)

View File

@@ -105,7 +105,7 @@ namespace OpenRA.Mods.Common.Traits
public void SetVisualPosition(Actor self, WPos pos) public void SetVisualPosition(Actor self, WPos pos)
{ {
CenterPosition = pos; CenterPosition = pos;
self.World.ScreenMap.Update(self); self.World.ScreenMap.AddOrUpdate(self);
} }
public void SetPosition(Actor self, WPos pos) public void SetPosition(Actor self, WPos pos)