Replace Map.CustomTerrain radar colors with IRadarTerrainLayer.

* TSVeinsRenderer now shows border cells on the radar
* BuildableTerrainLayer now uses the radar colors defined on the individual tiles
* CliffBackImpassabilityLayer no longer overrides the underlying terrain color.
This commit is contained in:
Paul Chote
2021-08-20 18:43:22 +01:00
committed by abcdefg30
parent 72c0c7e38b
commit 7f94d67d39
11 changed files with 278 additions and 58 deletions

View File

@@ -93,7 +93,7 @@ namespace OpenRA.Mods.Common.Traits
}
}
class Bridge : IRender, INotifyDamageStateChanged
class Bridge : IRender, INotifyDamageStateChanged, IRadarSignature
{
readonly BuildingInfo buildingInfo;
readonly Bridge[] neighbours = new Bridge[2];
@@ -108,6 +108,7 @@ namespace OpenRA.Mods.Common.Traits
readonly Lazy<bool> isDangling;
ushort template;
Dictionary<CPos, byte> footprint;
(CPos Cell, Color Color)[] radarSignature;
public LegacyBridgeHut Hut { get; private set; }
public bool IsDangling => isDangling.Value;
@@ -147,17 +148,23 @@ namespace OpenRA.Mods.Common.Traits
{
this.template = template;
this.footprint = footprint;
radarSignature = new (CPos Cell, Color Color)[footprint.Keys.Count];
// Set the initial custom terrain types
// Set the initial state
var i = 0;
foreach (var c in footprint.Keys)
self.World.Map.CustomTerrain[c] = GetTerrainType(c);
{
var tileInfo = GetTerrainInfo(c);
self.World.Map.CustomTerrain[c] = tileInfo.TerrainType;
radarSignature[i++] = (c, tileInfo.GetColor(self.World.LocalRandom));
}
}
byte GetTerrainType(CPos cell)
TerrainTileInfo GetTerrainInfo(CPos cell)
{
var dx = cell - self.Location;
var index = dx.X + terrainInfo.Templates[template].Size.X * dx.Y;
return terrainInfo.GetTerrainIndex(new TerrainTile(template, (byte)index));
return terrainInfo.GetTerrainInfo(new TerrainTile(template, (byte)index));
}
public void LinkNeighbouringBridges(World world, LegacyBridgeLayer bridges)
@@ -308,8 +315,13 @@ namespace OpenRA.Mods.Common.Traits
return;
// Update map
var i = 0;
foreach (var c in footprint.Keys)
self.World.Map.CustomTerrain[c] = GetTerrainType(c);
{
var tileInfo = GetTerrainInfo(c);
self.World.Map.CustomTerrain[c] = tileInfo.TerrainType;
radarSignature[i++] = (c, tileInfo.GetColor(self.World.LocalRandom));
}
// If this bridge repair operation connects two pathfinding domains,
// update the domain index.
@@ -401,5 +413,10 @@ namespace OpenRA.Mods.Common.Traits
neighbours[direction].Demolish(saboteur, direction, damageTypes))));
}
}
void IRadarSignature.PopulateRadarSignatureCells(Actor self, List<(CPos Cell, Color Color)> destinationBuffer)
{
destinationBuffer.AddRange(radarSignature);
}
}
}

View File

