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

@@ -675,16 +675,10 @@ namespace OpenRA
public (Color Left, Color Right) GetTerrainColorPair(MPos uv) public (Color Left, Color Right) GetTerrainColorPair(MPos uv)
{ {
Color left, right;
var terrainInfo = Rules.TerrainInfo; var terrainInfo = Rules.TerrainInfo;
var type = terrainInfo.GetTerrainInfo(Tiles[uv]); var type = terrainInfo.GetTerrainInfo(Tiles[uv]);
if (type.MinColor != type.MaxColor) var left = type.GetColor(Game.CosmeticRandom);
{ var right = type.GetColor(Game.CosmeticRandom);
left = Exts.ColorLerp(Game.CosmeticRandom.NextFloat(), type.MinColor, type.MaxColor);
right = Exts.ColorLerp(Game.CosmeticRandom.NextFloat(), type.MinColor, type.MaxColor);
}
else
left = right = type.MinColor;
if (terrainInfo.MinHeightColorBrightness != 1.0f || terrainInfo.MaxHeightColorBrightness != 1.0f) if (terrainInfo.MinHeightColorBrightness != 1.0f || terrainInfo.MaxHeightColorBrightness != 1.0f)
{ {

View File

@@ -12,6 +12,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using OpenRA.FileSystem; using OpenRA.FileSystem;
using OpenRA.Primitives; using OpenRA.Primitives;
using OpenRA.Support;
using OpenRA.Traits; using OpenRA.Traits;
namespace OpenRA namespace OpenRA
@@ -45,6 +46,14 @@ namespace OpenRA
public readonly byte RampType; public readonly byte RampType;
public readonly Color MinColor; public readonly Color MinColor;
public readonly Color MaxColor; public readonly Color MaxColor;
public Color GetColor(MersenneTwister random)
{
if (MinColor != MaxColor)
return Exts.ColorLerp(random.NextFloat(), MinColor, MaxColor);
return MinColor;
}
} }
public class TerrainTypeInfo public class TerrainTypeInfo

View File

@@ -13,6 +13,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using OpenRA.Graphics; using OpenRA.Graphics;
using OpenRA.Mods.Common;
using OpenRA.Mods.Common.Traits; using OpenRA.Mods.Common.Traits;
using OpenRA.Primitives; using OpenRA.Primitives;
using OpenRA.Traits; using OpenRA.Traits;
@@ -20,7 +21,7 @@ using OpenRA.Traits;
namespace OpenRA.Mods.Cnc.Traits namespace OpenRA.Mods.Cnc.Traits
{ {
[Desc("Renders the Tiberian Sun Vein resources.", "Attach this to the world actor")] [Desc("Renders the Tiberian Sun Vein resources.", "Attach this to the world actor")]
public class TSVeinsRendererInfo : TraitInfo, Requires<IResourceLayerInfo> public class TSVeinsRendererInfo : TraitInfo, Requires<IResourceLayerInfo>, IMapPreviewSignatureInfo
{ {
[FieldLoader.Require] [FieldLoader.Require]
[Desc("Resource type used for veins.")] [Desc("Resource type used for veins.")]
@@ -45,10 +46,69 @@ namespace OpenRA.Mods.Cnc.Traits
[Desc("Actor types that should be treated as veins for adjacency.")] [Desc("Actor types that should be treated as veins for adjacency.")]
public readonly HashSet<string> VeinholeActors = new HashSet<string> { }; public readonly HashSet<string> VeinholeActors = new HashSet<string> { };
void IMapPreviewSignatureInfo.PopulateMapPreviewSignatureCells(Map map, ActorInfo ai, ActorReference s, List<(MPos, Color)> destinationBuffer)
{
var resourceLayer = ai.TraitInfoOrDefault<IResourceLayerInfo>();
if (resourceLayer == null)
return;
if (!resourceLayer.TryGetResourceIndex(ResourceType, out var resourceIndex) || !resourceLayer.TryGetTerrainType(ResourceType, out var terrainType))
return;
var veinholeCells = new HashSet<CPos>();
foreach (var kv in map.ActorDefinitions)
{
var type = kv.Value.Value;
if (!VeinholeActors.Contains(type))
continue;
var actorReference = new ActorReference(type, kv.Value.ToDictionary());
var location = actorReference.Get<LocationInit>();
var veinholeInfo = map.Rules.Actors[actorReference.Type];
foreach (var cell in veinholeInfo.TraitInfo<IOccupySpaceInfo>().OccupiedCells(veinholeInfo, location.Value))
veinholeCells.Add(cell.Key);
}
var terrainInfo = map.Rules.TerrainInfo;
var info = terrainInfo.TerrainTypes[terrainInfo.GetTerrainIndex(terrainType)];
for (var i = 0; i < map.MapSize.X; i++)
{
for (var j = 0; j < map.MapSize.Y; j++)
{
var uv = new MPos(i, j);
// Cell contains veins
if (map.Resources[uv].Type == resourceIndex)
{
destinationBuffer.Add((uv, info.Color));
continue;
}
// Cell is a vein border if it is flat and adjacent to at least one cell
// that is also flat and contains veins (borders are not drawn next to slope vein cells)
var isBorder = map.Ramp[uv] == 0 && Common.Util.ExpandFootprint(uv.ToCPos(map), false).Any(c =>
{
if (!map.Resources.Contains(c))
return false;
if (veinholeCells.Contains(c))
return true;
return map.Resources[c].Type == resourceIndex && map.Ramp[c] == 0;
});
if (isBorder)
destinationBuffer.Add((uv, info.Color));
}
}
}
public override object Create(ActorInitializer init) { return new TSVeinsRenderer(init.Self, this); } public override object Create(ActorInitializer init) { return new TSVeinsRenderer(init.Self, this); }
} }
public class TSVeinsRenderer : IResourceRenderer, IWorldLoaded, IRenderOverlay, ITickRender, INotifyActorDisposing public class TSVeinsRenderer : IResourceRenderer, IWorldLoaded, IRenderOverlay, ITickRender, INotifyActorDisposing, IRadarTerrainLayer
{ {
[Flags] [Flags]
enum Adjacency : byte enum Adjacency : byte
@@ -95,6 +155,7 @@ namespace OpenRA.Mods.Cnc.Traits
readonly Queue<CPos> cleanDirty = new Queue<CPos>(); readonly Queue<CPos> cleanDirty = new Queue<CPos>();
readonly HashSet<CPos> veinholeCells = new HashSet<CPos>(); readonly HashSet<CPos> veinholeCells = new HashSet<CPos>();
readonly int maxDensity; readonly int maxDensity;
readonly Color veinRadarColor;
ISpriteSequence veinSequence; ISpriteSequence veinSequence;
PaletteReference veinPalette; PaletteReference veinPalette;
@@ -109,6 +170,10 @@ namespace OpenRA.Mods.Cnc.Traits
resourceLayer.CellChanged += AddDirtyCell; resourceLayer.CellChanged += AddDirtyCell;
maxDensity = resourceLayer.GetMaxDensity(info.ResourceType); maxDensity = resourceLayer.GetMaxDensity(info.ResourceType);
var terrainInfo = self.World.Map.Rules.TerrainInfo;
resourceLayer.Info.TryGetTerrainType(info.ResourceType, out var terrainType);
veinRadarColor = terrainInfo.TerrainTypes[terrainInfo.GetTerrainIndex(terrainType)].Color;
renderIndices = new CellLayer<int[]>(world.Map); renderIndices = new CellLayer<int[]>(world.Map);
borders = new CellLayer<Adjacency>(world.Map); borders = new CellLayer<Adjacency>(world.Map);
} }
@@ -334,5 +399,30 @@ namespace OpenRA.Mods.Cnc.Traits
var tintModifiers = veinSequence.IgnoreWorldTint ? TintModifiers.IgnoreWorldTint : TintModifiers.None; var tintModifiers = veinSequence.IgnoreWorldTint ? TintModifiers.IgnoreWorldTint : TintModifiers.None;
yield return new SpriteRenderable(sprite, origin, WVec.Zero, 0, palette, veinSequence.Scale, alpha, float3.Ones, tintModifiers, false); yield return new SpriteRenderable(sprite, origin, WVec.Zero, 0, palette, veinSequence.Scale, alpha, float3.Ones, tintModifiers, false);
} }
event Action<CPos> IRadarTerrainLayer.CellEntryChanged
{
add
{
renderIndices.CellEntryChanged += value;
borders.CellEntryChanged += value;
}
remove
{
renderIndices.CellEntryChanged -= value;
borders.CellEntryChanged -= value;
}
}
bool IRadarTerrainLayer.TryGetTerrainColorPair(MPos uv, out (Color Left, Color Right) value)
{
value = default;
if (borders[uv] == Adjacency.None && renderIndices[uv] == null)
return false;
value = (veinRadarColor, veinRadarColor);
return true;
}
} }
} }

