Convert shroud calculations and rendering to PPos.
This commit is contained in:
@@ -24,7 +24,7 @@ namespace OpenRA.Traits
|
|||||||
|
|
||||||
public class FrozenActor
|
public class FrozenActor
|
||||||
{
|
{
|
||||||
public readonly MPos[] Footprint;
|
public readonly PPos[] Footprint;
|
||||||
public readonly WPos CenterPosition;
|
public readonly WPos CenterPosition;
|
||||||
public readonly Rectangle Bounds;
|
public readonly Rectangle Bounds;
|
||||||
readonly Actor actor;
|
readonly Actor actor;
|
||||||
@@ -42,7 +42,7 @@ namespace OpenRA.Traits
|
|||||||
public bool NeedRenderables;
|
public bool NeedRenderables;
|
||||||
public bool IsRendering { get; private set; }
|
public bool IsRendering { get; private set; }
|
||||||
|
|
||||||
public FrozenActor(Actor self, MPos[] footprint, Shroud shroud)
|
public FrozenActor(Actor self, PPos[] footprint, Shroud shroud)
|
||||||
{
|
{
|
||||||
actor = self;
|
actor = self;
|
||||||
this.shroud = shroud;
|
this.shroud = shroud;
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ namespace OpenRA.Traits
|
|||||||
{
|
{
|
||||||
[Sync] public bool Disabled;
|
[Sync] public bool Disabled;
|
||||||
|
|
||||||
public event Action<IEnumerable<CPos>> CellsChanged;
|
public event Action<IEnumerable<PPos>> CellsChanged;
|
||||||
|
|
||||||
readonly Actor self;
|
readonly Actor self;
|
||||||
readonly Map map;
|
readonly Map map;
|
||||||
@@ -35,15 +35,15 @@ namespace OpenRA.Traits
|
|||||||
|
|
||||||
// Cache of visibility that was added, so no matter what crazy trait code does, it
|
// Cache of visibility that was added, so no matter what crazy trait code does, it
|
||||||
// can't make us invalid.
|
// can't make us invalid.
|
||||||
readonly Dictionary<Actor, CPos[]> visibility = new Dictionary<Actor, CPos[]>();
|
readonly Dictionary<Actor, PPos[]> visibility = new Dictionary<Actor, PPos[]>();
|
||||||
readonly Dictionary<Actor, CPos[]> generation = new Dictionary<Actor, CPos[]>();
|
readonly Dictionary<Actor, PPos[]> generation = new Dictionary<Actor, PPos[]>();
|
||||||
|
|
||||||
public int Hash { get; private set; }
|
public int Hash { get; private set; }
|
||||||
|
|
||||||
static readonly Func<MPos, bool> TruthPredicate = _ => true;
|
static readonly Func<PPos, bool> TruthPredicate = _ => true;
|
||||||
readonly Func<MPos, bool> shroudEdgeTest;
|
readonly Func<PPos, bool> shroudEdgeTest;
|
||||||
readonly Func<MPos, bool> isExploredTest;
|
readonly Func<PPos, bool> isExploredTest;
|
||||||
readonly Func<MPos, bool> isVisibleTest;
|
readonly Func<PPos, bool> isVisibleTest;
|
||||||
|
|
||||||
public Shroud(Actor self)
|
public Shroud(Actor self)
|
||||||
{
|
{
|
||||||
@@ -55,11 +55,12 @@ namespace OpenRA.Traits
|
|||||||
explored = new CellLayer<bool>(map);
|
explored = new CellLayer<bool>(map);
|
||||||
|
|
||||||
shroudEdgeTest = map.Contains;
|
shroudEdgeTest = map.Contains;
|
||||||
isExploredTest = IsExploredCore;
|
|
||||||
isVisibleTest = IsVisibleCore;
|
isExploredTest = IsExplored;
|
||||||
|
isVisibleTest = IsVisible;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Invalidate(IEnumerable<CPos> changed)
|
void Invalidate(IEnumerable<PPos> changed)
|
||||||
{
|
{
|
||||||
if (CellsChanged != null)
|
if (CellsChanged != null)
|
||||||
CellsChanged(changed);
|
CellsChanged(changed);
|
||||||
@@ -72,35 +73,38 @@ namespace OpenRA.Traits
|
|||||||
Hash += 1;
|
Hash += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IEnumerable<CPos> CellsInRange(Map map, WPos pos, WDist range)
|
public static IEnumerable<PPos> ProjectedCellsInRange(Map map, WPos pos, WDist range)
|
||||||
{
|
{
|
||||||
var r = (range.Length + 1023) / 1024;
|
// Account for potential extra half-cell from odd-height terrain
|
||||||
|
var r = (range.Length + 1023 + 512) / 1024;
|
||||||
var limit = range.LengthSquared;
|
var limit = range.LengthSquared;
|
||||||
var cell = map.CellContaining(pos);
|
|
||||||
|
|
||||||
foreach (var c in map.FindTilesInCircle(cell, r, true))
|
// Project actor position into the shroud plane
|
||||||
if ((map.CenterOfCell(c) - pos).HorizontalLengthSquared <= limit)
|
var projectedPos = pos - new WVec(0, pos.Z, pos.Z);
|
||||||
yield return c;
|
var projectedCell = map.CellContaining(projectedPos);
|
||||||
|
|
||||||
|
foreach (var c in map.FindTilesInCircle(projectedCell, r, true))
|
||||||
|
if ((map.CenterOfCell(c) - projectedPos).HorizontalLengthSquared <= limit)
|
||||||
|
yield return (PPos)c.ToMPos(map);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IEnumerable<CPos> CellsInRange(Map map, CPos cell, WDist range)
|
public static IEnumerable<PPos> ProjectedCellsInRange(Map map, CPos cell, WDist range)
|
||||||
{
|
{
|
||||||
return CellsInRange(map, map.CenterOfCell(cell), range);
|
return ProjectedCellsInRange(map, map.CenterOfCell(cell), range);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddVisibility(Actor a, CPos[] visible)
|
public void AddProjectedVisibility(Actor a, PPos[] visible)
|
||||||
{
|
{
|
||||||
if (!a.Owner.IsAlliedWith(self.Owner))
|
if (!a.Owner.IsAlliedWith(self.Owner))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
foreach (var c in visible)
|
foreach (var puv in visible)
|
||||||
{
|
{
|
||||||
var uv = c.ToMPos(map);
|
|
||||||
|
|
||||||
// Force cells outside the visible bounds invisible
|
// Force cells outside the visible bounds invisible
|
||||||
if (!map.Contains(uv))
|
if (!map.Contains(puv))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
var uv = (MPos)puv;
|
||||||
visibleCount[uv]++;
|
visibleCount[uv]++;
|
||||||
explored[uv] = true;
|
explored[uv] = true;
|
||||||
}
|
}
|
||||||
@@ -114,28 +118,28 @@ namespace OpenRA.Traits
|
|||||||
|
|
||||||
public void RemoveVisibility(Actor a)
|
public void RemoveVisibility(Actor a)
|
||||||
{
|
{
|
||||||
CPos[] visible;
|
PPos[] visible;
|
||||||
if (!visibility.TryGetValue(a, out visible))
|
if (!visibility.TryGetValue(a, out visible))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
foreach (var c in visible)
|
foreach (var puv in visible)
|
||||||
{
|
{
|
||||||
// Cells outside the visible bounds don't increment visibleCount
|
// Cells outside the visible bounds don't increment visibleCount
|
||||||
if (map.Contains(c))
|
if (map.Contains(puv))
|
||||||
visibleCount[c.ToMPos(map)]--;
|
visibleCount[(MPos)puv]--;
|
||||||
}
|
}
|
||||||
|
|
||||||
visibility.Remove(a);
|
visibility.Remove(a);
|
||||||
Invalidate(visible);
|
Invalidate(visible);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddShroudGeneration(Actor a, CPos[] shrouded)
|
public void AddProjectedShroudGeneration(Actor a, PPos[] shrouded)
|
||||||
{
|
{
|
||||||
if (a.Owner.IsAlliedWith(self.Owner))
|
if (a.Owner.IsAlliedWith(self.Owner))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
foreach (var c in shrouded)
|
foreach (var uv in shrouded)
|
||||||
generatedShroudCount[c]++;
|
generatedShroudCount[(MPos)uv]++;
|
||||||
|
|
||||||
if (generation.ContainsKey(a))
|
if (generation.ContainsKey(a))
|
||||||
throw new InvalidOperationException("Attempting to add duplicate shroud generation");
|
throw new InvalidOperationException("Attempting to add duplicate shroud generation");
|
||||||
@@ -146,12 +150,12 @@ namespace OpenRA.Traits
|
|||||||
|
|
||||||
public void RemoveShroudGeneration(Actor a)
|
public void RemoveShroudGeneration(Actor a)
|
||||||
{
|
{
|
||||||
CPos[] shrouded;
|
PPos[] shrouded;
|
||||||
if (!generation.TryGetValue(a, out shrouded))
|
if (!generation.TryGetValue(a, out shrouded))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
foreach (var c in shrouded)
|
foreach (var uv in shrouded)
|
||||||
generatedShroudCount[c]--;
|
generatedShroudCount[(MPos)uv]--;
|
||||||
|
|
||||||
generation.Remove(a);
|
generation.Remove(a);
|
||||||
Invalidate(shrouded);
|
Invalidate(shrouded);
|
||||||
@@ -164,34 +168,35 @@ namespace OpenRA.Traits
|
|||||||
|
|
||||||
foreach (var a in w.Actors.Where(a => a.Owner == player))
|
foreach (var a in w.Actors.Where(a => a.Owner == player))
|
||||||
{
|
{
|
||||||
CPos[] visible = null;
|
PPos[] visible = null;
|
||||||
CPos[] shrouded = null;
|
PPos[] shrouded = null;
|
||||||
foreach (var p in self.World.Players)
|
foreach (var p in self.World.Players)
|
||||||
{
|
{
|
||||||
if (p.Shroud.visibility.TryGetValue(self, out visible))
|
if (p.Shroud.visibility.TryGetValue(self, out visible))
|
||||||
{
|
{
|
||||||
p.Shroud.RemoveVisibility(self);
|
p.Shroud.RemoveVisibility(self);
|
||||||
p.Shroud.AddVisibility(self, visible);
|
p.Shroud.AddProjectedVisibility(self, visible);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p.Shroud.generation.TryGetValue(self, out shrouded))
|
if (p.Shroud.generation.TryGetValue(self, out shrouded))
|
||||||
{
|
{
|
||||||
p.Shroud.RemoveShroudGeneration(self);
|
p.Shroud.RemoveShroudGeneration(self);
|
||||||
p.Shroud.AddShroudGeneration(self, shrouded);
|
p.Shroud.AddProjectedShroudGeneration(self, shrouded);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Explore(World world, IEnumerable<CPos> cells)
|
public void ExploreProjectedCells(World world, IEnumerable<PPos> cells)
|
||||||
{
|
{
|
||||||
var changed = new HashSet<CPos>();
|
var changed = new HashSet<PPos>();
|
||||||
foreach (var c in cells)
|
foreach (var puv in cells)
|
||||||
{
|
{
|
||||||
if (!explored[c])
|
var uv = (MPos)puv;
|
||||||
|
if (!explored[uv])
|
||||||
{
|
{
|
||||||
explored[c] = true;
|
explored[uv] = true;
|
||||||
changed.Add(c);
|
changed.Add(puv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -203,13 +208,14 @@ namespace OpenRA.Traits
|
|||||||
if (map.Bounds != s.map.Bounds)
|
if (map.Bounds != s.map.Bounds)
|
||||||
throw new ArgumentException("The map bounds of these shrouds do not match.", "s");
|
throw new ArgumentException("The map bounds of these shrouds do not match.", "s");
|
||||||
|
|
||||||
var changed = new List<CPos>();
|
var changed = new List<PPos>();
|
||||||
foreach (var uv in map.ProjectedCellBounds.CandidateMapCoords)
|
foreach (var puv in map.ProjectedCellBounds)
|
||||||
{
|
{
|
||||||
|
var uv = (MPos)puv;
|
||||||
if (!explored[uv] && s.explored[uv])
|
if (!explored[uv] && s.explored[uv])
|
||||||
{
|
{
|
||||||
explored[uv] = true;
|
explored[uv] = true;
|
||||||
changed.Add(uv.ToCPos(map));
|
changed.Add(puv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,13 +224,14 @@ namespace OpenRA.Traits
|
|||||||
|
|
||||||
public void ExploreAll(World world)
|
public void ExploreAll(World world)
|
||||||
{
|
{
|
||||||
var changed = new List<CPos>();
|
var changed = new List<PPos>();
|
||||||
foreach (var uv in map.ProjectedCellBounds.CandidateMapCoords)
|
foreach (var puv in map.ProjectedCellBounds)
|
||||||
{
|
{
|
||||||
|
var uv = (MPos)puv;
|
||||||
if (!explored[uv])
|
if (!explored[uv])
|
||||||
{
|
{
|
||||||
explored[uv] = true;
|
explored[uv] = true;
|
||||||
changed.Add(uv.ToCPos(map));
|
changed.Add(puv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,14 +240,15 @@ namespace OpenRA.Traits
|
|||||||
|
|
||||||
public void ResetExploration()
|
public void ResetExploration()
|
||||||
{
|
{
|
||||||
var changed = new List<CPos>();
|
var changed = new List<PPos>();
|
||||||
foreach (var uv in map.ProjectedCellBounds.CandidateMapCoords)
|
foreach (var puv in map.ProjectedCellBounds)
|
||||||
{
|
{
|
||||||
|
var uv = (MPos)puv;
|
||||||
var visible = visibleCount[uv] > 0;
|
var visible = visibleCount[uv] > 0;
|
||||||
if (explored[uv] != visible)
|
if (explored[uv] != visible)
|
||||||
{
|
{
|
||||||
explored[uv] = visible;
|
explored[uv] = visible;
|
||||||
changed.Add(uv.ToCPos(map));
|
changed.Add(puv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -249,7 +257,7 @@ namespace OpenRA.Traits
|
|||||||
|
|
||||||
public bool IsExplored(WPos pos)
|
public bool IsExplored(WPos pos)
|
||||||
{
|
{
|
||||||
return IsExplored(map.CellContaining(pos));
|
return IsExplored(map.ProjectedCellCovering(pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsExplored(CPos cell)
|
public bool IsExplored(CPos cell)
|
||||||
@@ -262,25 +270,26 @@ namespace OpenRA.Traits
|
|||||||
if (!map.Contains(uv))
|
if (!map.Contains(uv))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
return map.ProjectedCellsCovering(uv).Any(isExploredTest);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsExplored(PPos puv)
|
||||||
|
{
|
||||||
if (!ShroudEnabled)
|
if (!ShroudEnabled)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return IsExploredCore(uv);
|
var uv = (MPos)puv;
|
||||||
|
return explored.Contains(uv) && explored[uv] && (generatedShroudCount[uv] == 0 || visibleCount[uv] > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ShroudEnabled { get { return !Disabled && self.World.LobbyInfo.GlobalSettings.Shroud; } }
|
bool ShroudEnabled { get { return !Disabled && self.World.LobbyInfo.GlobalSettings.Shroud; } }
|
||||||
|
|
||||||
bool IsExploredCore(MPos uv)
|
|
||||||
{
|
|
||||||
return explored[uv] && (generatedShroudCount[uv] == 0 || visibleCount[uv] > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns a fast exploration lookup that skips the usual validation.
|
/// Returns a fast exploration lookup that skips the usual validation.
|
||||||
/// The return value should not be cached across ticks, and should not
|
/// The return value should not be cached across ticks, and should not
|
||||||
/// be called with cells outside the map bounds.
|
/// be called with cells outside the map bounds.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Func<MPos, bool> IsExploredTest
|
public Func<PPos, bool> IsExploredTest
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
@@ -294,39 +303,40 @@ namespace OpenRA.Traits
|
|||||||
|
|
||||||
public bool IsVisible(WPos pos)
|
public bool IsVisible(WPos pos)
|
||||||
{
|
{
|
||||||
return IsVisible(map.CellContaining(pos));
|
return IsVisible(map.ProjectedCellCovering(pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsVisible(CPos cell)
|
public bool IsVisible(CPos cell)
|
||||||
{
|
{
|
||||||
var uv = cell.ToMPos(map);
|
return IsVisible(cell.ToMPos(map));
|
||||||
return IsVisible(uv);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsVisible(MPos uv)
|
public bool IsVisible(MPos uv)
|
||||||
{
|
{
|
||||||
if (!map.Contains(uv))
|
if (!visibleCount.Contains(uv))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
return map.ProjectedCellsCovering(uv).Any(isVisibleTest);
|
||||||
|
}
|
||||||
|
|
||||||
|
// In internal shroud coords
|
||||||
|
public bool IsVisible(PPos puv)
|
||||||
|
{
|
||||||
if (!FogEnabled)
|
if (!FogEnabled)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return IsVisibleCore(uv);
|
var uv = (MPos)puv;
|
||||||
|
return visibleCount.Contains(uv) && visibleCount[uv] > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FogEnabled { get { return !Disabled && self.World.LobbyInfo.GlobalSettings.Fog; } }
|
bool FogEnabled { get { return !Disabled && self.World.LobbyInfo.GlobalSettings.Fog; } }
|
||||||
|
|
||||||
bool IsVisibleCore(MPos uv)
|
|
||||||
{
|
|
||||||
return visibleCount[uv] > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns a fast visibility lookup that skips the usual validation.
|
/// Returns a fast visibility lookup that skips the usual validation.
|
||||||
/// The return value should not be cached across ticks, and should not
|
/// The return value should not be cached across ticks, and should not
|
||||||
/// be called with cells outside the map bounds.
|
/// be called with cells outside the map bounds.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Func<MPos, bool> IsVisibleTest
|
public Func<PPos, bool> IsVisibleTest
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
@@ -339,11 +349,11 @@ namespace OpenRA.Traits
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Contains(MPos uv)
|
public bool Contains(PPos uv)
|
||||||
{
|
{
|
||||||
// Check that uv is inside the map area. There is nothing special
|
// Check that uv is inside the map area. There is nothing special
|
||||||
// about explored here: any of the CellLayers would have been suitable.
|
// about explored here: any of the CellLayers would have been suitable.
|
||||||
return explored.Contains(uv);
|
return explored.Contains((MPos)uv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ namespace OpenRA
|
|||||||
public int Compare(Actor x, Actor y) { return x.ActorID.CompareTo(y.ActorID); }
|
public int Compare(Actor x, Actor y) { return x.ActorID.CompareTo(y.ActorID); }
|
||||||
}
|
}
|
||||||
|
|
||||||
static readonly Func<MPos, bool> FalsePredicate = _ => false;
|
|
||||||
internal readonly TraitDictionary TraitDict = new TraitDictionary();
|
internal readonly TraitDictionary TraitDict = new TraitDictionary();
|
||||||
readonly SortedSet<Actor> actors = new SortedSet<Actor>(ActorIDComparer.Instance);
|
readonly SortedSet<Actor> actors = new SortedSet<Actor>(ActorIDComparer.Instance);
|
||||||
readonly List<IEffect> effects = new List<IEffect>();
|
readonly List<IEffect> effects = new List<IEffect>();
|
||||||
@@ -78,33 +77,7 @@ namespace OpenRA
|
|||||||
public bool FogObscures(WPos pos) { return RenderPlayer != null && !RenderPlayer.Shroud.IsVisible(pos); }
|
public bool FogObscures(WPos pos) { return RenderPlayer != null && !RenderPlayer.Shroud.IsVisible(pos); }
|
||||||
public bool ShroudObscures(CPos p) { return RenderPlayer != null && !RenderPlayer.Shroud.IsExplored(p); }
|
public bool ShroudObscures(CPos p) { return RenderPlayer != null && !RenderPlayer.Shroud.IsExplored(p); }
|
||||||
public bool ShroudObscures(WPos pos) { return RenderPlayer != null && !RenderPlayer.Shroud.IsExplored(pos); }
|
public bool ShroudObscures(WPos pos) { return RenderPlayer != null && !RenderPlayer.Shroud.IsExplored(pos); }
|
||||||
public bool ShroudObscures(MPos uv) { return RenderPlayer != null && !RenderPlayer.Shroud.IsExplored(uv); }
|
public bool ShroudObscures(PPos uv) { return RenderPlayer != null && !RenderPlayer.Shroud.IsExplored(uv); }
|
||||||
|
|
||||||
public Func<MPos, bool> FogObscuresTest
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
var rp = RenderPlayer;
|
|
||||||
if (rp == null)
|
|
||||||
return FalsePredicate;
|
|
||||||
|
|
||||||
var predicate = rp.Shroud.IsVisibleTest;
|
|
||||||
return uv => !predicate(uv);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Func<MPos, bool> ShroudObscuresTest
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
var rp = RenderPlayer;
|
|
||||||
if (rp == null)
|
|
||||||
return FalsePredicate;
|
|
||||||
|
|
||||||
var predicate = rp.Shroud.IsExploredTest;
|
|
||||||
return uv => !predicate(uv);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsReplay
|
public bool IsReplay
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
public CreatesShroud(Actor self, CreatesShroudInfo info)
|
public CreatesShroud(Actor self, CreatesShroudInfo info)
|
||||||
: base(self, info)
|
: base(self, info)
|
||||||
{
|
{
|
||||||
addCellsToPlayerShroud = (p, c) => p.Shroud.AddShroudGeneration(self, c);
|
addCellsToPlayerShroud = (p, uv) => p.Shroud.AddProjectedShroudGeneration(self, uv);
|
||||||
removeCellsFromPlayerShroud = p => p.Shroud.RemoveShroudGeneration(self);
|
removeCellsFromPlayerShroud = p => p.Shroud.RemoveShroudGeneration(self);
|
||||||
isDisabled = () => self.IsDisabled();
|
isDisabled = () => self.IsDisabled();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
|
|
||||||
readonly FrozenUnderFogInfo info;
|
readonly FrozenUnderFogInfo info;
|
||||||
readonly bool startsRevealed;
|
readonly bool startsRevealed;
|
||||||
readonly MPos[] footprint;
|
readonly PPos[] footprint;
|
||||||
|
|
||||||
readonly Lazy<IToolTip> tooltip;
|
readonly Lazy<IToolTip> tooltip;
|
||||||
readonly Lazy<Health> health;
|
readonly Lazy<Health> health;
|
||||||
@@ -47,10 +47,12 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
{
|
{
|
||||||
this.info = info;
|
this.info = info;
|
||||||
|
|
||||||
|
var map = init.World.Map;
|
||||||
|
|
||||||
// Spawned actors (e.g. building husks) shouldn't be revealed
|
// Spawned actors (e.g. building husks) shouldn't be revealed
|
||||||
startsRevealed = info.StartsRevealed && !init.Contains<ParentActorInit>();
|
startsRevealed = info.StartsRevealed && !init.Contains<ParentActorInit>();
|
||||||
var footprintCells = FootprintUtils.Tiles(init.Self).ToList();
|
var footprintCells = FootprintUtils.Tiles(init.Self).ToList();
|
||||||
footprint = footprintCells.Select(cell => cell.ToMPos(init.World.Map)).ToArray();
|
footprint = footprintCells.SelectMany(c => map.ProjectedCellsCovering(c.ToMPos(map))).ToArray();
|
||||||
tooltip = Exts.Lazy(() => init.Self.TraitsImplementing<IToolTip>().FirstOrDefault());
|
tooltip = Exts.Lazy(() => init.Self.TraitsImplementing<IToolTip>().FirstOrDefault());
|
||||||
health = Exts.Lazy(() => init.Self.TraitOrDefault<Health>());
|
health = Exts.Lazy(() => init.Self.TraitOrDefault<Health>());
|
||||||
|
|
||||||
|
|||||||
@@ -27,14 +27,14 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
|
|
||||||
public class RevealsShroud : ITick, ISync, INotifyAddedToWorld, INotifyRemovedFromWorld
|
public class RevealsShroud : ITick, ISync, INotifyAddedToWorld, INotifyRemovedFromWorld
|
||||||
{
|
{
|
||||||
static readonly CPos[] NoCells = { };
|
static readonly PPos[] NoCells = { };
|
||||||
|
|
||||||
readonly RevealsShroudInfo info;
|
readonly RevealsShroudInfo info;
|
||||||
readonly bool lobbyShroudFogDisabled;
|
readonly bool lobbyShroudFogDisabled;
|
||||||
[Sync] CPos cachedLocation;
|
[Sync] CPos cachedLocation;
|
||||||
[Sync] bool cachedDisabled;
|
[Sync] bool cachedDisabled;
|
||||||
|
|
||||||
protected Action<Player, CPos[]> addCellsToPlayerShroud;
|
protected Action<Player, PPos[]> addCellsToPlayerShroud;
|
||||||
protected Action<Player> removeCellsFromPlayerShroud;
|
protected Action<Player> removeCellsFromPlayerShroud;
|
||||||
protected Func<bool> isDisabled;
|
protected Func<bool> isDisabled;
|
||||||
|
|
||||||
@@ -43,12 +43,12 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
this.info = info;
|
this.info = info;
|
||||||
lobbyShroudFogDisabled = !self.World.LobbyInfo.GlobalSettings.Shroud && !self.World.LobbyInfo.GlobalSettings.Fog;
|
lobbyShroudFogDisabled = !self.World.LobbyInfo.GlobalSettings.Shroud && !self.World.LobbyInfo.GlobalSettings.Fog;
|
||||||
|
|
||||||
addCellsToPlayerShroud = (p, c) => p.Shroud.AddVisibility(self, c);
|
addCellsToPlayerShroud = (p, uv) => p.Shroud.AddProjectedVisibility(self, uv);
|
||||||
removeCellsFromPlayerShroud = p => p.Shroud.RemoveVisibility(self);
|
removeCellsFromPlayerShroud = p => p.Shroud.RemoveVisibility(self);
|
||||||
isDisabled = () => false;
|
isDisabled = () => false;
|
||||||
}
|
}
|
||||||
|
|
||||||
CPos[] Cells(Actor self)
|
PPos[] ProjectedCells(Actor self)
|
||||||
{
|
{
|
||||||
var map = self.World.Map;
|
var map = self.World.Map;
|
||||||
var range = Range;
|
var range = Range;
|
||||||
@@ -57,10 +57,10 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
|
|
||||||
if (info.Type == VisibilityType.Footprint)
|
if (info.Type == VisibilityType.Footprint)
|
||||||
return self.OccupiesSpace.OccupiedCells()
|
return self.OccupiesSpace.OccupiedCells()
|
||||||
.SelectMany(kv => Shroud.CellsInRange(map, kv.First, range))
|
.SelectMany(kv => Shroud.ProjectedCellsInRange(map, kv.First, range))
|
||||||
.Distinct().ToArray();
|
.Distinct().ToArray();
|
||||||
|
|
||||||
return Shroud.CellsInRange(map, self.CenterPosition, range)
|
return Shroud.ProjectedCellsInRange(map, self.CenterPosition, range)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,15 +69,18 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
if (lobbyShroudFogDisabled || !self.IsInWorld)
|
if (lobbyShroudFogDisabled || !self.IsInWorld)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var location = self.Location;
|
var centerPosition = self.CenterPosition;
|
||||||
|
var projectedPos = centerPosition - new WVec(0, centerPosition.Z, centerPosition.Z);
|
||||||
|
var projectedLocation = self.World.Map.CellContaining(projectedPos);
|
||||||
var disabled = isDisabled();
|
var disabled = isDisabled();
|
||||||
if (cachedLocation == location && cachedDisabled == disabled)
|
|
||||||
|
if (cachedLocation == projectedLocation && cachedDisabled == disabled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
cachedLocation = location;
|
cachedLocation = projectedLocation;
|
||||||
cachedDisabled = disabled;
|
cachedDisabled = disabled;
|
||||||
|
|
||||||
var cells = Cells(self);
|
var cells = ProjectedCells(self);
|
||||||
foreach (var p in self.World.Players)
|
foreach (var p in self.World.Players)
|
||||||
{
|
{
|
||||||
removeCellsFromPlayerShroud(p);
|
removeCellsFromPlayerShroud(p);
|
||||||
@@ -87,10 +90,11 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
|
|
||||||
public void AddedToWorld(Actor self)
|
public void AddedToWorld(Actor self)
|
||||||
{
|
{
|
||||||
cachedLocation = self.Location;
|
var centerPosition = self.CenterPosition;
|
||||||
|
var projectedPos = centerPosition - new WVec(0, centerPosition.Z, centerPosition.Z);
|
||||||
|
cachedLocation = self.World.Map.CellContaining(projectedPos);
|
||||||
cachedDisabled = isDisabled();
|
cachedDisabled = isDisabled();
|
||||||
|
var cells = ProjectedCells(self);
|
||||||
var cells = Cells(self);
|
|
||||||
foreach (var p in self.World.Players)
|
foreach (var p in self.World.Players)
|
||||||
addCellsToPlayerShroud(p, cells);
|
addCellsToPlayerShroud(p, cells);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,10 +64,10 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
var map = world.Map;
|
var map = world.Map;
|
||||||
foreach (var p in Start.Keys)
|
foreach (var p in Start.Keys)
|
||||||
{
|
{
|
||||||
var cells = Shroud.CellsInRange(map, Start[p], info.InitialExploreRange);
|
var cells = Shroud.ProjectedCellsInRange(map, Start[p], info.InitialExploreRange);
|
||||||
foreach (var q in world.Players)
|
foreach (var q in world.Players)
|
||||||
if (p.IsAlliedWith(q))
|
if (p.IsAlliedWith(q))
|
||||||
q.Shroud.Explore(world, cells);
|
q.Shroud.ExploreProjectedCells(world, cells);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set viewport
|
// Set viewport
|
||||||
|
|||||||
@@ -91,11 +91,11 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
|
|
||||||
readonly CellLayer<TileInfo> tileInfos;
|
readonly CellLayer<TileInfo> tileInfos;
|
||||||
readonly Sprite[] fogSprites, shroudSprites;
|
readonly Sprite[] fogSprites, shroudSprites;
|
||||||
readonly HashSet<CPos> cellsDirty = new HashSet<CPos>();
|
readonly HashSet<PPos> cellsDirty = new HashSet<PPos>();
|
||||||
readonly HashSet<CPos> cellsAndNeighborsDirty = new HashSet<CPos>();
|
readonly HashSet<PPos> cellsAndNeighborsDirty = new HashSet<PPos>();
|
||||||
|
|
||||||
Shroud currentShroud;
|
Shroud currentShroud;
|
||||||
Func<MPos, bool> visibleUnderShroud, visibleUnderFog;
|
Func<PPos, bool> visibleUnderShroud, visibleUnderFog;
|
||||||
TerrainSpriteLayer shroudLayer, fogLayer;
|
TerrainSpriteLayer shroudLayer, fogLayer;
|
||||||
|
|
||||||
public ShroudRenderer(World world, ShroudRendererInfo info)
|
public ShroudRenderer(World world, ShroudRendererInfo info)
|
||||||
@@ -158,20 +158,22 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
// This includes the region outside the visible area to cover any sprites peeking outside the map
|
// This includes the region outside the visible area to cover any sprites peeking outside the map
|
||||||
foreach (var uv in w.Map.AllCells.MapCoords)
|
foreach (var uv in w.Map.AllCells.MapCoords)
|
||||||
{
|
{
|
||||||
var screen = wr.ScreenPosition(w.Map.CenterOfCell(uv.ToCPos(map)));
|
var pos = w.Map.CenterOfCell(uv.ToCPos(map));
|
||||||
|
var screen = wr.ScreenPosition(pos - new WVec(0, 0, pos.Z));
|
||||||
var variant = (byte)Game.CosmeticRandom.Next(info.ShroudVariants.Length);
|
var variant = (byte)Game.CosmeticRandom.Next(info.ShroudVariants.Length);
|
||||||
tileInfos[uv] = new TileInfo(screen, variant);
|
tileInfos[uv] = new TileInfo(screen, variant);
|
||||||
}
|
}
|
||||||
|
|
||||||
DirtyCells(map.AllCells);
|
// Dirty the whole projected space
|
||||||
|
DirtyCells(map.AllCells.MapCoords.Select(uv => (PPos)uv));
|
||||||
|
|
||||||
// All tiles are visible in the editor
|
// All tiles are visible in the editor
|
||||||
if (w.Type == WorldType.Editor)
|
if (w.Type == WorldType.Editor)
|
||||||
visibleUnderShroud = _ => true;
|
visibleUnderShroud = _ => true;
|
||||||
else
|
else
|
||||||
visibleUnderShroud = map.Contains;
|
visibleUnderShroud = puv => map.Contains(puv);
|
||||||
|
|
||||||
visibleUnderFog = map.Contains;
|
visibleUnderFog = puv => map.Contains(puv);
|
||||||
|
|
||||||
var shroudSheet = shroudSprites[0].Sheet;
|
var shroudSheet = shroudSprites[0].Sheet;
|
||||||
if (shroudSprites.Any(s => s.Sheet != shroudSheet))
|
if (shroudSprites.Any(s => s.Sheet != shroudSheet))
|
||||||
@@ -193,25 +195,25 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
fogLayer = new TerrainSpriteLayer(w, wr, fogSheet, fogBlend, wr.Palette(info.FogPalette), false);
|
fogLayer = new TerrainSpriteLayer(w, wr, fogSheet, fogBlend, wr.Palette(info.FogPalette), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
Edges GetEdges(MPos uv, Func<MPos, bool> isVisible)
|
Edges GetEdges(PPos puv, Func<PPos, bool> isVisible)
|
||||||
{
|
{
|
||||||
if (!isVisible(uv))
|
if (!isVisible(puv))
|
||||||
return notVisibleEdges;
|
return notVisibleEdges;
|
||||||
|
|
||||||
var cell = uv.ToCPos(map);
|
var cell = ((MPos)puv).ToCPos(map);
|
||||||
|
|
||||||
// If a side is shrouded then we also count the corners.
|
// If a side is shrouded then we also count the corners.
|
||||||
var edge = Edges.None;
|
var edge = Edges.None;
|
||||||
if (!isVisible((cell + new CVec(0, -1)).ToMPos(map))) edge |= Edges.Top;
|
if (!isVisible((PPos)(cell + new CVec(0, -1)).ToMPos(map))) edge |= Edges.Top;
|
||||||
if (!isVisible((cell + new CVec(1, 0)).ToMPos(map))) edge |= Edges.Right;
|
if (!isVisible((PPos)(cell + new CVec(1, 0)).ToMPos(map))) edge |= Edges.Right;
|
||||||
if (!isVisible((cell + new CVec(0, 1)).ToMPos(map))) edge |= Edges.Bottom;
|
if (!isVisible((PPos)(cell + new CVec(0, 1)).ToMPos(map))) edge |= Edges.Bottom;
|
||||||
if (!isVisible((cell + new CVec(-1, 0)).ToMPos(map))) edge |= Edges.Left;
|
if (!isVisible((PPos)(cell + new CVec(-1, 0)).ToMPos(map))) edge |= Edges.Left;
|
||||||
|
|
||||||
var ucorner = edge & Edges.AllCorners;
|
var ucorner = edge & Edges.AllCorners;
|
||||||
if (!isVisible((cell + new CVec(-1, -1)).ToMPos(map))) edge |= Edges.TopLeft;
|
if (!isVisible((PPos)(cell + new CVec(-1, -1)).ToMPos(map))) edge |= Edges.TopLeft;
|
||||||
if (!isVisible((cell + new CVec(1, -1)).ToMPos(map))) edge |= Edges.TopRight;
|
if (!isVisible((PPos)(cell + new CVec(1, -1)).ToMPos(map))) edge |= Edges.TopRight;
|
||||||
if (!isVisible((cell + new CVec(1, 1)).ToMPos(map))) edge |= Edges.BottomRight;
|
if (!isVisible((PPos)(cell + new CVec(1, 1)).ToMPos(map))) edge |= Edges.BottomRight;
|
||||||
if (!isVisible((cell + new CVec(-1, 1)).ToMPos(map))) edge |= Edges.BottomLeft;
|
if (!isVisible((PPos)(cell + new CVec(-1, 1)).ToMPos(map))) edge |= Edges.BottomLeft;
|
||||||
|
|
||||||
// RA provides a set of frames for tiles with shrouded
|
// RA provides a set of frames for tiles with shrouded
|
||||||
// corners but unshrouded edges. We want to detect this
|
// corners but unshrouded edges. We want to detect this
|
||||||
@@ -222,7 +224,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
return info.UseExtendedIndex ? edge ^ ucorner : edge & Edges.AllCorners;
|
return info.UseExtendedIndex ? edge ^ ucorner : edge & Edges.AllCorners;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DirtyCells(IEnumerable<CPos> cells)
|
void DirtyCells(IEnumerable<PPos> cells)
|
||||||
{
|
{
|
||||||
cellsDirty.UnionWith(cells);
|
cellsDirty.UnionWith(cells);
|
||||||
}
|
}
|
||||||
@@ -244,38 +246,37 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
visibleUnderShroud = map.Contains;
|
visibleUnderShroud = puv => map.Contains(puv);
|
||||||
visibleUnderFog = map.Contains;
|
visibleUnderFog = puv => map.Contains(puv);
|
||||||
}
|
}
|
||||||
|
|
||||||
currentShroud = shroud;
|
currentShroud = shroud;
|
||||||
var dirty = map.ProjectedCellBounds
|
DirtyCells(map.ProjectedCellBounds);
|
||||||
.SelectMany(puv => map.Unproject(puv).Select(uv => uv.ToCPos(map)));
|
|
||||||
DirtyCells(dirty);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// We need to update newly dirtied areas of the shroud.
|
// We need to update newly dirtied areas of the shroud.
|
||||||
// Expand the dirty area to cover the neighboring cells, since shroud is affected by neighboring cells.
|
// Expand the dirty area to cover the neighboring cells, since shroud is affected by neighboring cells.
|
||||||
foreach (var cell in cellsDirty)
|
foreach (var uv in cellsDirty)
|
||||||
{
|
{
|
||||||
cellsAndNeighborsDirty.Add(cell);
|
cellsAndNeighborsDirty.Add(uv);
|
||||||
|
var cell = ((MPos)uv).ToCPos(map);
|
||||||
foreach (var direction in CVec.Directions)
|
foreach (var direction in CVec.Directions)
|
||||||
cellsAndNeighborsDirty.Add(cell + direction);
|
cellsAndNeighborsDirty.Add((PPos)(cell + direction).ToMPos(map));
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var cell in cellsAndNeighborsDirty)
|
foreach (var puv in cellsAndNeighborsDirty)
|
||||||
{
|
{
|
||||||
var uv = cell.ToMPos(map.TileShape);
|
var uv = (MPos)puv;
|
||||||
if (!tileInfos.Contains(uv))
|
if (!tileInfos.Contains(uv))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var tileInfo = tileInfos[uv];
|
var tileInfo = tileInfos[uv];
|
||||||
var shroudSprite = GetSprite(shroudSprites, GetEdges(uv, visibleUnderShroud), tileInfo.Variant);
|
var shroudSprite = GetSprite(shroudSprites, GetEdges(puv, visibleUnderShroud), tileInfo.Variant);
|
||||||
var shroudPos = tileInfo.ScreenPosition;
|
var shroudPos = tileInfo.ScreenPosition;
|
||||||
if (shroudSprite != null)
|
if (shroudSprite != null)
|
||||||
shroudPos += shroudSprite.Offset - 0.5f * shroudSprite.Size;
|
shroudPos += shroudSprite.Offset - 0.5f * shroudSprite.Size;
|
||||||
|
|
||||||
var fogSprite = GetSprite(fogSprites, GetEdges(uv, visibleUnderFog), tileInfo.Variant);
|
var fogSprite = GetSprite(fogSprites, GetEdges(puv, visibleUnderFog), tileInfo.Variant);
|
||||||
var fogPos = tileInfo.ScreenPosition;
|
var fogPos = tileInfo.ScreenPosition;
|
||||||
if (fogSprite != null)
|
if (fogSprite != null)
|
||||||
fogPos += fogSprite.Offset - 0.5f * fogSprite.Size;
|
fogPos += fogSprite.Offset - 0.5f * fogSprite.Size;
|
||||||
|
|||||||
@@ -59,6 +59,9 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
|
|
||||||
foreach (var uv in wr.Viewport.AllVisibleCells.CandidateMapCoords)
|
foreach (var uv in wr.Viewport.AllVisibleCells.CandidateMapCoords)
|
||||||
{
|
{
|
||||||
|
if (!map.MapHeight.Value.Contains(uv))
|
||||||
|
continue;
|
||||||
|
|
||||||
var height = (int)map.MapHeight.Value[uv];
|
var height = (int)map.MapHeight.Value[uv];
|
||||||
var tile = map.MapTiles.Value[uv];
|
var tile = map.MapTiles.Value[uv];
|
||||||
var ti = tileSet.GetTileInfo(tile);
|
var ti = tileSet.GetTileInfo(tile);
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ namespace OpenRA.Mods.Common.Widgets
|
|||||||
readonly WorldRenderer worldRenderer;
|
readonly WorldRenderer worldRenderer;
|
||||||
readonly RadarPings radarPings;
|
readonly RadarPings radarPings;
|
||||||
|
|
||||||
readonly HashSet<CPos> dirtyShroudCells = new HashSet<CPos>();
|
readonly HashSet<PPos> dirtyShroudCells = new HashSet<PPos>();
|
||||||
|
|
||||||
float radarMinimapHeight;
|
float radarMinimapHeight;
|
||||||
int frame;
|
int frame;
|
||||||
@@ -120,35 +120,38 @@ namespace OpenRA.Mods.Common.Widgets
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateShroudCell(CPos cell)
|
void UpdateShroudCell(PPos projectedCell)
|
||||||
{
|
{
|
||||||
if (!world.Map.Contains(cell))
|
if (!world.Map.Bounds.Contains(projectedCell.U, projectedCell.V))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var stride = radarSheet.Size.Width;
|
var stride = radarSheet.Size.Width;
|
||||||
var uv = cell.ToMPos(world.Map);
|
|
||||||
var dx = shroudSprite.Bounds.Left - world.Map.Bounds.Left;
|
var dx = shroudSprite.Bounds.Left - world.Map.Bounds.Left;
|
||||||
var dy = shroudSprite.Bounds.Top - world.Map.Bounds.Top;
|
var dy = shroudSprite.Bounds.Top - world.Map.Bounds.Top;
|
||||||
|
|
||||||
var color = 0;
|
var color = 0;
|
||||||
if (world.ShroudObscures(cell))
|
var rp = world.RenderPlayer;
|
||||||
color = Color.Black.ToArgb();
|
if (rp != null)
|
||||||
else if (world.FogObscures(cell))
|
{
|
||||||
color = Color.FromArgb(128, Color.Black).ToArgb();
|
if (!rp.Shroud.IsExplored(projectedCell))
|
||||||
|
color = Color.Black.ToArgb();
|
||||||
|
else if (!rp.Shroud.IsVisible(projectedCell))
|
||||||
|
color = Color.FromArgb(128, Color.Black).ToArgb();
|
||||||
|
}
|
||||||
|
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
fixed (byte* colorBytes = &radarData[0])
|
fixed (byte* colorBytes = &radarData[0])
|
||||||
{
|
{
|
||||||
var colors = (int*)colorBytes;
|
var colors = (int*)colorBytes;
|
||||||
colors[(uv.V + dy) * stride + uv.U + dx] = color;
|
colors[(projectedCell.V + dy) * stride + projectedCell.U + dx] = color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MarkShroudDirty(IEnumerable<CPos> cellsChanged)
|
void MarkShroudDirty(IEnumerable<PPos> projectedCellsChanged)
|
||||||
{
|
{
|
||||||
dirtyShroudCells.UnionWith(cellsChanged);
|
dirtyShroudCells.UnionWith(projectedCellsChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string GetCursor(int2 pos)
|
public override string GetCursor(int2 pos)
|
||||||
@@ -290,7 +293,7 @@ namespace OpenRA.Mods.Common.Widgets
|
|||||||
if (newRenderShroud != null)
|
if (newRenderShroud != null)
|
||||||
{
|
{
|
||||||
// Redraw the full shroud sprite
|
// Redraw the full shroud sprite
|
||||||
MarkShroudDirty(world.Map.AllCells);
|
MarkShroudDirty(world.Map.AllCells.MapCoords.Select(uv => (PPos)uv));
|
||||||
|
|
||||||
// Update the notification binding
|
// Update the notification binding
|
||||||
newRenderShroud.CellsChanged += MarkShroudDirty;
|
newRenderShroud.CellsChanged += MarkShroudDirty;
|
||||||
|
|||||||
Reference in New Issue
Block a user