diff --git a/OpenRA.Game/OpenRA.Game.csproj b/OpenRA.Game/OpenRA.Game.csproj
index fa6d6941db..ca101ce3fc 100644
--- a/OpenRA.Game/OpenRA.Game.csproj
+++ b/OpenRA.Game/OpenRA.Game.csproj
@@ -169,7 +169,6 @@
-
@@ -177,7 +176,6 @@
-
diff --git a/OpenRA.Game/Traits/CreatesShroud.cs b/OpenRA.Game/Traits/CreatesShroud.cs
deleted file mode 100644
index 2b6a28b5fc..0000000000
--- a/OpenRA.Game/Traits/CreatesShroud.cs
+++ /dev/null
@@ -1,51 +0,0 @@
-#region Copyright & License Information
-/*
- * Copyright 2007-2015 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.Linq;
-
-namespace OpenRA.Traits
-{
- public class CreatesShroudInfo : ITraitInfo
- {
- public readonly WRange Range = WRange.Zero;
-
- public object Create(ActorInitializer init) { return new CreatesShroud(init.Self, this); }
- }
-
- public class CreatesShroud : ITick, ISync
- {
- readonly CreatesShroudInfo info;
- readonly bool lobbyShroudFogDisabled;
- [Sync] CPos cachedLocation;
- [Sync] bool cachedDisabled;
-
- public CreatesShroud(Actor self, CreatesShroudInfo info)
- {
- this.info = info;
- lobbyShroudFogDisabled = !self.World.LobbyInfo.GlobalSettings.Shroud && !self.World.LobbyInfo.GlobalSettings.Fog;
- }
-
- public void Tick(Actor self)
- {
- if (lobbyShroudFogDisabled)
- return;
-
- var disabled = self.IsDisabled();
- if (cachedLocation != self.Location || cachedDisabled != disabled)
- {
- cachedLocation = self.Location;
- cachedDisabled = disabled;
- Shroud.UpdateShroudGeneration(self.World.Players.Select(p => p.Shroud), self);
- }
- }
-
- public WRange Range { get { return cachedDisabled ? WRange.Zero : info.Range; } }
- }
-}
\ No newline at end of file
diff --git a/OpenRA.Game/Traits/RevealsShroud.cs b/OpenRA.Game/Traits/RevealsShroud.cs
deleted file mode 100644
index cea05d54f4..0000000000
--- a/OpenRA.Game/Traits/RevealsShroud.cs
+++ /dev/null
@@ -1,48 +0,0 @@
-#region Copyright & License Information
-/*
- * Copyright 2007-2015 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.Linq;
-
-namespace OpenRA.Traits
-{
- public class RevealsShroudInfo : ITraitInfo
- {
- public readonly WRange Range = WRange.Zero;
-
- public object Create(ActorInitializer init) { return new RevealsShroud(init.Self, this); }
- }
-
- public class RevealsShroud : ITick, ISync
- {
- readonly RevealsShroudInfo info;
- readonly bool lobbyShroudFogDisabled;
- [Sync] CPos cachedLocation;
-
- public RevealsShroud(Actor self, RevealsShroudInfo info)
- {
- this.info = info;
- lobbyShroudFogDisabled = !self.World.LobbyInfo.GlobalSettings.Shroud && !self.World.LobbyInfo.GlobalSettings.Fog;
- }
-
- public void Tick(Actor self)
- {
- if (lobbyShroudFogDisabled)
- return;
-
- if (cachedLocation != self.Location)
- {
- cachedLocation = self.Location;
- Shroud.UpdateVisibility(self.World.Players.Select(p => p.Shroud), self);
- }
- }
-
- public WRange Range { get { return info.Range; } }
- }
-}
diff --git a/OpenRA.Game/Traits/World/Shroud.cs b/OpenRA.Game/Traits/World/Shroud.cs
index ad8a58a5b3..473a1731b4 100644
--- a/OpenRA.Game/Traits/World/Shroud.cs
+++ b/OpenRA.Game/Traits/World/Shroud.cs
@@ -54,12 +54,6 @@ namespace OpenRA.Traits
generatedShroudCount = new CellLayer(map);
explored = new CellLayer(map);
- self.World.ActorAdded += a => { CPos[] visible = null; AddVisibility(a, ref visible); };
- self.World.ActorRemoved += RemoveVisibility;
-
- self.World.ActorAdded += a => { CPos[] shrouded = null; AddShroudGeneration(a, ref shrouded); };
- self.World.ActorRemoved += RemoveShroudGeneration;
-
shroudEdgeTest = map.Contains;
isExploredTest = IsExploredCore;
isVisibleTest = IsVisibleCore;
@@ -78,46 +72,27 @@ namespace OpenRA.Traits
Hash += 1;
}
- public static void UpdateVisibility(IEnumerable shrouds, Actor actor)
+ public static IEnumerable CellsInRange(Map map, WPos pos, WRange range)
{
- CPos[] visbility = null;
- foreach (var shroud in shrouds)
- shroud.UpdateVisibility(actor, ref visbility);
+ var r = (range.Range + 1023) / 1024;
+ var limit = range.RangeSquared;
+ var cell = map.CellContaining(pos);
+
+ foreach (var c in map.FindTilesInCircle(cell, r, true))
+ if ((map.CenterOfCell(c) - pos).HorizontalLengthSquared <= limit)
+ yield return c;
}
- public static void UpdateShroudGeneration(IEnumerable shrouds, Actor actor)
+ public static IEnumerable CellsInRange(Map map, CPos cell, WRange range)
{
- CPos[] shrouded = null;
- foreach (var shroud in shrouds)
- shroud.UpdateShroudGeneration(actor, ref shrouded);
+ return CellsInRange(map, map.CenterOfCell(cell), range);
}
- static CPos[] FindVisibleTiles(Actor actor, WRange range)
+ public void AddVisibility(Actor a, CPos[] visible)
{
- return GetVisOrigins(actor).SelectMany(o => FindVisibleTiles(actor.World, o, range)).Distinct().ToArray();
- }
-
- static IEnumerable FindVisibleTiles(World world, CPos position, WRange radius)
- {
- var map = world.Map;
- var r = (radius.Range + 1023) / 1024;
- var limit = radius.RangeSquared;
- var pos = map.CenterOfCell(position);
-
- foreach (var cell in map.FindTilesInCircle(position, r, true))
- if ((map.CenterOfCell(cell) - pos).HorizontalLengthSquared <= limit)
- yield return cell;
- }
-
- void AddVisibility(Actor a, ref CPos[] visible)
- {
- var rs = a.TraitOrDefault();
- if (rs == null || !a.Owner.IsAlliedWith(self.Owner) || rs.Range == WRange.Zero)
+ if (!a.Owner.IsAlliedWith(self.Owner))
return;
- // Lazily generate the visible tiles, allowing the caller to re-use them if desired.
- visible = visible ?? FindVisibleTiles(a, rs.Range);
-
foreach (var c in visible)
{
var uv = c.ToMPos(map);
@@ -137,7 +112,7 @@ namespace OpenRA.Traits
Invalidate(visible);
}
- void RemoveVisibility(Actor a)
+ public void RemoveVisibility(Actor a)
{
CPos[] visible;
if (!visibility.TryGetValue(a, out visible))
@@ -154,25 +129,11 @@ namespace OpenRA.Traits
Invalidate(visible);
}
- void UpdateVisibility(Actor a, ref CPos[] visible)
+ public void AddShroudGeneration(Actor a, CPos[] shrouded)
{
- // Actors outside the world don't have any vis
- if (!a.IsInWorld)
+ if (a.Owner.IsAlliedWith(self.Owner))
return;
- RemoveVisibility(a);
- AddVisibility(a, ref visible);
- }
-
- void AddShroudGeneration(Actor a, ref CPos[] shrouded)
- {
- var cs = a.TraitOrDefault();
- if (cs == null || a.Owner.IsAlliedWith(self.Owner) || cs.Range == WRange.Zero)
- return;
-
- // Lazily generate the shrouded tiles, allowing the caller to re-use them if desired.
- shrouded = shrouded ?? FindVisibleTiles(a, cs.Range);
-
foreach (var c in shrouded)
generatedShroudCount[c]++;
@@ -183,7 +144,7 @@ namespace OpenRA.Traits
Invalidate(shrouded);
}
- void RemoveShroudGeneration(Actor a)
+ public void RemoveShroudGeneration(Actor a)
{
CPos[] shrouded;
if (!generation.TryGetValue(a, out shrouded))
@@ -196,12 +157,6 @@ namespace OpenRA.Traits
Invalidate(shrouded);
}
- void UpdateShroudGeneration(Actor a, ref CPos[] shrouded)
- {
- RemoveShroudGeneration(a);
- AddShroudGeneration(a, ref shrouded);
- }
-
public void UpdatePlayerStance(World w, Player player, Stance oldStance, Stance newStance)
{
if (oldStance == newStance)
@@ -210,12 +165,26 @@ namespace OpenRA.Traits
foreach (var a in w.Actors.Where(a => a.Owner == player))
{
CPos[] visible = null;
- UpdateVisibility(a, ref visible);
CPos[] shrouded = null;
- UpdateShroudGeneration(a, ref shrouded);
+ foreach (var p in self.World.Players)
+ {
+ if (p.Shroud.visibility.TryGetValue(self, out visible))
+ {
+ p.Shroud.RemoveVisibility(self);
+ p.Shroud.AddVisibility(self, visible);
+ }
+
+ if (p.Shroud.generation.TryGetValue(self, out shrouded))
+ {
+ p.Shroud.RemoveShroudGeneration(self);
+ p.Shroud.AddShroudGeneration(self, shrouded);
+ }
+ }
}
}
+ // TODO: Actor vis will be split into separate cases for
+ // "cells that I reveal from" and "cells that reveal me"
public static IEnumerable GetVisOrigins(Actor a)
{
var ios = a.OccupiesSpace;
@@ -229,10 +198,10 @@ namespace OpenRA.Traits
return new[] { a.World.Map.CellContaining(a.CenterPosition) };
}
- public void Explore(World world, CPos center, WRange range)
+ public void Explore(World world, IEnumerable cells)
{
- var changed = new List();
- foreach (var c in FindVisibleTiles(world, center, range))
+ var changed = new HashSet();
+ foreach (var c in cells)
{
if (!explored[c])
{
diff --git a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj
index 7ddbb3a6a0..bfd03510a5 100644
--- a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj
+++ b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj
@@ -681,6 +681,8 @@
+
+
diff --git a/OpenRA.Mods.Common/Traits/CreatesShroud.cs b/OpenRA.Mods.Common/Traits/CreatesShroud.cs
new file mode 100644
index 0000000000..862a599175
--- /dev/null
+++ b/OpenRA.Mods.Common/Traits/CreatesShroud.cs
@@ -0,0 +1,28 @@
+#region Copyright & License Information
+/*
+ * Copyright 2007-2015 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
+
+namespace OpenRA.Mods.Common.Traits
+{
+ public class CreatesShroudInfo : RevealsShroudInfo
+ {
+ public override object Create(ActorInitializer init) { return new CreatesShroud(init.Self, this); }
+ }
+
+ public class CreatesShroud : RevealsShroud
+ {
+ public CreatesShroud(Actor self, CreatesShroudInfo info)
+ : base(self, info)
+ {
+ addCellsToPlayerShroud = (p, c) => p.Shroud.AddShroudGeneration(self, c);
+ removeCellsFromPlayerShroud = p => p.Shroud.RemoveShroudGeneration(self);
+ isDisabled = () => self.IsDisabled();
+ }
+ }
+}
\ No newline at end of file
diff --git a/OpenRA.Mods.Common/Traits/RevealsShroud.cs b/OpenRA.Mods.Common/Traits/RevealsShroud.cs
new file mode 100644
index 0000000000..0c5ba61cf0
--- /dev/null
+++ b/OpenRA.Mods.Common/Traits/RevealsShroud.cs
@@ -0,0 +1,98 @@
+#region Copyright & License Information
+/*
+ * Copyright 2007-2015 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;
+using System.Linq;
+using OpenRA.Traits;
+
+namespace OpenRA.Mods.Common.Traits
+{
+ public class RevealsShroudInfo : ITraitInfo
+ {
+ public readonly WRange Range = WRange.Zero;
+
+ public virtual object Create(ActorInitializer init) { return new RevealsShroud(init.Self, this); }
+ }
+
+ public class RevealsShroud : ITick, ISync, INotifyAddedToWorld, INotifyRemovedFromWorld
+ {
+ static readonly CPos[] NoCells = { };
+
+ readonly RevealsShroudInfo info;
+ readonly bool lobbyShroudFogDisabled;
+ [Sync] CPos cachedLocation;
+ [Sync] bool cachedDisabled;
+
+ protected Action addCellsToPlayerShroud;
+ protected Action removeCellsFromPlayerShroud;
+ protected Func isDisabled;
+
+ public RevealsShroud(Actor self, RevealsShroudInfo info)
+ {
+ this.info = info;
+ lobbyShroudFogDisabled = !self.World.LobbyInfo.GlobalSettings.Shroud && !self.World.LobbyInfo.GlobalSettings.Fog;
+
+ addCellsToPlayerShroud = (p, c) => p.Shroud.AddVisibility(self, c);
+ removeCellsFromPlayerShroud = p => p.Shroud.RemoveVisibility(self);
+ isDisabled = () => false;
+ }
+
+ CPos[] Cells(Actor self)
+ {
+ var map = self.World.Map;
+ var range = Range;
+ if (range == WRange.Zero)
+ return NoCells;
+
+ return Shroud.GetVisOrigins(self)
+ .SelectMany(c => Shroud.CellsInRange(map, c, range))
+ .Distinct().ToArray();
+ }
+
+ public void Tick(Actor self)
+ {
+ if (lobbyShroudFogDisabled || !self.IsInWorld)
+ return;
+
+ var location = self.Location;
+ var disabled = isDisabled();
+ if (cachedLocation == location && cachedDisabled == disabled)
+ return;
+
+ cachedLocation = location;
+ cachedDisabled = disabled;
+
+ var cells = Cells(self);
+ foreach (var p in self.World.Players)
+ {
+ removeCellsFromPlayerShroud(p);
+ addCellsToPlayerShroud(p, cells);
+ }
+ }
+
+ public void AddedToWorld(Actor self)
+ {
+ cachedLocation = self.Location;
+ cachedDisabled = isDisabled();
+
+ var cells = Cells(self);
+ foreach (var p in self.World.Players)
+ addCellsToPlayerShroud(p, cells);
+ }
+
+ public void RemovedFromWorld(Actor self)
+ {
+ foreach (var p in self.World.Players)
+ removeCellsFromPlayerShroud(p);
+ }
+
+ public WRange Range { get { return cachedDisabled ? WRange.Zero : info.Range; } }
+ }
+}
diff --git a/OpenRA.Mods.Common/Traits/World/MPStartLocations.cs b/OpenRA.Mods.Common/Traits/World/MPStartLocations.cs
index db50067aae..3cd90e25ad 100644
--- a/OpenRA.Mods.Common/Traits/World/MPStartLocations.cs
+++ b/OpenRA.Mods.Common/Traits/World/MPStartLocations.cs
@@ -17,14 +17,23 @@ using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits
{
- public class MPStartLocationsInfo : TraitInfo
+ public class MPStartLocationsInfo : ITraitInfo
{
public readonly WRange InitialExploreRange = WRange.FromCells(5);
+
+ public virtual object Create(ActorInitializer init) { return new MPStartLocations(this); }
}
public class MPStartLocations : IWorldLoaded
{
- public Dictionary Start = new Dictionary();
+ readonly MPStartLocationsInfo info;
+
+ public readonly Dictionary Start = new Dictionary();
+
+ public MPStartLocations(MPStartLocationsInfo info)
+ {
+ this.info = info;
+ }
public void WorldLoaded(World world, WorldRenderer wr)
{
@@ -52,15 +61,18 @@ namespace OpenRA.Mods.Common.Traits
}
// Explore allied shroud
- var explore = world.WorldActor.Info.Traits.Get().InitialExploreRange;
+ var map = world.Map;
foreach (var p in Start.Keys)
+ {
+ var cells = Shroud.CellsInRange(map, Start[p], info.InitialExploreRange);
foreach (var q in world.Players)
if (p.IsAlliedWith(q))
- q.Shroud.Explore(world, Start[p], explore);
+ q.Shroud.Explore(world, cells);
+ }
// Set viewport
if (world.LocalPlayer != null && Start.ContainsKey(world.LocalPlayer))
- wr.Viewport.Center(world.Map.CenterOfCell(Start[world.LocalPlayer]));
+ wr.Viewport.Center(map.CenterOfCell(Start[world.LocalPlayer]));
}
static Player FindPlayerInSlot(World world, string pr)