View File

@@ -93,7 +93,7 @@ namespace OpenRA.Mods.Common.Traits
} }
} }
class Bridge : IRender, INotifyDamageStateChanged class Bridge : IRender, INotifyDamageStateChanged, IRadarSignature
{ {
readonly BuildingInfo buildingInfo; readonly BuildingInfo buildingInfo;
readonly Bridge[] neighbours = new Bridge[2]; readonly Bridge[] neighbours = new Bridge[2];
@@ -108,6 +108,7 @@ namespace OpenRA.Mods.Common.Traits
readonly Lazy<bool> isDangling; readonly Lazy<bool> isDangling;
ushort template; ushort template;
Dictionary<CPos, byte> footprint; Dictionary<CPos, byte> footprint;
(CPos Cell, Color Color)[] radarSignature;
public LegacyBridgeHut Hut { get; private set; } public LegacyBridgeHut Hut { get; private set; }
public bool IsDangling => isDangling.Value; public bool IsDangling => isDangling.Value;
@@ -147,17 +148,23 @@ namespace OpenRA.Mods.Common.Traits
{ {
this.template = template; this.template = template;
this.footprint = footprint; 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) 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 dx = cell - self.Location;
var index = dx.X + terrainInfo.Templates[template].Size.X * dx.Y; 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) public void LinkNeighbouringBridges(World world, LegacyBridgeLayer bridges)
@@ -308,8 +315,13 @@ namespace OpenRA.Mods.Common.Traits
return; return;
// Update map // Update map
var i = 0;
foreach (var c in footprint.Keys) 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, // If this bridge repair operation connects two pathfinding domains,
// update the domain index. // update the domain index.
@@ -401,5 +413,10 @@ namespace OpenRA.Mods.Common.Traits
neighbours[direction].Demolish(saboteur, direction, damageTypes)))); 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 #endregion
using System; using System;
using System.Linq;
using OpenRA.Graphics; using OpenRA.Graphics;
using OpenRA.Traits; using OpenRA.Traits;
@@ -29,6 +30,7 @@ namespace OpenRA.Mods.Common.Traits
public bool IsInitialized { get; private set; } public bool IsInitialized { get; private set; }
readonly World world; readonly World world;
IRadarTerrainLayer[] radarTerrainLayers;
CellLayer<(int, int)> terrainColor; CellLayer<(int, int)> terrainColor;
readonly Shroud shroud; readonly Shroud shroud;
@@ -50,22 +52,20 @@ namespace OpenRA.Mods.Common.Traits
void UpdateTerrainCell(MPos uv) void UpdateTerrainCell(MPos uv)
{ {
if (!world.Map.CustomTerrain.Contains(uv))
return;
if (shroud.IsVisible(uv)) if (shroud.IsVisible(uv))
UpdateTerrainCellColor(uv); UpdateTerrainCellColor(uv);
} }
void UpdateTerrainCellColor(MPos uv) void UpdateTerrainCellColor(MPos uv)
{ {
terrainColor[uv] = GetColor(world.Map, uv); terrainColor[uv] = GetColor(world.Map, radarTerrainLayers, uv);
CellTerrainColorChanged?.Invoke(uv); CellTerrainColorChanged?.Invoke(uv);
} }
public void WorldLoaded(World w, WorldRenderer wr) public void WorldLoaded(World w, WorldRenderer wr)
{ {
radarTerrainLayers = w.WorldActor.TraitsImplementing<IRadarTerrainLayer>().ToArray();
terrainColor = new CellLayer<(int, int)>(w.Map); terrainColor = new CellLayer<(int, int)>(w.Map);
w.AddFrameEndTask(_ => w.AddFrameEndTask(_ =>
@@ -75,7 +75,8 @@ namespace OpenRA.Mods.Common.Traits
UpdateTerrainCellColor(uv); UpdateTerrainCellColor(uv);
world.Map.Tiles.CellEntryChanged += cell => UpdateTerrainCell(cell.ToMPos(world.Map)); 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; IsInitialized = true;
}); });
@@ -83,14 +84,11 @@ namespace OpenRA.Mods.Common.Traits
public (int Left, int Right) this[MPos uv] => terrainColor[uv]; 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]; foreach (var rtl in radarTerrainLayers)
if (custom != byte.MaxValue) if (rtl.TryGetTerrainColorPair(uv, out var c))
{ return (c.Left.ToArgb(), c.Right.ToArgb());
var c = map.Rules.TerrainInfo.TerrainTypes[custom].Color.ToArgb();
return (c, c);
}
var tc = map.GetTerrainColorPair(uv); var tc = map.GetTerrainColorPair(uv);
return (tc.Left.ToArgb(), tc.Right.ToArgb()); return (tc.Left.ToArgb(), tc.Right.ToArgb());

