From 7f94d67d39d35ef030ccf9ba532b77c6824473f1 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Fri, 20 Aug 2021 18:43:22 +0100 Subject: [PATCH] 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. --- OpenRA.Game/Map/Map.cs | 10 +- OpenRA.Game/Map/TerrainInfo.cs | 9 ++ .../Traits/World/TSVeinsRenderer.cs | 94 ++++++++++++++++++- OpenRA.Mods.Common/Traits/Buildings/Bridge.cs | 29 ++++-- .../Traits/Player/PlayerRadarTerrain.cs | 22 ++--- .../Traits/World/EditorResourceLayer.cs | 26 ++++- .../Traits/World/ResourceLayer.cs | 34 +++---- .../Traits/World/ResourceRenderer.cs | 57 ++++++++++- OpenRA.Mods.Common/TraitsInterfaces.cs | 14 ++- OpenRA.Mods.Common/Widgets/RadarWidget.cs | 12 ++- .../Traits/World/BuildableTerrainLayer.cs | 29 +++++- 11 files changed, 278 insertions(+), 58 deletions(-) diff --git a/OpenRA.Game/Map/Map.cs b/OpenRA.Game/Map/Map.cs index 522297ce8c..f97bde2277 100644 --- a/OpenRA.Game/Map/Map.cs +++ b/OpenRA.Game/Map/Map.cs @@ -675,16 +675,10 @@ namespace OpenRA public (Color Left, Color Right) GetTerrainColorPair(MPos uv) { - Color left, right; var terrainInfo = Rules.TerrainInfo; var type = terrainInfo.GetTerrainInfo(Tiles[uv]); - if (type.MinColor != type.MaxColor) - { - 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; + var left = type.GetColor(Game.CosmeticRandom); + var right = type.GetColor(Game.CosmeticRandom); if (terrainInfo.MinHeightColorBrightness != 1.0f || terrainInfo.MaxHeightColorBrightness != 1.0f) { diff --git a/OpenRA.Game/Map/TerrainInfo.cs b/OpenRA.Game/Map/TerrainInfo.cs index a8f42438e2..0f44bcd0cb 100644 --- a/OpenRA.Game/Map/TerrainInfo.cs +++ b/OpenRA.Game/Map/TerrainInfo.cs @@ -12,6 +12,7 @@ using System.Collections.Generic; using OpenRA.FileSystem; using OpenRA.Primitives; +using OpenRA.Support; using OpenRA.Traits; namespace OpenRA @@ -45,6 +46,14 @@ namespace OpenRA public readonly byte RampType; public readonly Color MinColor; public readonly Color MaxColor; + + public Color GetColor(MersenneTwister random) + { + if (MinColor != MaxColor) + return Exts.ColorLerp(random.NextFloat(), MinColor, MaxColor); + + return MinColor; + } } public class TerrainTypeInfo diff --git a/OpenRA.Mods.Cnc/Traits/World/TSVeinsRenderer.cs b/OpenRA.Mods.Cnc/Traits/World/TSVeinsRenderer.cs index 895c800f43..16120c6f12 100644 --- a/OpenRA.Mods.Cnc/Traits/World/TSVeinsRenderer.cs +++ b/OpenRA.Mods.Cnc/Traits/World/TSVeinsRenderer.cs @@ -13,6 +13,7 @@ using System; using System.Collections.Generic; using System.Linq; using OpenRA.Graphics; +using OpenRA.Mods.Common; using OpenRA.Mods.Common.Traits; using OpenRA.Primitives; using OpenRA.Traits; @@ -20,7 +21,7 @@ using OpenRA.Traits; namespace OpenRA.Mods.Cnc.Traits { [Desc("Renders the Tiberian Sun Vein resources.", "Attach this to the world actor")] - public class TSVeinsRendererInfo : TraitInfo, Requires + public class TSVeinsRendererInfo : TraitInfo, Requires, IMapPreviewSignatureInfo { [FieldLoader.Require] [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.")] public readonly HashSet VeinholeActors = new HashSet { }; + void IMapPreviewSignatureInfo.PopulateMapPreviewSignatureCells(Map map, ActorInfo ai, ActorReference s, List<(MPos, Color)> destinationBuffer) + { + var resourceLayer = ai.TraitInfoOrDefault(); + if (resourceLayer == null) + return; + + if (!resourceLayer.TryGetResourceIndex(ResourceType, out var resourceIndex) || !resourceLayer.TryGetTerrainType(ResourceType, out var terrainType)) + return; + + var veinholeCells = new HashSet(); + + 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(); + var veinholeInfo = map.Rules.Actors[actorReference.Type]; + foreach (var cell in veinholeInfo.TraitInfo().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 class TSVeinsRenderer : IResourceRenderer, IWorldLoaded, IRenderOverlay, ITickRender, INotifyActorDisposing + public class TSVeinsRenderer : IResourceRenderer, IWorldLoaded, IRenderOverlay, ITickRender, INotifyActorDisposing, IRadarTerrainLayer { [Flags] enum Adjacency : byte @@ -95,6 +155,7 @@ namespace OpenRA.Mods.Cnc.Traits readonly Queue cleanDirty = new Queue(); readonly HashSet veinholeCells = new HashSet(); readonly int maxDensity; + readonly Color veinRadarColor; ISpriteSequence veinSequence; PaletteReference veinPalette; @@ -109,6 +170,10 @@ namespace OpenRA.Mods.Cnc.Traits resourceLayer.CellChanged += AddDirtyCell; 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(world.Map); borders = new CellLayer(world.Map); } @@ -334,5 +399,30 @@ namespace OpenRA.Mods.Cnc.Traits 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); } + + event Action 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; + } } } diff --git a/OpenRA.Mods.Common/Traits/Buildings/Bridge.cs b/OpenRA.Mods.Common/Traits/Buildings/Bridge.cs index f66a9cdc0d..46b13c92b4 100644 --- a/OpenRA.Mods.Common/Traits/Buildings/Bridge.cs +++ b/OpenRA.Mods.Common/Traits/Buildings/Bridge.cs @@ -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 isDangling; ushort template; Dictionary 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); + } } } diff --git a/OpenRA.Mods.Common/Traits/Player/PlayerRadarTerrain.cs b/OpenRA.Mods.Common/Traits/Player/PlayerRadarTerrain.cs index ec8040cee4..e3782b52b6 100644 --- a/OpenRA.Mods.Common/Traits/Player/PlayerRadarTerrain.cs +++ b/OpenRA.Mods.Common/Traits/Player/PlayerRadarTerrain.cs @@ -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().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()); diff --git a/OpenRA.Mods.Common/Traits/World/EditorResourceLayer.cs b/OpenRA.Mods.Common/Traits/World/EditorResourceLayer.cs index a7a5ace739..e4092b1c95 100644 --- a/OpenRA.Mods.Common/Traits/World/EditorResourceLayer.cs +++ b/OpenRA.Mods.Common/Traits/World/EditorResourceLayer.cs @@ -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 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) { diff --git a/OpenRA.Mods.Common/Traits/World/ResourceLayer.cs b/OpenRA.Mods.Common/Traits/World/ResourceLayer.cs index 194ae1edc0..c40e77752c 100644 --- a/OpenRA.Mods.Common/Traits/World/ResourceLayer.cs +++ b/OpenRA.Mods.Common/Traits/World/ResourceLayer.cs @@ -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, IMapPreviewSignatureInfo + public class ResourceLayerInfo : TraitInfo, IResourceLayerInfo, Requires { public class ResourceTypeInfo { @@ -76,27 +76,28 @@ namespace OpenRA.Mods.Common.Traits return ret; } - public static void PopulateMapPreviewSignatureCells(Map map, Dictionary 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; } } diff --git a/OpenRA.Mods.Common/Traits/World/ResourceRenderer.cs b/OpenRA.Mods.Common/Traits/World/ResourceRenderer.cs index 5bc84bcd35..315cde1488 100644 --- a/OpenRA.Mods.Common/Traits/World/ResourceRenderer.cs +++ b/OpenRA.Mods.Common/Traits/World/ResourceRenderer.cs @@ -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 + public class ResourceRendererInfo : TraitInfo, Requires, 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(); + if (resourceLayer == null) + return; + + var terrainInfo = map.Rules.TerrainInfo; + var colors = new Dictionary(); + 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 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; diff --git a/OpenRA.Mods.Common/TraitsInterfaces.cs b/OpenRA.Mods.Common/TraitsInterfaces.cs index 2183f201ff..33cc33eb89 100644 --- a/OpenRA.Mods.Common/TraitsInterfaces.cs +++ b/OpenRA.Mods.Common/TraitsInterfaces.cs @@ -677,7 +677,11 @@ namespace OpenRA.Mods.Common.Traits IEnumerable 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 RenderUIPreview(WorldRenderer wr, string resourceType, int2 origin, float scale); IEnumerable RenderPreview(WorldRenderer wr, string resourceType, WPos origin); } + + [RequireExplicitImplementation] + public interface IRadarTerrainLayer + { + event Action CellEntryChanged; + bool TryGetTerrainColorPair(MPos uv, out (Color Left, Color Right) value); + } } diff --git a/OpenRA.Mods.Common/Widgets/RadarWidget.cs b/OpenRA.Mods.Common/Widgets/RadarWidget.cs index fcb6bb4425..b9a263870c 100644 --- a/OpenRA.Mods.Common/Widgets/RadarWidget.cs +++ b/OpenRA.Mods.Common/Widgets/RadarWidget.cs @@ -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(); - + radarTerrainLayers = world.WorldActor.TraitsImplementing().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; diff --git a/OpenRA.Mods.D2k/Traits/World/BuildableTerrainLayer.cs b/OpenRA.Mods.D2k/Traits/World/BuildableTerrainLayer.cs index 62d602d091..39d4caccd5 100644 --- a/OpenRA.Mods.D2k/Traits/World/BuildableTerrainLayer.cs +++ b/OpenRA.Mods.D2k/Traits/World/BuildableTerrainLayer.cs @@ -9,10 +9,12 @@ */ #endregion +using System; using System.Collections.Generic; using System.Linq; using OpenRA.Graphics; using OpenRA.Mods.Common.Traits; +using OpenRA.Primitives; using OpenRA.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 class BuildableTerrainLayer : IRenderOverlay, IWorldLoaded, ITickRender, INotifyActorDisposing + public class BuildableTerrainLayer : IRenderOverlay, IWorldLoaded, ITickRender, IRadarTerrainLayer, INotifyActorDisposing { readonly BuildableTerrainLayerInfo info; readonly Dictionary dirty = new Dictionary(); readonly ITiledTerrainRenderer terrainRenderer; readonly World world; readonly CellLayer strength; + readonly CellLayer<(Color, Color)> radarColor; TerrainSpriteLayer render; PaletteReference paletteReference; @@ -47,6 +50,7 @@ namespace OpenRA.Mods.D2k.Traits this.info = info; world = self.World; strength = new CellLayer(world.Map); + radarColor = new CellLayer<(Color, Color)>(world.Map); terrainRenderer = self.Trait(); } @@ -61,8 +65,11 @@ namespace OpenRA.Mods.D2k.Traits if (!strength.Contains(cell)) return; - world.Map.CustomTerrain[cell] = world.Map.Rules.TerrainInfo.GetTerrainIndex(tile); - strength[cell] = info.MaxStrength; + var uv = cell.ToMPos(world.Map); + 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; } @@ -85,8 +92,10 @@ namespace OpenRA.Mods.D2k.Traits if (!strength.Contains(cell)) return; - world.Map.CustomTerrain[cell] = byte.MaxValue; + var uv = cell.ToMPos(world.Map); + world.Map.CustomTerrain[uv] = byte.MaxValue; strength[cell] = 0; + radarColor[uv] = (Color.Transparent, Color.Transparent); dirty[cell] = null; } @@ -121,6 +130,18 @@ namespace OpenRA.Mods.D2k.Traits render.Draw(wr.Viewport); } + event Action 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) { if (disposed)