Shroud, combine IsVisible and IsExplored into a single function.
This commit is contained in:
@@ -155,14 +155,15 @@ namespace OpenRA.Traits
|
|||||||
// PERF: Avoid LINQ.
|
// PERF: Avoid LINQ.
|
||||||
foreach (var puv in Footprint)
|
foreach (var puv in Footprint)
|
||||||
{
|
{
|
||||||
if (shroud.IsVisible(puv))
|
var cv = shroud.GetVisibility(puv);
|
||||||
|
if (cv.HasFlag(Shroud.CellVisibility.Visible))
|
||||||
{
|
{
|
||||||
Visible = false;
|
Visible = false;
|
||||||
Shrouded = false;
|
Shrouded = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Shrouded && shroud.IsExplored(puv))
|
if (Shrouded && cv.HasFlag(Shroud.CellVisibility.Explored))
|
||||||
Shrouded = false;
|
Shrouded = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -83,6 +83,10 @@ namespace OpenRA.Traits
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Visible is not a super set of Explored. IsExplored may return false even if IsVisible returns true.
|
||||||
|
[Flags]
|
||||||
|
public enum CellVisibility : byte { Hidden = 0x0, Explored = 0x1, Visible = 0x2 }
|
||||||
|
|
||||||
readonly Actor self;
|
readonly Actor self;
|
||||||
readonly ShroudInfo info;
|
readonly ShroudInfo info;
|
||||||
readonly Map map;
|
readonly Map map;
|
||||||
@@ -423,5 +427,53 @@ namespace OpenRA.Traits
|
|||||||
// 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(uv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PERF: Combine IsExplored and IsVisible.
|
||||||
|
public CellVisibility GetVisibility(PPos puv)
|
||||||
|
{
|
||||||
|
var state = CellVisibility.Hidden;
|
||||||
|
|
||||||
|
if (Disabled)
|
||||||
|
{
|
||||||
|
if (FogEnabled)
|
||||||
|
{
|
||||||
|
// Shroud disabled, Fog enabled
|
||||||
|
if (resolvedType.Contains(puv))
|
||||||
|
{
|
||||||
|
state |= CellVisibility.Explored;
|
||||||
|
|
||||||
|
if (resolvedType[puv] == ShroudCellType.Visible)
|
||||||
|
state |= CellVisibility.Visible;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (map.Contains(puv))
|
||||||
|
state |= CellVisibility.Explored | CellVisibility.Visible;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (FogEnabled)
|
||||||
|
{
|
||||||
|
// Shroud and Fog enabled
|
||||||
|
if (resolvedType.Contains(puv))
|
||||||
|
{
|
||||||
|
var rt = resolvedType[puv];
|
||||||
|
if (rt == ShroudCellType.Visible)
|
||||||
|
state |= CellVisibility.Explored | CellVisibility.Visible;
|
||||||
|
else if (rt > ShroudCellType.Shroud)
|
||||||
|
state |= CellVisibility.Explored;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (resolvedType.Contains(puv))
|
||||||
|
{
|
||||||
|
// We do not set Explored since IsExplored may return false.
|
||||||
|
state |= CellVisibility.Visible;
|
||||||
|
|
||||||
|
if (resolvedType[puv] > ShroudCellType.Shroud)
|
||||||
|
state |= CellVisibility.Explored;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,6 +81,19 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
All = Top | Right | Bottom | Left
|
All = Top | Right | Bottom | Left
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Index into neighbors array.
|
||||||
|
enum Neighbor
|
||||||
|
{
|
||||||
|
Top = 0,
|
||||||
|
Right,
|
||||||
|
Bottom,
|
||||||
|
Left,
|
||||||
|
TopLeft,
|
||||||
|
TopRight,
|
||||||
|
BottomRight,
|
||||||
|
BottomLeft
|
||||||
|
}
|
||||||
|
|
||||||
readonly struct TileInfo
|
readonly struct TileInfo
|
||||||
{
|
{
|
||||||
public readonly float3 ScreenPosition;
|
public readonly float3 ScreenPosition;
|
||||||
@@ -96,17 +109,20 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
readonly ShroudRendererInfo info;
|
readonly ShroudRendererInfo info;
|
||||||
readonly World world;
|
readonly World world;
|
||||||
readonly Map map;
|
readonly Map map;
|
||||||
readonly Edges notVisibleEdges;
|
readonly (Edges, Edges) notVisibleEdgesPair;
|
||||||
readonly byte variantStride;
|
readonly byte variantStride;
|
||||||
readonly byte[] edgesToSpriteIndexOffset;
|
readonly byte[] edgesToSpriteIndexOffset;
|
||||||
|
|
||||||
|
// PERF: Allocate once.
|
||||||
|
readonly Shroud.CellVisibility[] neighbors = new Shroud.CellVisibility[8];
|
||||||
|
|
||||||
readonly CellLayer<TileInfo> tileInfos;
|
readonly CellLayer<TileInfo> tileInfos;
|
||||||
readonly CellLayer<bool> cellsDirty;
|
readonly CellLayer<bool> cellsDirty;
|
||||||
bool anyCellDirty;
|
bool anyCellDirty;
|
||||||
readonly (Sprite Sprite, float Scale, float Alpha)[] fogSprites, shroudSprites;
|
readonly (Sprite Sprite, float Scale, float Alpha)[] fogSprites, shroudSprites;
|
||||||
|
|
||||||
Shroud shroud;
|
Shroud shroud;
|
||||||
Func<PPos, bool> visibleUnderShroud, visibleUnderFog;
|
Func<PPos, Shroud.CellVisibility> cellVisibility;
|
||||||
TerrainSpriteLayer shroudLayer, fogLayer;
|
TerrainSpriteLayer shroudLayer, fogLayer;
|
||||||
PaletteReference shroudPaletteReference, fogPaletteReference;
|
PaletteReference shroudPaletteReference, fogPaletteReference;
|
||||||
bool disposed;
|
bool disposed;
|
||||||
@@ -161,16 +177,26 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int spriteCount;
|
||||||
|
if (info.UseExtendedIndex)
|
||||||
|
{
|
||||||
|
notVisibleEdgesPair = (Edges.AllSides, Edges.AllSides);
|
||||||
|
spriteCount = (int)Edges.All;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
notVisibleEdgesPair = (Edges.AllCorners, Edges.AllCorners);
|
||||||
|
spriteCount = (int)Edges.AllCorners;
|
||||||
|
}
|
||||||
|
|
||||||
// Mapping of shrouded directions -> sprite index
|
// Mapping of shrouded directions -> sprite index
|
||||||
edgesToSpriteIndexOffset = new byte[(byte)(info.UseExtendedIndex ? Edges.All : Edges.AllCorners) + 1];
|
edgesToSpriteIndexOffset = new byte[spriteCount + 1];
|
||||||
for (var i = 0; i < info.Index.Length; i++)
|
for (var i = 0; i < info.Index.Length; i++)
|
||||||
edgesToSpriteIndexOffset[info.Index[i]] = (byte)i;
|
edgesToSpriteIndexOffset[info.Index[i]] = (byte)i;
|
||||||
|
|
||||||
if (info.OverrideFullShroud != null)
|
if (info.OverrideFullShroud != null)
|
||||||
edgesToSpriteIndexOffset[info.OverrideShroudIndex] = (byte)(variantStride - 1);
|
edgesToSpriteIndexOffset[info.OverrideShroudIndex] = (byte)(variantStride - 1);
|
||||||
|
|
||||||
notVisibleEdges = info.UseExtendedIndex ? Edges.AllSides : Edges.AllCorners;
|
|
||||||
|
|
||||||
world.RenderPlayerChanged += WorldOnRenderPlayerChanged;
|
world.RenderPlayerChanged += WorldOnRenderPlayerChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,11 +214,9 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
|
|
||||||
// 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;
|
cellVisibility = puv => Shroud.CellVisibility.Visible;
|
||||||
else
|
else
|
||||||
visibleUnderShroud = puv => map.Contains(puv);
|
cellVisibility = puv => (map.Contains(puv) ? Shroud.CellVisibility.Visible | Shroud.CellVisibility.Explored : Shroud.CellVisibility.Hidden);
|
||||||
|
|
||||||
visibleUnderFog = puv => map.Contains(puv);
|
|
||||||
|
|
||||||
var shroudBlend = shroudSprites[0].Sprite.BlendMode;
|
var shroudBlend = shroudSprites[0].Sprite.BlendMode;
|
||||||
if (shroudSprites.Any(s => s.Sprite.BlendMode != shroudBlend))
|
if (shroudSprites.Any(s => s.Sprite.BlendMode != shroudBlend))
|
||||||
@@ -211,33 +235,61 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
WorldOnRenderPlayerChanged(world.RenderPlayer);
|
WorldOnRenderPlayerChanged(world.RenderPlayer);
|
||||||
}
|
}
|
||||||
|
|
||||||
Edges GetEdges(PPos puv, Func<PPos, bool> isVisible)
|
Shroud.CellVisibility[] GetNeighborsVisbility(PPos puv)
|
||||||
{
|
{
|
||||||
if (!isVisible(puv))
|
|
||||||
return notVisibleEdges;
|
|
||||||
|
|
||||||
var cell = ((MPos)puv).ToCPos(map);
|
var cell = ((MPos)puv).ToCPos(map);
|
||||||
|
neighbors[(int)Neighbor.Top] = cellVisibility((PPos)(cell + new CVec(0, -1)).ToMPos(map));
|
||||||
|
neighbors[(int)Neighbor.Right] = cellVisibility((PPos)(cell + new CVec(1, 0)).ToMPos(map));
|
||||||
|
neighbors[(int)Neighbor.Bottom] = cellVisibility((PPos)(cell + new CVec(0, 1)).ToMPos(map));
|
||||||
|
neighbors[(int)Neighbor.Left] = cellVisibility((PPos)(cell + new CVec(-1, 0)).ToMPos(map));
|
||||||
|
|
||||||
|
neighbors[(int)Neighbor.TopLeft] = cellVisibility((PPos)(cell + new CVec(-1, -1)).ToMPos(map));
|
||||||
|
neighbors[(int)Neighbor.TopRight] = cellVisibility((PPos)(cell + new CVec(1, -1)).ToMPos(map));
|
||||||
|
neighbors[(int)Neighbor.BottomRight] = cellVisibility((PPos)(cell + new CVec(1, 1)).ToMPos(map));
|
||||||
|
neighbors[(int)Neighbor.BottomLeft] = cellVisibility((PPos)(cell + new CVec(-1, 1)).ToMPos(map));
|
||||||
|
|
||||||
|
return neighbors;
|
||||||
|
}
|
||||||
|
|
||||||
|
Edges GetEdges(Shroud.CellVisibility[] neighbors, Shroud.CellVisibility visibleMask)
|
||||||
|
{
|
||||||
// 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 edges = Edges.None;
|
||||||
if (!isVisible((PPos)(cell + new CVec(0, -1)).ToMPos(map))) edge |= Edges.Top;
|
if ((neighbors[(int)Neighbor.Top] & visibleMask) == 0) edges |= Edges.Top;
|
||||||
if (!isVisible((PPos)(cell + new CVec(1, 0)).ToMPos(map))) edge |= Edges.Right;
|
if ((neighbors[(int)Neighbor.Right] & visibleMask) == 0) edges |= Edges.Right;
|
||||||
if (!isVisible((PPos)(cell + new CVec(0, 1)).ToMPos(map))) edge |= Edges.Bottom;
|
if ((neighbors[(int)Neighbor.Bottom] & visibleMask) == 0) edges |= Edges.Bottom;
|
||||||
if (!isVisible((PPos)(cell + new CVec(-1, 0)).ToMPos(map))) edge |= Edges.Left;
|
if ((neighbors[(int)Neighbor.Left] & visibleMask) == 0) edges |= Edges.Left;
|
||||||
|
|
||||||
var ucorner = edge & Edges.AllCorners;
|
var ucorner = edges & Edges.AllCorners;
|
||||||
if (!isVisible((PPos)(cell + new CVec(-1, -1)).ToMPos(map))) edge |= Edges.TopLeft;
|
if ((neighbors[(int)Neighbor.TopLeft] & visibleMask) == 0) edges |= Edges.TopLeft;
|
||||||
if (!isVisible((PPos)(cell + new CVec(1, -1)).ToMPos(map))) edge |= Edges.TopRight;
|
if ((neighbors[(int)Neighbor.TopRight] & visibleMask) == 0) edges |= Edges.TopRight;
|
||||||
if (!isVisible((PPos)(cell + new CVec(1, 1)).ToMPos(map))) edge |= Edges.BottomRight;
|
if ((neighbors[(int)Neighbor.BottomRight] & visibleMask) == 0) edges |= Edges.BottomRight;
|
||||||
if (!isVisible((PPos)(cell + new CVec(-1, 1)).ToMPos(map))) edge |= Edges.BottomLeft;
|
if ((neighbors[(int)Neighbor.BottomLeft] & visibleMask) == 0) edges |= 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
|
||||||
// situation without breaking the edge -> corner enabling
|
// situation without breaking the edge -> corner enabling
|
||||||
// in other combinations. The XOR turns off the corner
|
// in other combinations. The XOR turns off the corner
|
||||||
// bits that are enabled twice, which gives the behavior
|
// bits that are enabled twice, which gives the sprite offset
|
||||||
// we want here.
|
// we want here.
|
||||||
return info.UseExtendedIndex ? edge ^ ucorner : edge & Edges.AllCorners;
|
return info.UseExtendedIndex ? edges ^ ucorner : edges & Edges.AllCorners;
|
||||||
|
}
|
||||||
|
|
||||||
|
(Edges, Edges) GetEdges(PPos puv)
|
||||||
|
{
|
||||||
|
var cv = cellVisibility(puv);
|
||||||
|
|
||||||
|
// If a cell is covered by shroud, then all neigbhors are covered by shroud and fog.
|
||||||
|
if (cv == Shroud.CellVisibility.Hidden)
|
||||||
|
return notVisibleEdgesPair;
|
||||||
|
|
||||||
|
var ncv = GetNeighborsVisbility(puv);
|
||||||
|
|
||||||
|
// If a cell is covered by fog, then all neigbhors are as well.
|
||||||
|
var edgesFog = cv.HasFlag(Shroud.CellVisibility.Visible) ? GetEdges(ncv, Shroud.CellVisibility.Visible) : notVisibleEdgesPair.Item2;
|
||||||
|
|
||||||
|
var edgesShroud = GetEdges(ncv, Shroud.CellVisibility.Explored | Shroud.CellVisibility.Visible);
|
||||||
|
return (edgesShroud, edgesFog);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldOnRenderPlayerChanged(Player player)
|
void WorldOnRenderPlayerChanged(Player player)
|
||||||
@@ -251,14 +303,13 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
|
|
||||||
if (newShroud != null)
|
if (newShroud != null)
|
||||||
{
|
{
|
||||||
visibleUnderShroud = puv => newShroud.IsExplored(puv);
|
cellVisibility = puv => newShroud.GetVisibility(puv);
|
||||||
visibleUnderFog = puv => newShroud.IsVisible(puv);
|
|
||||||
newShroud.OnShroudChanged += UpdateShroudCell;
|
newShroud.OnShroudChanged += UpdateShroudCell;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
visibleUnderShroud = puv => map.Contains(puv);
|
// Visible under shroud: Explored. Visible under fog: Visible.
|
||||||
visibleUnderFog = puv => map.Contains(puv);
|
cellVisibility = puv => (map.Contains(puv) ? Shroud.CellVisibility.Visible | Shroud.CellVisibility.Explored : Shroud.CellVisibility.Hidden);
|
||||||
}
|
}
|
||||||
|
|
||||||
shroud = newShroud;
|
shroud = newShroud;
|
||||||
@@ -287,12 +338,13 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
cellsDirty[uv] = false;
|
cellsDirty[uv] = false;
|
||||||
|
|
||||||
var tileInfo = tileInfos[uv];
|
var tileInfo = tileInfos[uv];
|
||||||
var shroudSprite = GetSprite(shroudSprites, GetEdges(puv, visibleUnderShroud), tileInfo.Variant);
|
var (edgesShroud, edgesFog) = GetEdges(puv);
|
||||||
|
var shroudSprite = GetSprite(shroudSprites, edgesShroud, tileInfo.Variant);
|
||||||
var shroudPos = tileInfo.ScreenPosition;
|
var shroudPos = tileInfo.ScreenPosition;
|
||||||
if (shroudSprite.Sprite != null)
|
if (shroudSprite.Sprite != null)
|
||||||
shroudPos += shroudSprite.Sprite.Offset - 0.5f * shroudSprite.Sprite.Size;
|
shroudPos += shroudSprite.Sprite.Offset - 0.5f * shroudSprite.Sprite.Size;
|
||||||
|
|
||||||
var fogSprite = GetSprite(fogSprites, GetEdges(puv, visibleUnderFog), tileInfo.Variant);
|
var fogSprite = GetSprite(fogSprites, edgesFog, tileInfo.Variant);
|
||||||
var fogPos = tileInfo.ScreenPosition;
|
var fogPos = tileInfo.ScreenPosition;
|
||||||
if (fogSprite.Sprite != null)
|
if (fogSprite.Sprite != null)
|
||||||
fogPos += fogSprite.Sprite.Offset - 0.5f * fogSprite.Sprite.Size;
|
fogPos += fogSprite.Sprite.Offset - 0.5f * fogSprite.Sprite.Size;
|
||||||
|
|||||||
@@ -22,6 +22,9 @@ namespace OpenRA.Mods.Common.Widgets
|
|||||||
{
|
{
|
||||||
public sealed class RadarWidget : Widget, IDisposable
|
public sealed class RadarWidget : Widget, IDisposable
|
||||||
{
|
{
|
||||||
|
public readonly int ColorFog = Color.FromArgb(128, Color.Black).ToArgb();
|
||||||
|
public readonly int ColorShroud = Color.Black.ToArgb();
|
||||||
|
|
||||||
public string WorldInteractionController = null;
|
public string WorldInteractionController = null;
|
||||||
public int AnimationLength = 5;
|
public int AnimationLength = 5;
|
||||||
public string RadarOnlineSound = null;
|
public string RadarOnlineSound = null;
|
||||||
@@ -240,10 +243,11 @@ namespace OpenRA.Mods.Common.Widgets
|
|||||||
void UpdateShroudCell(PPos puv)
|
void UpdateShroudCell(PPos puv)
|
||||||
{
|
{
|
||||||
var color = 0;
|
var color = 0;
|
||||||
if (!currentPlayer.Shroud.IsExplored(puv))
|
var cv = currentPlayer.Shroud.GetVisibility(puv);
|
||||||
color = Color.Black.ToArgb();
|
if (cv == Shroud.CellVisibility.Hidden)
|
||||||
else if (!currentPlayer.Shroud.IsVisible(puv))
|
color = ColorShroud;
|
||||||
color = Color.FromArgb(128, Color.Black).ToArgb();
|
else if (cv.HasFlag(Shroud.CellVisibility.Visible))
|
||||||
|
color = ColorFog;
|
||||||
|
|
||||||
var stride = radarSheet.Size.Width;
|
var stride = radarSheet.Size.Width;
|
||||||
unsafe
|
unsafe
|
||||||
|
|||||||
Reference in New Issue
Block a user