View File

@@ -20,7 +20,7 @@ namespace OpenRA.Mods.Common.Traits
{ {
[TraitLocation(SystemActors.EditorWorld)] [TraitLocation(SystemActors.EditorWorld)]
[Desc("Required for the map editor to work. Attach this to the world actor.")] [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))] [FieldLoader.LoadUsing(nameof(LoadResourceTypes))]
public readonly Dictionary<string, ResourceLayerInfo.ResourceTypeInfo> ResourceTypes = null; 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.")] [Desc("Override the density saved in maps with values calculated based on the number of neighbouring resource cells.")]
public readonly bool RecalculateResourceDensity = false; 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); } 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); } void IResourceLayer.ClearResources(CPos cell) { ClearResources(cell); }
bool IResourceLayer.IsVisible(CPos cell) { return Map.Contains(cell); } bool IResourceLayer.IsVisible(CPos cell) { return Map.Contains(cell); }
bool IResourceLayer.IsEmpty => false; bool IResourceLayer.IsEmpty => false;
IResourceLayerInfo IResourceLayer.Info => info;
public EditorResourceLayer(Actor self, EditorResourceLayerInfo info) public EditorResourceLayer(Actor self, EditorResourceLayerInfo info)
{ {

View File

@@ -33,7 +33,7 @@ namespace OpenRA.Mods.Common.Traits
[TraitLocation(SystemActors.World)] [TraitLocation(SystemActors.World)]
[Desc("Attach this to the world actor.")] [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 public class ResourceTypeInfo
{ {
@@ -76,27 +76,28 @@ namespace OpenRA.Mods.Common.Traits
return ret; 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; if (resourceType == null || !ResourceTypes.TryGetValue(resourceType, out var resourceInfo))
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++)
{ {
for (var j = 0; j < map.MapSize.Y; j++) terrainType = null;
{ return false;
var cell = new MPos(i, j);
if (colors.TryGetValue(map.Resources[cell].Type, out var color))
destinationBuffer.Add((cell, color));
}
} }
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); } 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); } void IResourceLayer.ClearResources(CPos cell) { ClearResources(cell); }
bool IResourceLayer.IsVisible(CPos cell) { return !world.FogObscures(cell); } bool IResourceLayer.IsVisible(CPos cell) { return !world.FogObscures(cell); }
bool IResourceLayer.IsEmpty => resCells < 1; bool IResourceLayer.IsEmpty => resCells < 1;
IResourceLayerInfo IResourceLayer.Info => info;
} }
} }

