Merge pull request #8781 from pchote/heightmap-shroud
Add plumbing for heighmap-aware shroud and map bounds checks.
This commit is contained in:
@@ -98,8 +98,8 @@ namespace OpenRA.Graphics
|
||||
var cells = restrictToBounds ? viewport.VisibleCellsInsideBounds : viewport.AllVisibleCells;
|
||||
|
||||
// Only draw the rows that are visible.
|
||||
var firstRow = cells.MapCoords.TopLeft.V;
|
||||
var lastRow = Math.Min(cells.MapCoords.BottomRight.V + 1, map.MapSize.Y);
|
||||
var firstRow = cells.CandidateMapCoords.TopLeft.V.Clamp(0, map.MapSize.Y);
|
||||
var lastRow = (cells.CandidateMapCoords.BottomRight.V + 1).Clamp(firstRow, map.MapSize.Y);
|
||||
|
||||
Game.Renderer.Flush();
|
||||
|
||||
|
||||
@@ -48,10 +48,10 @@ namespace OpenRA.Graphics
|
||||
public int2 TopLeft { get { return CenterLocation - viewportSize / 2; } }
|
||||
public int2 BottomRight { get { return CenterLocation + viewportSize / 2; } }
|
||||
int2 viewportSize;
|
||||
CellRegion cells;
|
||||
ProjectedCellRegion cells;
|
||||
bool cellsDirty = true;
|
||||
|
||||
CellRegion allCells;
|
||||
ProjectedCellRegion allCells;
|
||||
bool allCellsDirty = true;
|
||||
|
||||
float zoom = 1f;
|
||||
@@ -93,15 +93,27 @@ namespace OpenRA.Graphics
|
||||
{
|
||||
worldRenderer = wr;
|
||||
|
||||
var cells = wr.World.Type == WorldType.Editor ?
|
||||
map.AllCells : map.CellsInsideBounds;
|
||||
|
||||
// Calculate map bounds in world-px
|
||||
var tl = wr.ScreenPxPosition(map.CenterOfCell(cells.TopLeft) - new WVec(512, 512, 0));
|
||||
var br = wr.ScreenPxPosition(map.CenterOfCell(cells.BottomRight) + new WVec(511, 511, 0));
|
||||
mapBounds = Rectangle.FromLTRB(tl.X, tl.Y, br.X, br.Y);
|
||||
if (wr.World.Type == WorldType.Editor)
|
||||
{
|
||||
// The full map is visible in the editor
|
||||
var ts = Game.ModData.Manifest.TileSize;
|
||||
var width = map.MapSize.X * ts.Width;
|
||||
var height = map.MapSize.Y * ts.Height;
|
||||
if (wr.World.Map.TileShape == TileShape.Diamond)
|
||||
height /= 2;
|
||||
|
||||
mapBounds = new Rectangle(0, 0, width, height);
|
||||
CenterLocation = new int2(width / 2, height / 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
var tl = wr.ScreenPxPosition(map.ProjectedTopLeft);
|
||||
var br = wr.ScreenPxPosition(map.ProjectedBottomRight);
|
||||
mapBounds = Rectangle.FromLTRB(tl.X, tl.Y, br.X, br.Y);
|
||||
CenterLocation = (tl + br) / 2;
|
||||
}
|
||||
|
||||
CenterLocation = (tl + br) / 2;
|
||||
Zoom = Game.Settings.Graphics.PixelDouble ? 2 : 1;
|
||||
tileSize = Game.ModData.Manifest.TileSize;
|
||||
}
|
||||
@@ -209,8 +221,8 @@ namespace OpenRA.Graphics
|
||||
// Visible rectangle in world coordinates (expanded to the corners of the cells)
|
||||
var bounds = insideBounds ? VisibleCellsInsideBounds : AllVisibleCells;
|
||||
var map = worldRenderer.World.Map;
|
||||
var ctl = map.CenterOfCell(bounds.TopLeft) - new WVec(512, 512, 0);
|
||||
var cbr = map.CenterOfCell(bounds.BottomRight) + new WVec(512, 512, 0);
|
||||
var ctl = map.CenterOfCell(((MPos)bounds.TopLeft).ToCPos(map)) - new WVec(512, 512, 0);
|
||||
var cbr = map.CenterOfCell(((MPos)bounds.BottomRight).ToCPos(map)) + new WVec(512, 512, 0);
|
||||
|
||||
// Convert to screen coordinates
|
||||
var tl = WorldToViewPx(worldRenderer.ScreenPxPosition(ctl - new WVec(0, 0, ctl.Z))).Clamp(ScreenClip);
|
||||
@@ -221,22 +233,21 @@ namespace OpenRA.Graphics
|
||||
br.X + tileSize.Width, br.Y + tileSize.Height);
|
||||
}
|
||||
|
||||
CellRegion CalculateVisibleCells(bool insideBounds)
|
||||
ProjectedCellRegion CalculateVisibleCells(bool insideBounds)
|
||||
{
|
||||
var map = worldRenderer.World.Map;
|
||||
|
||||
// Calculate the viewport corners in "projected wpos" (at ground level), and
|
||||
// this to an equivalent projected cell for the two corners
|
||||
var tl = map.CellContaining(worldRenderer.ProjectedPosition(TopLeft)).ToMPos(map);
|
||||
var br = map.CellContaining(worldRenderer.ProjectedPosition(BottomRight)).ToMPos(map);
|
||||
// Calculate the projected cell position at the corners of the visible area
|
||||
var tl = (PPos)map.CellContaining(worldRenderer.ProjectedPosition(TopLeft)).ToMPos(map);
|
||||
var br = (PPos)map.CellContaining(worldRenderer.ProjectedPosition(BottomRight)).ToMPos(map);
|
||||
|
||||
// Diamond tile shapes don't have straight edges, and so we need
|
||||
// an additional cell margin to include the cells that are half
|
||||
// visible on each edge.
|
||||
if (map.TileShape == TileShape.Diamond)
|
||||
{
|
||||
tl = new MPos(tl.U - 1, tl.V - 1);
|
||||
br = new MPos(br.U + 1, br.V + 1);
|
||||
tl = new PPos(tl.U - 1, tl.V - 1);
|
||||
br = new PPos(br.U + 1, br.V + 1);
|
||||
}
|
||||
|
||||
// Clamp to the visible map bounds, if requested
|
||||
@@ -246,21 +257,10 @@ namespace OpenRA.Graphics
|
||||
br = map.Clamp(br);
|
||||
}
|
||||
|
||||
// Cells can be pushed up from below if they have non-zero height.
|
||||
// Each height step is equivalent to 512 WDist units, which is
|
||||
// one MPos step for diamond cells, but only half a MPos step
|
||||
// for classic cells. Doh!
|
||||
var heightOffset = map.TileShape == TileShape.Diamond ? map.MaximumTerrainHeight : map.MaximumTerrainHeight / 2;
|
||||
br = new MPos(br.U, br.V + heightOffset);
|
||||
|
||||
// Finally, make sure that this region doesn't extend outside the map area.
|
||||
tl = map.MapHeight.Value.Clamp(tl);
|
||||
br = map.MapHeight.Value.Clamp(br);
|
||||
|
||||
return new CellRegion(map.TileShape, tl.ToCPos(map), br.ToCPos(map));
|
||||
return new ProjectedCellRegion(map, tl, br);
|
||||
}
|
||||
|
||||
public CellRegion VisibleCellsInsideBounds
|
||||
public ProjectedCellRegion VisibleCellsInsideBounds
|
||||
{
|
||||
get
|
||||
{
|
||||
@@ -274,7 +274,7 @@ namespace OpenRA.Graphics
|
||||
}
|
||||
}
|
||||
|
||||
public CellRegion AllVisibleCells
|
||||
public ProjectedCellRegion AllVisibleCells
|
||||
{
|
||||
get
|
||||
{
|
||||
|
||||
@@ -61,4 +61,34 @@ namespace OpenRA
|
||||
return new CPos(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Projected map position
|
||||
/// </summary>
|
||||
public struct PPos : IEquatable<PPos>
|
||||
{
|
||||
public readonly int U, V;
|
||||
|
||||
public PPos(int u, int v) { U = u; V = v; }
|
||||
public static readonly PPos Zero = new PPos(0, 0);
|
||||
|
||||
public static bool operator ==(PPos me, PPos other) { return me.U == other.U && me.V == other.V; }
|
||||
public static bool operator !=(PPos me, PPos other) { return !(me == other); }
|
||||
|
||||
public static explicit operator MPos(PPos puv) { return new MPos(puv.U, puv.V); }
|
||||
public static explicit operator PPos(MPos uv) { return new PPos(uv.U, uv.V); }
|
||||
|
||||
public PPos Clamp(Rectangle r)
|
||||
{
|
||||
return new PPos(Math.Min(r.Right, Math.Max(U, r.Left)),
|
||||
Math.Min(r.Bottom, Math.Max(V, r.Top)));
|
||||
}
|
||||
|
||||
public override int GetHashCode() { return U.GetHashCode() ^ V.GetHashCode(); }
|
||||
|
||||
public bool Equals(PPos other) { return other == this; }
|
||||
public override bool Equals(object obj) { return obj is PPos && Equals((PPos)obj); }
|
||||
|
||||
public override string ToString() { return U + "," + V; }
|
||||
}
|
||||
}
|
||||
@@ -87,7 +87,7 @@ namespace OpenRA
|
||||
|
||||
public MapCoordsRegion MapCoords
|
||||
{
|
||||
get { return new MapCoordsRegion(this); }
|
||||
get { return new MapCoordsRegion(mapTopLeft, mapBottomRight); }
|
||||
}
|
||||
|
||||
public CellRegionEnumerator GetEnumerator()
|
||||
@@ -151,75 +151,5 @@ namespace OpenRA
|
||||
object IEnumerator.Current { get { return Current; } }
|
||||
public void Dispose() { }
|
||||
}
|
||||
|
||||
public struct MapCoordsRegion : IEnumerable<MPos>
|
||||
{
|
||||
public struct MapCoordsEnumerator : IEnumerator<MPos>
|
||||
{
|
||||
readonly CellRegion r;
|
||||
MPos current;
|
||||
|
||||
public MapCoordsEnumerator(CellRegion region)
|
||||
: this()
|
||||
{
|
||||
r = region;
|
||||
Reset();
|
||||
}
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
var u = current.U + 1;
|
||||
var v = current.V;
|
||||
|
||||
// Check for column overflow
|
||||
if (u > r.mapBottomRight.U)
|
||||
{
|
||||
v += 1;
|
||||
u = r.mapTopLeft.U;
|
||||
|
||||
// Check for row overflow
|
||||
if (v > r.mapBottomRight.V)
|
||||
return false;
|
||||
}
|
||||
|
||||
current = new MPos(u, v);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
current = new MPos(r.mapTopLeft.U - 1, r.mapTopLeft.V);
|
||||
}
|
||||
|
||||
public MPos Current { get { return current; } }
|
||||
object IEnumerator.Current { get { return Current; } }
|
||||
public void Dispose() { }
|
||||
}
|
||||
|
||||
readonly CellRegion r;
|
||||
|
||||
public MapCoordsRegion(CellRegion region)
|
||||
{
|
||||
r = region;
|
||||
}
|
||||
|
||||
public MapCoordsEnumerator GetEnumerator()
|
||||
{
|
||||
return new MapCoordsEnumerator(r);
|
||||
}
|
||||
|
||||
IEnumerator<MPos> IEnumerable<MPos>.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
public MPos TopLeft { get { return r.mapTopLeft; } }
|
||||
public MPos BottomRight { get { return r.mapBottomRight; } }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
@@ -245,6 +246,8 @@ namespace OpenRA
|
||||
[FieldLoader.Ignore] public Lazy<CellLayer<byte>> MapHeight;
|
||||
|
||||
[FieldLoader.Ignore] public CellLayer<byte> CustomTerrain;
|
||||
[FieldLoader.Ignore] CellLayer<PPos[]> cellProjection;
|
||||
[FieldLoader.Ignore] CellLayer<List<MPos>> inverseCellProjection;
|
||||
|
||||
[FieldLoader.Ignore] Lazy<TileSet> cachedTileSet;
|
||||
[FieldLoader.Ignore] Lazy<Ruleset> rules;
|
||||
@@ -252,9 +255,11 @@ namespace OpenRA
|
||||
public SequenceProvider SequenceProvider { get { return Rules.Sequences[Tileset]; } }
|
||||
|
||||
public WVec[][] CellCorners { get; private set; }
|
||||
[FieldLoader.Ignore] public CellRegion CellsInsideBounds;
|
||||
[FieldLoader.Ignore] public ProjectedCellRegion ProjectedCellBounds;
|
||||
[FieldLoader.Ignore] public CellRegion AllCells;
|
||||
|
||||
readonly Func<PPos, bool> containsTest;
|
||||
|
||||
void AssertExists(string filename)
|
||||
{
|
||||
using (var s = Container.GetContent(filename))
|
||||
@@ -268,6 +273,8 @@ namespace OpenRA
|
||||
/// </summary>
|
||||
public Map(TileSet tileset, int width, int height)
|
||||
{
|
||||
containsTest = Contains;
|
||||
|
||||
var size = new Size(width, height);
|
||||
var tileShape = Game.ModData.Manifest.TileShape;
|
||||
var tileRef = new TerrainTile(tileset.Templates.First().Key, (byte)0);
|
||||
@@ -307,6 +314,8 @@ namespace OpenRA
|
||||
/// <summary>Initializes a map loaded from disk.</summary>
|
||||
public Map(string path)
|
||||
{
|
||||
containsTest = Contains;
|
||||
|
||||
Path = path;
|
||||
Container = GlobalFileSystem.OpenPackage(path, null, int.MaxValue);
|
||||
|
||||
@@ -409,8 +418,8 @@ namespace OpenRA
|
||||
var br = new MPos(MapSize.X - 1, MapSize.Y - 1).ToCPos(this);
|
||||
AllCells = new CellRegion(TileShape, tl, br);
|
||||
|
||||
var btl = new MPos(Bounds.Left, Bounds.Top);
|
||||
var bbr = new MPos(Bounds.Right - 1, Bounds.Bottom - 1);
|
||||
var btl = new PPos(Bounds.Left, Bounds.Top);
|
||||
var bbr = new PPos(Bounds.Right - 1, Bounds.Bottom - 1);
|
||||
SetBounds(btl, bbr);
|
||||
|
||||
CustomTerrain = new CellLayer<byte>(this);
|
||||
@@ -428,6 +437,80 @@ namespace OpenRA
|
||||
rightDelta + new WVec(0, 0, 512 * ramp[2]),
|
||||
bottomDelta + new WVec(0, 0, 512 * ramp[3])
|
||||
}).ToArray();
|
||||
|
||||
if (MaximumTerrainHeight != 0)
|
||||
{
|
||||
cellProjection = new CellLayer<PPos[]>(this);
|
||||
inverseCellProjection = new CellLayer<List<MPos>>(this);
|
||||
|
||||
// Initialize collections
|
||||
foreach (var cell in AllCells)
|
||||
{
|
||||
var uv = cell.ToMPos(TileShape);
|
||||
cellProjection[uv] = new PPos[0];
|
||||
inverseCellProjection[uv] = new List<MPos>();
|
||||
}
|
||||
|
||||
// Initialize projections
|
||||
foreach (var cell in AllCells)
|
||||
UpdateProjection(cell);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateProjection(CPos cell)
|
||||
{
|
||||
if (MaximumTerrainHeight == 0)
|
||||
return;
|
||||
|
||||
var uv = cell.ToMPos(TileShape);
|
||||
|
||||
// Remove old reverse projection
|
||||
foreach (var puv in cellProjection[uv])
|
||||
inverseCellProjection[(MPos)puv].Remove(uv);
|
||||
|
||||
var projected = ProjectCellInner(uv);
|
||||
cellProjection[uv] = projected;
|
||||
|
||||
foreach (var puv in projected)
|
||||
inverseCellProjection[(MPos)puv].Add(uv);
|
||||
}
|
||||
|
||||
PPos[] ProjectCellInner(MPos uv)
|
||||
{
|
||||
var mapHeight = MapHeight.Value;
|
||||
if (!mapHeight.Contains(uv))
|
||||
return NoProjectedCells;
|
||||
|
||||
var height = mapHeight[uv];
|
||||
if (height == 0)
|
||||
return new[] { (PPos)uv };
|
||||
|
||||
// Odd-height ramps get bumped up a level to the next even height layer
|
||||
if ((height & 1) == 1)
|
||||
{
|
||||
var ti = cachedTileSet.Value.GetTileInfo(MapTiles.Value[uv]);
|
||||
if (ti != null && ti.RampType != 0)
|
||||
height += 1;
|
||||
}
|
||||
|
||||
var candidates = new List<PPos>();
|
||||
|
||||
// Odd-height level tiles are equally covered by four projected tiles
|
||||
if ((height & 1) == 1)
|
||||
{
|
||||
if ((uv.V & 1) == 1)
|
||||
candidates.Add(new PPos(uv.U + 1, uv.V - height));
|
||||
else
|
||||
candidates.Add(new PPos(uv.U - 1, uv.V - height));
|
||||
|
||||
candidates.Add(new PPos(uv.U, uv.V - height));
|
||||
candidates.Add(new PPos(uv.U, uv.V - height + 1));
|
||||
candidates.Add(new PPos(uv.U, uv.V - height - 1));
|
||||
}
|
||||
else
|
||||
candidates.Add(new PPos(uv.U, uv.V - height));
|
||||
|
||||
return candidates.Where(c => mapHeight.Contains((MPos)c)).ToArray();
|
||||
}
|
||||
|
||||
public Ruleset PreloadRules()
|
||||
@@ -534,6 +617,8 @@ namespace OpenRA
|
||||
}
|
||||
}
|
||||
|
||||
tiles.CellEntryChanged += UpdateProjection;
|
||||
|
||||
return tiles;
|
||||
}
|
||||
|
||||
@@ -552,6 +637,8 @@ namespace OpenRA
|
||||
}
|
||||
}
|
||||
|
||||
tiles.CellEntryChanged += UpdateProjection;
|
||||
|
||||
return tiles;
|
||||
}
|
||||
|
||||
@@ -652,7 +739,15 @@ namespace OpenRA
|
||||
|
||||
public bool Contains(MPos uv)
|
||||
{
|
||||
return Bounds.Contains(uv.U, uv.V);
|
||||
// TODO: Checking against the bounds excludes valid parts of the map if MaxTerrainHeight > 0.
|
||||
// Unfortunatley, doing this properly leads to memory corruption issues in the (unsafe) radar
|
||||
// rendering code.
|
||||
return Bounds.Contains(uv.U, uv.V) && ProjectedCellsCovering(uv).All(containsTest);
|
||||
}
|
||||
|
||||
public bool Contains(PPos puv)
|
||||
{
|
||||
return Bounds.Contains(puv.U, puv.V);
|
||||
}
|
||||
|
||||
public WPos CenterOfCell(CPos cell)
|
||||
@@ -695,6 +790,39 @@ namespace OpenRA
|
||||
return new CPos(u, v);
|
||||
}
|
||||
|
||||
public PPos ProjectedCellCovering(WPos pos)
|
||||
{
|
||||
var projectedPos = pos - new WVec(0, pos.Z, pos.Z);
|
||||
return (PPos)CellContaining(projectedPos).ToMPos(TileShape);
|
||||
}
|
||||
|
||||
static readonly PPos[] NoProjectedCells = { };
|
||||
public PPos[] ProjectedCellsCovering(MPos uv)
|
||||
{
|
||||
// Shortcut for mods that don't use heightmaps
|
||||
if (MaximumTerrainHeight == 0)
|
||||
return new[] { (PPos)uv };
|
||||
|
||||
if (!cellProjection.Contains(uv))
|
||||
return NoProjectedCells;
|
||||
|
||||
return cellProjection[uv];
|
||||
}
|
||||
|
||||
public MPos[] Unproject(PPos puv)
|
||||
{
|
||||
var uv = (MPos)puv;
|
||||
|
||||
// Shortcut for mods that don't use heightmaps
|
||||
if (MaximumTerrainHeight == 0)
|
||||
return new[] { uv };
|
||||
|
||||
if (!inverseCellProjection.Contains(uv))
|
||||
return new MPos[0];
|
||||
|
||||
return inverseCellProjection[uv].ToArray();
|
||||
}
|
||||
|
||||
public int FacingBetween(CPos cell, CPos towards, int fallbackfacing)
|
||||
{
|
||||
return Traits.Util.GetFacing(CenterOfCell(towards) - CenterOfCell(cell), fallbackfacing);
|
||||
@@ -717,12 +845,11 @@ namespace OpenRA
|
||||
AllCells = new CellRegion(TileShape, tl, br);
|
||||
}
|
||||
|
||||
public void SetBounds(MPos tl, MPos br)
|
||||
public void SetBounds(PPos tl, PPos br)
|
||||
{
|
||||
// The tl and br coordinates are inclusive, but the Rectangle
|
||||
// is exclusive. Pad the right and bottom edges to match.
|
||||
Bounds = Rectangle.FromLTRB(tl.U, tl.V, br.U + 1, br.V + 1);
|
||||
CellsInsideBounds = new CellRegion(TileShape, tl.ToCPos(this), br.ToCPos(this));
|
||||
|
||||
// Directly calculate the projected map corners in world units avoiding unnecessary
|
||||
// conversions. This abuses the definition that the width of the cell is always
|
||||
@@ -738,6 +865,8 @@ namespace OpenRA
|
||||
|
||||
ProjectedTopLeft = new WPos(tl.U * 1024, wtop, 0);
|
||||
ProjectedBottomRight = new WPos(br.U * 1024 - 1, wbottom - 1, 0);
|
||||
|
||||
ProjectedCellBounds = new ProjectedCellRegion(this, tl, br);
|
||||
}
|
||||
|
||||
string ComputeHash()
|
||||
@@ -799,18 +928,28 @@ namespace OpenRA
|
||||
|
||||
public CPos Clamp(CPos cell)
|
||||
{
|
||||
var bounds = new Rectangle(Bounds.X, Bounds.Y, Bounds.Width - 1, Bounds.Height - 1);
|
||||
return cell.ToMPos(this).Clamp(bounds).ToCPos(this);
|
||||
return Clamp(cell.ToMPos(this)).ToCPos(this);
|
||||
}
|
||||
|
||||
public MPos Clamp(MPos uv)
|
||||
{
|
||||
// Already in bounds, so don't need to do anything.
|
||||
if (Contains(uv))
|
||||
return uv;
|
||||
|
||||
// TODO: Account for terrain height
|
||||
return (MPos)Clamp((PPos)uv);
|
||||
}
|
||||
|
||||
public PPos Clamp(PPos puv)
|
||||
{
|
||||
var bounds = new Rectangle(Bounds.X, Bounds.Y, Bounds.Width - 1, Bounds.Height - 1);
|
||||
return uv.Clamp(bounds);
|
||||
return puv.Clamp(bounds);
|
||||
}
|
||||
|
||||
public CPos ChooseRandomCell(MersenneTwister rand)
|
||||
{
|
||||
// TODO: Account for terrain height
|
||||
var x = rand.Next(Bounds.Left, Bounds.Right);
|
||||
var y = rand.Next(Bounds.Top, Bounds.Bottom);
|
||||
|
||||
@@ -819,6 +958,7 @@ namespace OpenRA
|
||||
|
||||
public CPos ChooseClosestEdgeCell(CPos pos)
|
||||
{
|
||||
// TODO: Account for terrain height
|
||||
var mpos = pos.ToMPos(this);
|
||||
|
||||
var horizontalBound = ((mpos.U - Bounds.Left) < Bounds.Width / 2) ? Bounds.Left : Bounds.Right;
|
||||
@@ -832,6 +972,7 @@ namespace OpenRA
|
||||
|
||||
public CPos ChooseRandomEdgeCell(MersenneTwister rand)
|
||||
{
|
||||
// TODO: Account for terrain height
|
||||
var isX = rand.Next(2) == 0;
|
||||
var edge = rand.Next(2) == 0;
|
||||
|
||||
@@ -843,8 +984,10 @@ namespace OpenRA
|
||||
|
||||
public WDist DistanceToEdge(WPos pos, WVec dir)
|
||||
{
|
||||
var tl = CenterOfCell(CellsInsideBounds.TopLeft) - new WVec(512, 512, 0);
|
||||
var br = CenterOfCell(CellsInsideBounds.BottomRight) + new WVec(511, 511, 0);
|
||||
// TODO: Account for terrain height
|
||||
// Project into the screen plane and then compare against ProjectedWorldBounds.
|
||||
var tl = CenterOfCell(((MPos)ProjectedCellBounds.TopLeft).ToCPos(this)) - new WVec(512, 512, 0);
|
||||
var br = CenterOfCell(((MPos)ProjectedCellBounds.BottomRight).ToCPos(this)) + new WVec(511, 511, 0);
|
||||
var x = dir.X == 0 ? int.MaxValue : ((dir.X < 0 ? tl.X : br.X) - pos.X) / dir.X;
|
||||
var y = dir.Y == 0 ? int.MaxValue : ((dir.Y < 0 ? tl.Y : br.Y) - pos.Y) / dir.Y;
|
||||
return new WDist(Math.Min(x, y) * dir.Length);
|
||||
|
||||
89
OpenRA.Game/Map/MapCoordsRegion.cs
Normal file
89
OpenRA.Game/Map/MapCoordsRegion.cs
Normal file
@@ -0,0 +1,89 @@
|
||||
#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.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace OpenRA
|
||||
{
|
||||
public struct MapCoordsRegion : IEnumerable<MPos>
|
||||
{
|
||||
public struct MapCoordsEnumerator : IEnumerator<MPos>
|
||||
{
|
||||
readonly MapCoordsRegion r;
|
||||
MPos current;
|
||||
|
||||
public MapCoordsEnumerator(MapCoordsRegion region)
|
||||
: this()
|
||||
{
|
||||
r = region;
|
||||
Reset();
|
||||
}
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
var u = current.U + 1;
|
||||
var v = current.V;
|
||||
|
||||
// Check for column overflow
|
||||
if (u > r.bottomRight.U)
|
||||
{
|
||||
v += 1;
|
||||
u = r.topLeft.U;
|
||||
|
||||
// Check for row overflow
|
||||
if (v > r.bottomRight.V)
|
||||
return false;
|
||||
}
|
||||
|
||||
current = new MPos(u, v);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
current = new MPos(r.topLeft.U - 1, r.topLeft.V);
|
||||
}
|
||||
|
||||
public MPos Current { get { return current; } }
|
||||
object IEnumerator.Current { get { return Current; } }
|
||||
public void Dispose() { }
|
||||
}
|
||||
|
||||
readonly MPos topLeft;
|
||||
readonly MPos bottomRight;
|
||||
|
||||
public MapCoordsRegion(MPos mapTopLeft, MPos mapBottomRight)
|
||||
{
|
||||
this.topLeft = mapTopLeft;
|
||||
this.bottomRight = mapBottomRight;
|
||||
}
|
||||
|
||||
public MapCoordsEnumerator GetEnumerator()
|
||||
{
|
||||
return new MapCoordsEnumerator(this);
|
||||
}
|
||||
|
||||
IEnumerator<MPos> IEnumerable<MPos>.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
public MPos TopLeft { get { return topLeft; } }
|
||||
public MPos BottomRight { get { return bottomRight; } }
|
||||
}
|
||||
}
|
||||
125
OpenRA.Game/Map/ProjectedCellRegion.cs
Normal file
125
OpenRA.Game/Map/ProjectedCellRegion.cs
Normal file
@@ -0,0 +1,125 @@
|
||||
#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.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace OpenRA
|
||||
{
|
||||
// Represents a (on-screen) rectangular collection of tiles.
|
||||
// TopLeft and BottomRight are inclusive
|
||||
public class ProjectedCellRegion : IEnumerable<PPos>
|
||||
{
|
||||
// Corners of the region
|
||||
public readonly PPos TopLeft;
|
||||
public readonly PPos BottomRight;
|
||||
|
||||
// Corners of the bounding map region that contains all the cells that
|
||||
// may be projected within this region.
|
||||
readonly MPos mapTopLeft;
|
||||
readonly MPos mapBottomRight;
|
||||
|
||||
public ProjectedCellRegion(Map map, PPos topLeft, PPos bottomRight)
|
||||
{
|
||||
TopLeft = topLeft;
|
||||
BottomRight = bottomRight;
|
||||
|
||||
// The projection from MPos -> PPos cannot produce a larger V coordinate
|
||||
// so the top edge of the MPos region is the same as the PPos region.
|
||||
// (in fact the cells are identical if height == 0)
|
||||
mapTopLeft = (MPos)topLeft;
|
||||
|
||||
// The bottom edge is trickier: cells at MPos.V > bottomRight.V may have
|
||||
// been projected into this region if they have height > 0.
|
||||
// Each height step is equivalent to 512 WRange units, which is one MPos
|
||||
// step for diamond cells, but only half a MPos step for classic cells. Doh!
|
||||
var heightOffset = map.TileShape == TileShape.Diamond ? map.MaximumTerrainHeight : map.MaximumTerrainHeight / 2;
|
||||
|
||||
// Use the MapHeight data array to clamp the bottom coordinate so it doesn't overflow the map
|
||||
mapBottomRight = map.MapHeight.Value.Clamp(new MPos(bottomRight.U, bottomRight.V + heightOffset));
|
||||
}
|
||||
|
||||
public bool Contains(PPos puv)
|
||||
{
|
||||
return puv.U >= TopLeft.U && puv.U <= BottomRight.U && puv.V >= TopLeft.V && puv.V <= BottomRight.V;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The region in map coordinates that contains all the cells that
|
||||
/// may be projected inside this region. For increased performance,
|
||||
/// this does not validate whether individual map cells are actually
|
||||
/// projected inside the region.
|
||||
/// </summary>
|
||||
public MapCoordsRegion CandidateMapCoords { get { return new MapCoordsRegion(mapTopLeft, mapBottomRight); } }
|
||||
|
||||
public ProjectedCellRegionEnumerator GetEnumerator()
|
||||
{
|
||||
return new ProjectedCellRegionEnumerator(this);
|
||||
}
|
||||
|
||||
IEnumerator<PPos> IEnumerable<PPos>.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
public sealed class ProjectedCellRegionEnumerator : IEnumerator<PPos>
|
||||
{
|
||||
readonly ProjectedCellRegion r;
|
||||
|
||||
// Current position, in projected map coordinates
|
||||
int u, v;
|
||||
|
||||
PPos current;
|
||||
|
||||
public ProjectedCellRegionEnumerator(ProjectedCellRegion region)
|
||||
{
|
||||
r = region;
|
||||
Reset();
|
||||
}
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
u += 1;
|
||||
|
||||
// Check for column overflow
|
||||
if (u > r.BottomRight.U)
|
||||
{
|
||||
v += 1;
|
||||
u = r.TopLeft.U;
|
||||
|
||||
// Check for row overflow
|
||||
if (v > r.BottomRight.V)
|
||||
return false;
|
||||
}
|
||||
|
||||
current = new PPos(u, v);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
// Enumerator starts *before* the first element in the sequence.
|
||||
u = r.TopLeft.U - 1;
|
||||
v = r.TopLeft.V;
|
||||
}
|
||||
|
||||
public PPos Current { get { return current; } }
|
||||
object IEnumerator.Current { get { return Current; } }
|
||||
public void Dispose() { }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -247,6 +247,8 @@
|
||||
<Compile Include="Widgets\WorldInteractionControllerWidget.cs" />
|
||||
<Compile Include="Graphics\PaletteReference.cs" />
|
||||
<Compile Include="Graphics\TerrainSpriteLayer.cs" />
|
||||
<Compile Include="Map\ProjectedCellRegion.cs" />
|
||||
<Compile Include="Map\MapCoordsRegion.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="FileSystem\D2kSoundResources.cs" />
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace OpenRA.Traits
|
||||
|
||||
public class FrozenActor
|
||||
{
|
||||
public readonly MPos[] Footprint;
|
||||
public readonly PPos[] Footprint;
|
||||
public readonly WPos CenterPosition;
|
||||
public readonly Rectangle Bounds;
|
||||
readonly Actor actor;
|
||||
@@ -42,7 +42,7 @@ namespace OpenRA.Traits
|
||||
public bool NeedRenderables;
|
||||
public bool IsRendering { get; private set; }
|
||||
|
||||
public FrozenActor(Actor self, MPos[] footprint, Shroud shroud)
|
||||
public FrozenActor(Actor self, PPos[] footprint, Shroud shroud)
|
||||
{
|
||||
actor = self;
|
||||
this.shroud = shroud;
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace OpenRA.Traits
|
||||
{
|
||||
[Sync] public bool Disabled;
|
||||
|
||||
public event Action<IEnumerable<CPos>> CellsChanged;
|
||||
public event Action<IEnumerable<PPos>> CellsChanged;
|
||||
|
||||
readonly Actor self;
|
||||
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
|
||||
// can't make us invalid.
|
||||
readonly Dictionary<Actor, CPos[]> visibility = new Dictionary<Actor, CPos[]>();
|
||||
readonly Dictionary<Actor, CPos[]> generation = new Dictionary<Actor, CPos[]>();
|
||||
readonly Dictionary<Actor, PPos[]> visibility = new Dictionary<Actor, PPos[]>();
|
||||
readonly Dictionary<Actor, PPos[]> generation = new Dictionary<Actor, PPos[]>();
|
||||
|
||||
public int Hash { get; private set; }
|
||||
|
||||
static readonly Func<MPos, bool> TruthPredicate = _ => true;
|
||||
readonly Func<MPos, bool> shroudEdgeTest;
|
||||
readonly Func<MPos, bool> isExploredTest;
|
||||
readonly Func<MPos, bool> isVisibleTest;
|
||||
static readonly Func<PPos, bool> TruthPredicate = _ => true;
|
||||
readonly Func<PPos, bool> shroudEdgeTest;
|
||||
readonly Func<PPos, bool> isExploredTest;
|
||||
readonly Func<PPos, bool> isVisibleTest;
|
||||
|
||||
public Shroud(Actor self)
|
||||
{
|
||||
@@ -55,11 +55,12 @@ namespace OpenRA.Traits
|
||||
explored = new CellLayer<bool>(map);
|
||||
|
||||
shroudEdgeTest = map.Contains;
|
||||
isExploredTest = IsExploredCore;
|
||||
isVisibleTest = IsVisibleCore;
|
||||
|
||||
isExploredTest = IsExplored;
|
||||
isVisibleTest = IsVisible;
|
||||
}
|
||||
|
||||
void Invalidate(IEnumerable<CPos> changed)
|
||||
void Invalidate(IEnumerable<PPos> changed)
|
||||
{
|
||||
if (CellsChanged != null)
|
||||
CellsChanged(changed);
|
||||
@@ -72,35 +73,38 @@ namespace OpenRA.Traits
|
||||
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 cell = map.CellContaining(pos);
|
||||
|
||||
foreach (var c in map.FindTilesInCircle(cell, r, true))
|
||||
if ((map.CenterOfCell(c) - pos).HorizontalLengthSquared <= limit)
|
||||
yield return c;
|
||||
// Project actor position into the shroud plane
|
||||
var projectedPos = pos - new WVec(0, pos.Z, pos.Z);
|
||||
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))
|
||||
return;
|
||||
|
||||
foreach (var c in visible)
|
||||
foreach (var puv in visible)
|
||||
{
|
||||
var uv = c.ToMPos(map);
|
||||
|
||||
// Force cells outside the visible bounds invisible
|
||||
if (!map.Contains(uv))
|
||||
if (!map.Contains(puv))
|
||||
continue;
|
||||
|
||||
var uv = (MPos)puv;
|
||||
visibleCount[uv]++;
|
||||
explored[uv] = true;
|
||||
}
|
||||
@@ -114,28 +118,28 @@ namespace OpenRA.Traits
|
||||
|
||||
public void RemoveVisibility(Actor a)
|
||||
{
|
||||
CPos[] visible;
|
||||
PPos[] visible;
|
||||
if (!visibility.TryGetValue(a, out visible))
|
||||
return;
|
||||
|
||||
foreach (var c in visible)
|
||||
foreach (var puv in visible)
|
||||
{
|
||||
// Cells outside the visible bounds don't increment visibleCount
|
||||
if (map.Contains(c))
|
||||
visibleCount[c.ToMPos(map)]--;
|
||||
if (map.Contains(puv))
|
||||
visibleCount[(MPos)puv]--;
|
||||
}
|
||||
|
||||
visibility.Remove(a);
|
||||
Invalidate(visible);
|
||||
}
|
||||
|
||||
public void AddShroudGeneration(Actor a, CPos[] shrouded)
|
||||
public void AddProjectedShroudGeneration(Actor a, PPos[] shrouded)
|
||||
{
|
||||
if (a.Owner.IsAlliedWith(self.Owner))
|
||||
return;
|
||||
|
||||
foreach (var c in shrouded)
|
||||
generatedShroudCount[c]++;
|
||||
foreach (var uv in shrouded)
|
||||
generatedShroudCount[(MPos)uv]++;
|
||||
|
||||
if (generation.ContainsKey(a))
|
||||
throw new InvalidOperationException("Attempting to add duplicate shroud generation");
|
||||
@@ -146,12 +150,12 @@ namespace OpenRA.Traits
|
||||
|
||||
public void RemoveShroudGeneration(Actor a)
|
||||
{
|
||||
CPos[] shrouded;
|
||||
PPos[] shrouded;
|
||||
if (!generation.TryGetValue(a, out shrouded))
|
||||
return;
|
||||
|
||||
foreach (var c in shrouded)
|
||||
generatedShroudCount[c]--;
|
||||
foreach (var uv in shrouded)
|
||||
generatedShroudCount[(MPos)uv]--;
|
||||
|
||||
generation.Remove(a);
|
||||
Invalidate(shrouded);
|
||||
@@ -164,34 +168,35 @@ namespace OpenRA.Traits
|
||||
|
||||
foreach (var a in w.Actors.Where(a => a.Owner == player))
|
||||
{
|
||||
CPos[] visible = null;
|
||||
CPos[] shrouded = null;
|
||||
PPos[] visible = null;
|
||||
PPos[] shrouded = null;
|
||||
foreach (var p in self.World.Players)
|
||||
{
|
||||
if (p.Shroud.visibility.TryGetValue(self, out visible))
|
||||
{
|
||||
p.Shroud.RemoveVisibility(self);
|
||||
p.Shroud.AddVisibility(self, visible);
|
||||
p.Shroud.AddProjectedVisibility(self, visible);
|
||||
}
|
||||
|
||||
if (p.Shroud.generation.TryGetValue(self, out shrouded))
|
||||
{
|
||||
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>();
|
||||
foreach (var c in cells)
|
||||
var changed = new HashSet<PPos>();
|
||||
foreach (var puv in cells)
|
||||
{
|
||||
if (!explored[c])
|
||||
var uv = (MPos)puv;
|
||||
if (!explored[uv])
|
||||
{
|
||||
explored[c] = true;
|
||||
changed.Add(c);
|
||||
explored[uv] = true;
|
||||
changed.Add(puv);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,13 +208,14 @@ namespace OpenRA.Traits
|
||||
if (map.Bounds != s.map.Bounds)
|
||||
throw new ArgumentException("The map bounds of these shrouds do not match.", "s");
|
||||
|
||||
var changed = new List<CPos>();
|
||||
foreach (var uv in map.CellsInsideBounds.MapCoords)
|
||||
var changed = new List<PPos>();
|
||||
foreach (var puv in map.ProjectedCellBounds)
|
||||
{
|
||||
var uv = (MPos)puv;
|
||||
if (!explored[uv] && s.explored[uv])
|
||||
{
|
||||
explored[uv] = true;
|
||||
changed.Add(uv.ToCPos(map));
|
||||
changed.Add(puv);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,13 +224,14 @@ namespace OpenRA.Traits
|
||||
|
||||
public void ExploreAll(World world)
|
||||
{
|
||||
var changed = new List<CPos>();
|
||||
foreach (var uv in map.CellsInsideBounds.MapCoords)
|
||||
var changed = new List<PPos>();
|
||||
foreach (var puv in map.ProjectedCellBounds)
|
||||
{
|
||||
var uv = (MPos)puv;
|
||||
if (!explored[uv])
|
||||
{
|
||||
explored[uv] = true;
|
||||
changed.Add(uv.ToCPos(map));
|
||||
changed.Add(puv);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -233,14 +240,15 @@ namespace OpenRA.Traits
|
||||
|
||||
public void ResetExploration()
|
||||
{
|
||||
var changed = new List<CPos>();
|
||||
foreach (var uv in map.CellsInsideBounds.MapCoords)
|
||||
var changed = new List<PPos>();
|
||||
foreach (var puv in map.ProjectedCellBounds)
|
||||
{
|
||||
var uv = (MPos)puv;
|
||||
var visible = visibleCount[uv] > 0;
|
||||
if (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)
|
||||
{
|
||||
return IsExplored(map.CellContaining(pos));
|
||||
return IsExplored(map.ProjectedCellCovering(pos));
|
||||
}
|
||||
|
||||
public bool IsExplored(CPos cell)
|
||||
@@ -262,25 +270,26 @@ namespace OpenRA.Traits
|
||||
if (!map.Contains(uv))
|
||||
return false;
|
||||
|
||||
return map.ProjectedCellsCovering(uv).Any(isExploredTest);
|
||||
}
|
||||
|
||||
public bool IsExplored(PPos puv)
|
||||
{
|
||||
if (!ShroudEnabled)
|
||||
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 IsExploredCore(MPos uv)
|
||||
{
|
||||
return explored[uv] && (generatedShroudCount[uv] == 0 || visibleCount[uv] > 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a fast exploration lookup that skips the usual validation.
|
||||
/// The return value should not be cached across ticks, and should not
|
||||
/// be called with cells outside the map bounds.
|
||||
/// </summary>
|
||||
public Func<MPos, bool> IsExploredTest
|
||||
public Func<PPos, bool> IsExploredTest
|
||||
{
|
||||
get
|
||||
{
|
||||
@@ -294,39 +303,40 @@ namespace OpenRA.Traits
|
||||
|
||||
public bool IsVisible(WPos pos)
|
||||
{
|
||||
return IsVisible(map.CellContaining(pos));
|
||||
return IsVisible(map.ProjectedCellCovering(pos));
|
||||
}
|
||||
|
||||
public bool IsVisible(CPos cell)
|
||||
{
|
||||
var uv = cell.ToMPos(map);
|
||||
return IsVisible(uv);
|
||||
return IsVisible(cell.ToMPos(map));
|
||||
}
|
||||
|
||||
public bool IsVisible(MPos uv)
|
||||
{
|
||||
if (!map.Contains(uv))
|
||||
if (!visibleCount.Contains(uv))
|
||||
return false;
|
||||
|
||||
return map.ProjectedCellsCovering(uv).Any(isVisibleTest);
|
||||
}
|
||||
|
||||
// In internal shroud coords
|
||||
public bool IsVisible(PPos puv)
|
||||
{
|
||||
if (!FogEnabled)
|
||||
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 IsVisibleCore(MPos uv)
|
||||
{
|
||||
return visibleCount[uv] > 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a fast visibility lookup that skips the usual validation.
|
||||
/// The return value should not be cached across ticks, and should not
|
||||
/// be called with cells outside the map bounds.
|
||||
/// </summary>
|
||||
public Func<MPos, bool> IsVisibleTest
|
||||
public Func<PPos, bool> IsVisibleTest
|
||||
{
|
||||
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
|
||||
// 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); }
|
||||
}
|
||||
|
||||
static readonly Func<MPos, bool> FalsePredicate = _ => false;
|
||||
internal readonly TraitDictionary TraitDict = new TraitDictionary();
|
||||
readonly SortedSet<Actor> actors = new SortedSet<Actor>(ActorIDComparer.Instance);
|
||||
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 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(MPos 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 ShroudObscures(PPos uv) { return RenderPlayer != null && !RenderPlayer.Shroud.IsExplored(uv); }
|
||||
|
||||
public bool IsReplay
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user