@@ -10,6 +10,7 @@
#endregion
using System;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Traits;
@@ -29,6 +30,7 @@ namespace OpenRA.Mods.Common.Traits
public bool IsInitialized { get; private set; }
readonly World world;
IRadarTerrainLayer[] radarTerrainLayers;
CellLayer<(int, int)> terrainColor;
readonly Shroud shroud;
@@ -50,22 +52,20 @@ namespace OpenRA.Mods.Common.Traits
void UpdateTerrainCell(MPos uv)
{
if (!world.Map.CustomTerrain.Contains(uv))
return;
if (shroud.IsVisible(uv))
UpdateTerrainCellColor(uv);
}
void UpdateTerrainCellColor(MPos uv)
{
terrainColor[uv] = GetColor(world.Map, uv);
terrainColor[uv] = GetColor(world.Map, radarTerrainLayers, uv);
CellTerrainColorChanged?.Invoke(uv);
}
public void WorldLoaded(World w, WorldRenderer wr)
{
radarTerrainLayers = w.WorldActor.TraitsImplementing<IRadarTerrainLayer>().ToArray();
terrainColor = new CellLayer<(int, int)>(w.Map);
w.AddFrameEndTask(_ =>
@@ -75,7 +75,8 @@ namespace OpenRA.Mods.Common.Traits
UpdateTerrainCellColor(uv);
world.Map.Tiles.CellEntryChanged += cell => UpdateTerrainCell(cell.ToMPos(world.Map));
world.Map.CustomTerrain.CellEntryChanged += cell => UpdateTerrainCell(cell.ToMPos(world.Map));
foreach (var rtl in radarTerrainLayers)
rtl.CellEntryChanged += cell => UpdateTerrainCell(cell.ToMPos(world.Map));
IsInitialized = true;
});
@@ -83,14 +84,11 @@ namespace OpenRA.Mods.Common.Traits
public (int Left, int Right) this[MPos uv] => terrainColor[uv];
public static (int Left, int Right) GetColor(Map map, MPos uv)
public static (int Left, int Right) GetColor(Map map, IRadarTerrainLayer[] radarTerrainLayers, MPos uv)
{
var custom = map.CustomTerrain[uv];
if (custom != byte.MaxValue)
{
var c = map.Rules.TerrainInfo.TerrainTypes[custom].Color.ToArgb();
return (c, c);
}
foreach (var rtl in radarTerrainLayers)
if (rtl.TryGetTerrainColorPair(uv, out var c))
return (c.Left.ToArgb(), c.Right.ToArgb());
var tc = map.GetTerrainColorPair(uv);
return (tc.Left.ToArgb(), tc.Right.ToArgb());

View File

@@ -20,7 +20,7 @@ namespace OpenRA.Mods.Common.Traits
{
[TraitLocation(SystemActors.EditorWorld)]
[Desc("Required for the map editor to work. Attach this to the world actor.")]
public class EditorResourceLayerInfo : TraitInfo, IResourceLayerInfo, IMapPreviewSignatureInfo
public class EditorResourceLayerInfo : TraitInfo, IResourceLayerInfo
{
[FieldLoader.LoadUsing(nameof(LoadResourceTypes))]
public readonly Dictionary<string, ResourceLayerInfo.ResourceTypeInfo> ResourceTypes = null;
@@ -40,9 +40,28 @@ namespace OpenRA.Mods.Common.Traits
[Desc("Override the density saved in maps with values calculated based on the number of neighbouring resource cells.")]
public readonly bool RecalculateResourceDensity = false;
void IMapPreviewSignatureInfo.PopulateMapPreviewSignatureCells(Map map, ActorInfo ai, ActorReference s, List<(MPos, Color)> destinationBuffer)
bool IResourceLayerInfo.TryGetTerrainType(string resourceType, out string terrainType)
{
ResourceLayerInfo.PopulateMapPreviewSignatureCells(map, ResourceTypes, destinationBuffer);
if (resourceType == null || !ResourceTypes.TryGetValue(resourceType, out var resourceInfo))
{
terrainType = null;
return false;
}
terrainType = resourceInfo.TerrainType;
return true;
}
bool IResourceLayerInfo.TryGetResourceIndex(string resourceType, out byte index)
{
if (resourceType == null || !ResourceTypes.TryGetValue(resourceType, out var resourceInfo))
{
index = 0;
return false;
}
index = resourceInfo.ResourceIndex;
return true;
}
public override object Create(ActorInitializer init) { return new EditorResourceLayer(init.Self, this); }
@@ -74,6 +93,7 @@ namespace OpenRA.Mods.Common.Traits
void IResourceLayer.ClearResources(CPos cell) { ClearResources(cell); }
bool IResourceLayer.IsVisible(CPos cell) { return Map.Contains(cell); }
bool IResourceLayer.IsEmpty => false;
IResourceLayerInfo IResourceLayer.Info => info;
public EditorResourceLayer(Actor self, EditorResourceLayerInfo info)
{

View File

@@ -33,7 +33,7 @@ namespace OpenRA.Mods.Common.Traits
[TraitLocation(SystemActors.World)]
[Desc("Attach this to the world actor.")]
public class ResourceLayerInfo : TraitInfo, IResourceLayerInfo, Requires<BuildingInfluenceInfo>, IMapPreviewSignatureInfo
public class ResourceLayerInfo : TraitInfo, IResourceLayerInfo, Requires<BuildingInfluenceInfo>
{
public class ResourceTypeInfo
{
@@ -76,27 +76,28 @@ namespace OpenRA.Mods.Common.Traits
return ret;
}
public static void PopulateMapPreviewSignatureCells(Map map, Dictionary<string, ResourceTypeInfo> resources, List<(MPos, Color)> destinationBuffer)
bool IResourceLayerInfo.TryGetTerrainType(string resourceType, out string terrainType)
{
var terrainInfo = map.Rules.TerrainInfo;
var colors = resources.Values.ToDictionary(
r => r.ResourceIndex,
r => terrainInfo.TerrainTypes[terrainInfo.GetTerrainIndex(r.TerrainType)].Color);
for (var i = 0; i < map.MapSize.X; i++)
if (resourceType == null || !ResourceTypes.TryGetValue(resourceType, out var resourceInfo))
{
for (var j = 0; j < map.MapSize.Y; j++)
{
var cell = new MPos(i, j);
if (colors.TryGetValue(map.Resources[cell].Type, out var color))
destinationBuffer.Add((cell, color));
}
terrainType = null;
return false;
}
terrainType = resourceInfo.TerrainType;
return true;
}
void IMapPreviewSignatureInfo.PopulateMapPreviewSignatureCells(Map map, ActorInfo ai, ActorReference s, List<(MPos, Color)> destinationBuffer)
bool IResourceLayerInfo.TryGetResourceIndex(string resourceType, out byte index)
{
PopulateMapPreviewSignatureCells(map, ResourceTypes, destinationBuffer);
if (resourceType == null || !ResourceTypes.TryGetValue(resourceType, out var resourceInfo))
{
index = 0;
return false;
}
index = resourceInfo.ResourceIndex;
return true;
}
public override object Create(ActorInitializer init) { return new ResourceLayer(init.Self, this); }
@@ -299,5 +300,6 @@ namespace OpenRA.Mods.Common.Traits
void IResourceLayer.ClearResources(CPos cell) { ClearResources(cell); }
bool IResourceLayer.IsVisible(CPos cell) { return !world.FogObscures(cell); }
bool IResourceLayer.IsEmpty => resCells < 1;
IResourceLayerInfo IResourceLayer.Info => info;
}
}

View File

@@ -9,6 +9,7 @@
*/
#endregion
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
@@ -20,7 +21,7 @@ namespace OpenRA.Mods.Common.Traits
{
[TraitLocation(SystemActors.World | SystemActors.EditorWorld)]
[Desc("Visualizes the state of the `ResourceLayer`.", " Attach this to the world actor.")]
public class ResourceRendererInfo : TraitInfo, Requires<IResourceLayerInfo>
public class ResourceRendererInfo : TraitInfo, Requires<IResourceLayerInfo>, IMapPreviewSignatureInfo
{
public class ResourceTypeInfo
{
@@ -61,10 +62,38 @@ namespace OpenRA.Mods.Common.Traits
return ret;
}
void IMapPreviewSignatureInfo.PopulateMapPreviewSignatureCells(Map map, ActorInfo ai, ActorReference s, List<(MPos, Color)> destinationBuffer)
{
var resourceLayer = ai.TraitInfoOrDefault<IResourceLayerInfo>();
if (resourceLayer == null)
return;
var terrainInfo = map.Rules.TerrainInfo;
var colors = new Dictionary<byte, Color>();
foreach (var r in ResourceTypes.Keys)
{
if (!resourceLayer.TryGetResourceIndex(r, out var resourceIndex) || !resourceLayer.TryGetTerrainType(r, out var terrainType))
continue;
var info = terrainInfo.TerrainTypes[terrainInfo.GetTerrainIndex(terrainType)];
colors.Add(resourceIndex, info.Color);
}
for (var i = 0; i < map.MapSize.X; i++)
{
for (var j = 0; j < map.MapSize.Y; j++)
{
var cell = new MPos(i, j);
if (colors.TryGetValue(map.Resources[cell].Type, out var color))
destinationBuffer.Add((cell, color));
}
}
}
public override object Create(ActorInitializer init) { return new ResourceRenderer(init.Self, this); }
}
public class ResourceRenderer : IResourceRenderer, IWorldLoaded, IRenderOverlay, ITickRender, INotifyActorDisposing
public class ResourceRenderer : IResourceRenderer, IWorldLoaded, IRenderOverlay, ITickRender, INotifyActorDisposing, IRadarTerrainLayer
{
protected readonly ResourceRendererInfo Info;
protected readonly IResourceLayer ResourceLayer;
@@ -284,6 +313,30 @@ namespace OpenRA.Mods.Common.Traits
yield return new SpriteRenderable(sprite, origin, WVec.Zero, 0, palette, sequence.Scale, alpha, float3.Ones, tintModifiers, false);
}
event Action<CPos> IRadarTerrainLayer.CellEntryChanged
{
add => RenderContents.CellEntryChanged += value;
remove => RenderContents.CellEntryChanged -= value;
}
bool IRadarTerrainLayer.TryGetTerrainColorPair(MPos uv, out (Color Left, Color Right) value)
{
value = default;
var type = RenderContents[uv].Type;
if (type == null)
return false;
if (!ResourceLayer.Info.TryGetTerrainType(type, out var terrainType))
return false;
var terrainInfo = World.Map.Rules.TerrainInfo;
var info = terrainInfo.TerrainTypes[terrainInfo.GetTerrainIndex(terrainType)];
value = (info.Color, info.Color);
return true;
}
public readonly struct RendererCellContents
{
public readonly string Type;

View File

@@ -677,7 +677,11 @@ namespace OpenRA.Mods.Common.Traits
IEnumerable<IRenderable> RenderPreview(WorldRenderer wr, TerrainTemplateInfo template, WPos origin);
}
public interface IResourceLayerInfo : ITraitInfoInterface { }
public interface IResourceLayerInfo : ITraitInfoInterface
{
bool TryGetTerrainType(string resourceType, out string terrainType);
bool TryGetResourceIndex(string resourceType, out byte index);
}
[RequireExplicitImplementation]
public interface IResourceLayer
@@ -692,6 +696,7 @@ namespace OpenRA.Mods.Common.Traits
bool IsVisible(CPos cell);
bool IsEmpty { get; }
IResourceLayerInfo Info { get; }
}
[RequireExplicitImplementation]
@@ -703,4 +708,11 @@ namespace OpenRA.Mods.Common.Traits
IEnumerable<IRenderable> RenderUIPreview(WorldRenderer wr, string resourceType, int2 origin, float scale);
IEnumerable<IRenderable> RenderPreview(WorldRenderer wr, string resourceType, WPos origin);
}
[RequireExplicitImplementation]
public interface IRadarTerrainLayer
{
event Action<CPos> CellEntryChanged;
bool TryGetTerrainColorPair(MPos uv, out (Color Left, Color Right) value);
}
}

View File

@@ -34,6 +34,7 @@ namespace OpenRA.Mods.Common.Widgets
readonly World world;
readonly WorldRenderer worldRenderer;
readonly RadarPings radarPings;
readonly IRadarTerrainLayer[] radarTerrainLayers;
readonly bool isRectangularIsometric;
readonly int cellWidth;
readonly int previewWidth;
@@ -69,7 +70,7 @@ namespace OpenRA.Mods.Common.Widgets
this.worldRenderer = worldRenderer;
radarPings = world.WorldActor.TraitOrDefault<RadarPings>();
radarTerrainLayers = world.WorldActor.TraitsImplementing<IRadarTerrainLayer>().ToArray();
isRectangularIsometric = world.Map.Grid.Type == MapGridType.RectangularIsometric;
cellWidth = isRectangularIsometric ? 2 : 1;
previewWidth = world.Map.MapSize.X;
@@ -152,7 +153,8 @@ namespace OpenRA.Mods.Common.Widgets
else
{
world.Map.Tiles.CellEntryChanged -= CellTerrainColorChanged;
world.Map.CustomTerrain.CellEntryChanged -= CellTerrainColorChanged;
foreach (var rtl in radarTerrainLayers)
rtl.CellEntryChanged -= CellTerrainColorChanged;
}
if (newPlayerRadarTerrain != null)
@@ -160,7 +162,8 @@ namespace OpenRA.Mods.Common.Widgets
else
{
world.Map.Tiles.CellEntryChanged += CellTerrainColorChanged;
world.Map.CustomTerrain.CellEntryChanged += CellTerrainColorChanged;
foreach (var rtl in radarTerrainLayers)
rtl.CellEntryChanged += CellTerrainColorChanged;
}
playerRadarTerrain = newPlayerRadarTerrain;
@@ -206,7 +209,8 @@ namespace OpenRA.Mods.Common.Widgets
void UpdateTerrainColor(MPos uv)
{
var colorPair = playerRadarTerrain != null && playerRadarTerrain.IsInitialized ? playerRadarTerrain[uv] : PlayerRadarTerrain.GetColor(world.Map, uv);
var colorPair = playerRadarTerrain != null && playerRadarTerrain.IsInitialized ?
playerRadarTerrain[uv] : PlayerRadarTerrain.GetColor(world.Map, radarTerrainLayers, uv);
var leftColor = colorPair.Left;
var rightColor = colorPair.Right;