View File

@@ -9,6 +9,7 @@
*/ */
#endregion #endregion
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@@ -20,7 +21,7 @@ namespace OpenRA.Mods.Common.Traits
{ {
[TraitLocation(SystemActors.World | SystemActors.EditorWorld)] [TraitLocation(SystemActors.World | SystemActors.EditorWorld)]
[Desc("Visualizes the state of the `ResourceLayer`.", " Attach this to the world actor.")] [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 public class ResourceTypeInfo
{ {
@@ -61,10 +62,38 @@ namespace OpenRA.Mods.Common.Traits
return ret; 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 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 ResourceRendererInfo Info;
protected readonly IResourceLayer ResourceLayer; 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); 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 struct RendererCellContents
{ {
public readonly string Type; public readonly string Type;

View File

@@ -677,7 +677,11 @@ namespace OpenRA.Mods.Common.Traits
IEnumerable<IRenderable> RenderPreview(WorldRenderer wr, TerrainTemplateInfo template, WPos origin); 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] [RequireExplicitImplementation]
public interface IResourceLayer public interface IResourceLayer
@@ -692,6 +696,7 @@ namespace OpenRA.Mods.Common.Traits
bool IsVisible(CPos cell); bool IsVisible(CPos cell);
bool IsEmpty { get; } bool IsEmpty { get; }
IResourceLayerInfo Info { get; }
} }
[RequireExplicitImplementation] [RequireExplicitImplementation]
@@ -703,4 +708,11 @@ namespace OpenRA.Mods.Common.Traits
IEnumerable<IRenderable> RenderUIPreview(WorldRenderer wr, string resourceType, int2 origin, float scale); IEnumerable<IRenderable> RenderUIPreview(WorldRenderer wr, string resourceType, int2 origin, float scale);
IEnumerable<IRenderable> RenderPreview(WorldRenderer wr, string resourceType, WPos origin); 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 World world;
readonly WorldRenderer worldRenderer; readonly WorldRenderer worldRenderer;
readonly RadarPings radarPings; readonly RadarPings radarPings;
readonly IRadarTerrainLayer[] radarTerrainLayers;
readonly bool isRectangularIsometric; readonly bool isRectangularIsometric;
readonly int cellWidth; readonly int cellWidth;
readonly int previewWidth; readonly int previewWidth;
@@ -69,7 +70,7 @@ namespace OpenRA.Mods.Common.Widgets
this.worldRenderer = worldRenderer; this.worldRenderer = worldRenderer;
radarPings = world.WorldActor.TraitOrDefault<RadarPings>(); radarPings = world.WorldActor.TraitOrDefault<RadarPings>();
radarTerrainLayers = world.WorldActor.TraitsImplementing<IRadarTerrainLayer>().ToArray();
isRectangularIsometric = world.Map.Grid.Type == MapGridType.RectangularIsometric; isRectangularIsometric = world.Map.Grid.Type == MapGridType.RectangularIsometric;
cellWidth = isRectangularIsometric ? 2 : 1; cellWidth = isRectangularIsometric ? 2 : 1;
previewWidth = world.Map.MapSize.X; previewWidth = world.Map.MapSize.X;
@@ -152,7 +153,8 @@ namespace OpenRA.Mods.Common.Widgets
else else
{ {
world.Map.Tiles.CellEntryChanged -= CellTerrainColorChanged; world.Map.Tiles.CellEntryChanged -= CellTerrainColorChanged;
world.Map.CustomTerrain.CellEntryChanged -= CellTerrainColorChanged; foreach (var rtl in radarTerrainLayers)
rtl.CellEntryChanged -= CellTerrainColorChanged;
} }
if (newPlayerRadarTerrain != null) if (newPlayerRadarTerrain != null)
@@ -160,7 +162,8 @@ namespace OpenRA.Mods.Common.Widgets
else else
{ {
world.Map.Tiles.CellEntryChanged += CellTerrainColorChanged; world.Map.Tiles.CellEntryChanged += CellTerrainColorChanged;
world.Map.CustomTerrain.CellEntryChanged += CellTerrainColorChanged; foreach (var rtl in radarTerrainLayers)
rtl.CellEntryChanged += CellTerrainColorChanged;
} }
playerRadarTerrain = newPlayerRadarTerrain; playerRadarTerrain = newPlayerRadarTerrain;
@@ -206,7 +209,8 @@ namespace OpenRA.Mods.Common.Widgets
void UpdateTerrainColor(MPos uv) 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 leftColor = colorPair.Left;
var rightColor = colorPair.Right; var rightColor = colorPair.Right;

View File

@@ -9,10 +9,12 @@
*/ */
#endregion #endregion
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using OpenRA.Graphics; using OpenRA.Graphics;
using OpenRA.Mods.Common.Traits; using OpenRA.Mods.Common.Traits;
using OpenRA.Primitives;
using OpenRA.Traits; using OpenRA.Traits;
namespace OpenRA.Mods.D2k.Traits namespace OpenRA.Mods.D2k.Traits
@@ -30,13 +32,14 @@ namespace OpenRA.Mods.D2k.Traits
public override object Create(ActorInitializer init) { return new BuildableTerrainLayer(init.Self, this); } public override object Create(ActorInitializer init) { return new BuildableTerrainLayer(init.Self, this); }
} }
public class BuildableTerrainLayer : IRenderOverlay, IWorldLoaded, ITickRender, INotifyActorDisposing public class BuildableTerrainLayer : IRenderOverlay, IWorldLoaded, ITickRender, IRadarTerrainLayer, INotifyActorDisposing
{ {
readonly BuildableTerrainLayerInfo info; readonly BuildableTerrainLayerInfo info;
readonly Dictionary<CPos, TerrainTile?> dirty = new Dictionary<CPos, TerrainTile?>(); readonly Dictionary<CPos, TerrainTile?> dirty = new Dictionary<CPos, TerrainTile?>();
readonly ITiledTerrainRenderer terrainRenderer; readonly ITiledTerrainRenderer terrainRenderer;
readonly World world; readonly World world;
readonly CellLayer<int> strength; readonly CellLayer<int> strength;
readonly CellLayer<(Color, Color)> radarColor;
TerrainSpriteLayer render; TerrainSpriteLayer render;
PaletteReference paletteReference; PaletteReference paletteReference;
@@ -47,6 +50,7 @@ namespace OpenRA.Mods.D2k.Traits
this.info = info; this.info = info;
world = self.World; world = self.World;
strength = new CellLayer<int>(world.Map); strength = new CellLayer<int>(world.Map);
radarColor = new CellLayer<(Color, Color)>(world.Map);
terrainRenderer = self.Trait<ITiledTerrainRenderer>(); terrainRenderer = self.Trait<ITiledTerrainRenderer>();
} }
@@ -61,8 +65,11 @@ namespace OpenRA.Mods.D2k.Traits
if (!strength.Contains(cell)) if (!strength.Contains(cell))
return; return;
world.Map.CustomTerrain[cell] = world.Map.Rules.TerrainInfo.GetTerrainIndex(tile); var uv = cell.ToMPos(world.Map);
strength[cell] = info.MaxStrength; var tileInfo = world.Map.Rules.TerrainInfo.GetTerrainInfo(tile);
world.Map.CustomTerrain[uv] = tileInfo.TerrainType;
strength[uv] = info.MaxStrength;
radarColor[uv] = (tileInfo.GetColor(world.LocalRandom), tileInfo.GetColor(world.LocalRandom));
dirty[cell] = tile; dirty[cell] = tile;
} }
@@ -85,8 +92,10 @@ namespace OpenRA.Mods.D2k.Traits
if (!strength.Contains(cell)) if (!strength.Contains(cell))
return; return;
world.Map.CustomTerrain[cell] = byte.MaxValue; var uv = cell.ToMPos(world.Map);
world.Map.CustomTerrain[uv] = byte.MaxValue;
strength[cell] = 0; strength[cell] = 0;
radarColor[uv] = (Color.Transparent, Color.Transparent);
dirty[cell] = null; dirty[cell] = null;
} }
@@ -121,6 +130,18 @@ namespace OpenRA.Mods.D2k.Traits
render.Draw(wr.Viewport); render.Draw(wr.Viewport);
} }
event Action<CPos> IRadarTerrainLayer.CellEntryChanged
{
add => radarColor.CellEntryChanged += value;
remove => radarColor.CellEntryChanged -= value;
}
bool IRadarTerrainLayer.TryGetTerrainColorPair(MPos uv, out (Color Left, Color Right) value)
{
value = radarColor[uv];
return strength[uv] > 0;
}
void INotifyActorDisposing.Disposing(Actor self) void INotifyActorDisposing.Disposing(Actor self)
{ {
if (disposed) if (disposed)