Add a trait PlayerRadarTerrain to track explored terrain

This commit is contained in:
teinarss
2019-09-10 19:49:11 +02:00
committed by reaperrr
parent ee00954f2e
commit a47f60d3a6
7 changed files with 213 additions and 42 deletions

View File

@@ -48,6 +48,8 @@ namespace OpenRA
public Player[] Players = new Player[0];
public event Action<Player> RenderPlayerChanged;
public void SetPlayers(IEnumerable<Player> players, Player localPlayer)
{
if (Players.Length > 0)
@@ -84,7 +86,12 @@ namespace OpenRA
set
{
if (LocalPlayer == null || LocalPlayer.UnlockedRenderPlayer)
{
renderPlayer = value;
if (RenderPlayerChanged != null)
RenderPlayerChanged(value);
}
}
}

View File

@@ -0,0 +1,119 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 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, either version 3 of
* the License, or (at your option) any later version. For more
* information, see COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
using OpenRA.Graphics;
using OpenRA.Primitives;
using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits
{
public class PlayerRadarTerrainInfo : ITraitInfo, Requires<ShroudInfo>
{
public object Create(ActorInitializer init)
{
return new PlayerRadarTerrain(init.Self);
}
}
public class PlayerRadarTerrain : IWorldLoaded
{
public bool IsInitialized { get; private set; }
readonly World world;
CellLayer<Pair<int, int>> terrainColor;
readonly HashSet<MPos> dirtyTerrainCells = new HashSet<MPos>();
readonly Shroud shroud;
public event Action<MPos> CellTerrainColorChanged = null;
public PlayerRadarTerrain(Actor self)
{
world = self.World;
shroud = self.Trait<Shroud>();
shroud.CellsChanged += OnShroudCellsChanged;
}
void OnShroudCellsChanged(IEnumerable<PPos> puvs)
{
foreach (var puv in puvs)
{
foreach (var uv in world.Map.Unproject(puv))
{
if (dirtyTerrainCells.Contains(uv))
{
UpdateTerrainCellColor(uv);
dirtyTerrainCells.Remove(uv);
}
}
}
}
void UpdateTerrainCell(CPos cell)
{
var uv = cell.ToMPos(world.Map);
if (!world.Map.CustomTerrain.Contains(uv))
return;
if (!shroud.IsVisible(uv))
dirtyTerrainCells.Add(uv);
else
UpdateTerrainCellColor(uv);
}
void UpdateTerrainCellColor(MPos uv)
{
terrainColor[uv] = GetColor(world.Map, uv);
if (CellTerrainColorChanged != null)
CellTerrainColorChanged(uv);
}
public void WorldLoaded(World w, WorldRenderer wr)
{
terrainColor = new CellLayer<Pair<int, int>>(w.Map);
w.AddFrameEndTask(_ =>
{
// Set initial terrain data
foreach (var uv in world.Map.AllCells.MapCoords)
UpdateTerrainCellColor(uv);
world.Map.Tiles.CellEntryChanged += UpdateTerrainCell;
world.Map.CustomTerrain.CellEntryChanged += UpdateTerrainCell;
IsInitialized = true;
});
}
public Pair<int, int> this[MPos uv]
{
get { return terrainColor[uv]; }
}
public static Pair<int, int> GetColor(Map map, MPos uv)
{
var custom = map.CustomTerrain[uv];
int leftColor, rightColor;
if (custom == byte.MaxValue)
{
var type = map.Rules.TileSet.GetTileInfo(map.Tiles[uv]);
leftColor = type != null ? type.LeftColor.ToArgb() : Color.Black.ToArgb();
rightColor = type != null ? type.RightColor.ToArgb() : Color.Black.ToArgb();
}
else
leftColor = rightColor = map.Rules.TileSet[custom].Color.ToArgb();
return Pair.New(leftColor, rightColor);
}
}
}

View File

@@ -57,6 +57,8 @@ namespace OpenRA.Mods.Common.Widgets
Sprite actorSprite;
Sprite shroudSprite;
Shroud renderShroud;
PlayerRadarTerrain playerRadarTerrain;
Player currentPlayer;
public string SoundUp { get; private set; }
public string SoundDown { get; private set; }
@@ -66,7 +68,9 @@ namespace OpenRA.Mods.Common.Widgets
{
this.world = world;
this.worldRenderer = worldRenderer;
radarPings = world.WorldActor.TraitOrDefault<RadarPings>();
MarkShroudDirty(world.Map.AllCells.MapCoords.Select(uv => (PPos)uv));
isRectangularIsometric = world.Map.Grid.Type == MapGridType.RectangularIsometric;
cellWidth = isRectangularIsometric ? 2 : 1;
@@ -76,6 +80,11 @@ namespace OpenRA.Mods.Common.Widgets
previewWidth = 2 * previewWidth - 1;
}
void CellTerrainColorChanged(MPos puv)
{
UpdateTerrainColor(puv);
}
public override void Initialize(WidgetArgs args)
{
base.Initialize(args);
@@ -87,14 +96,74 @@ namespace OpenRA.Mods.Common.Widgets
MapBoundsChanged();
if (world.Type == WorldType.Regular)
SetPlayer(world.LocalPlayer ?? world.RenderPlayer);
else
{
// Set initial terrain data
foreach (var cell in world.Map.AllCells)
UpdateTerrainCell(cell);
foreach (var uv in world.Map.AllCells.MapCoords)
UpdateTerrainColor(uv);
world.Map.Tiles.CellEntryChanged += UpdateTerrainCell;
world.Map.CustomTerrain.CellEntryChanged += UpdateTerrainCell;
}
world.RenderPlayerChanged += WorldOnRenderPlayerChanged;
}
void UpdateTerrainCell(CPos cell)
{
var uv = cell.ToMPos(world.Map);
UpdateTerrainColor(uv);
}
void WorldOnRenderPlayerChanged(Player player)
{
SetPlayer(player);
// Set initial terrain data
foreach (var uv in world.Map.AllCells.MapCoords)
UpdateTerrainColor(uv);
}
void SetPlayer(Player player)
{
currentPlayer = player;
var newRenderShroud = player != null ? player.Shroud : null;
if (newRenderShroud != renderShroud)
{
if (renderShroud != null)
renderShroud.CellsChanged -= MarkShroudDirty;
if (newRenderShroud != null)
{
// Redraw the full shroud sprite
MarkShroudDirty(world.Map.AllCells.MapCoords.Select(uv => (PPos)uv));
// Update the notification binding
newRenderShroud.CellsChanged += MarkShroudDirty;
}
renderShroud = newRenderShroud;
}
var newPlayerRadarTerrain =
currentPlayer != null ? currentPlayer.PlayerActor.TraitOrDefault<PlayerRadarTerrain>() : null;
if (newPlayerRadarTerrain != playerRadarTerrain)
{
if (playerRadarTerrain != null)
playerRadarTerrain.CellTerrainColorChanged -= CellTerrainColorChanged;
if (newPlayerRadarTerrain != null)
newPlayerRadarTerrain.CellTerrainColorChanged += CellTerrainColorChanged;
playerRadarTerrain = newPlayerRadarTerrain;
}
}
void MapBoundsChanged()
{
var map = world.Map;
@@ -132,23 +201,11 @@ namespace OpenRA.Mods.Common.Widgets
actorSprite = new Sprite(radarSheet, new Rectangle(b.Location + new Size(0, previewHeight), b.Size), TextureChannel.RGBA);
}
void UpdateTerrainCell(CPos cell)
void UpdateTerrainColor(MPos uv)
{
var uv = cell.ToMPos(world.Map);
if (!world.Map.CustomTerrain.Contains(uv))
return;
var custom = world.Map.CustomTerrain[uv];
int leftColor, rightColor;
if (custom == byte.MaxValue)
{
var type = world.Map.Rules.TileSet.GetTileInfo(world.Map.Tiles[uv]);
leftColor = type != null ? type.LeftColor.ToArgb() : Color.Black.ToArgb();
rightColor = type != null ? type.RightColor.ToArgb() : Color.Black.ToArgb();
}
else
leftColor = rightColor = world.Map.Rules.TileSet[custom].Color.ToArgb();
var colorPair = playerRadarTerrain != null && playerRadarTerrain.IsInitialized ? playerRadarTerrain[uv] : PlayerRadarTerrain.GetColor(world.Map, uv);
var leftColor = colorPair.First;
var rightColor = colorPair.Second;
var stride = radarSheet.Size.Width;
@@ -341,25 +398,6 @@ namespace OpenRA.Mods.Common.Widgets
if (enabled)
{
var rp = world.RenderPlayer;
var newRenderShroud = rp != null ? rp.Shroud : null;
if (newRenderShroud != renderShroud)
{
if (renderShroud != null)
renderShroud.CellsChanged -= MarkShroudDirty;
if (newRenderShroud != null)
{
// Redraw the full shroud sprite
MarkShroudDirty(world.Map.AllCells.MapCoords.Select(uv => (PPos)uv));
// Update the notification binding
newRenderShroud.CellsChanged += MarkShroudDirty;
}
renderShroud = newRenderShroud;
}
// The actor layer is updated every tick
var stride = radarSheet.Size.Width;
Array.Clear(radarData, 4 * actorSprite.Bounds.Top * stride, 4 * actorSprite.Bounds.Height * stride);
@@ -451,8 +489,11 @@ namespace OpenRA.Mods.Common.Widgets
public override void Removed()
{
base.Removed();
world.Map.Tiles.CellEntryChanged -= UpdateTerrainCell;
world.Map.CustomTerrain.CellEntryChanged -= UpdateTerrainCell;
if (playerRadarTerrain != null)
playerRadarTerrain.CellTerrainColorChanged -= CellTerrainColorChanged;
world.RenderPlayerChanged -= WorldOnRenderPlayerChanged;
Dispose();
}

View File

@@ -60,3 +60,4 @@ Player:
PlayerExperience:
ConditionManager:
GameSaveViewportManager:
PlayerRadarTerrain:

View File

@@ -152,3 +152,4 @@ Player:
PlayerExperience:
ConditionManager:
GameSaveViewportManager:
PlayerRadarTerrain:

View File

@@ -151,3 +151,4 @@ Player:
PlayerExperience:
ConditionManager:
GameSaveViewportManager:
PlayerRadarTerrain:

View File

@@ -124,3 +124,4 @@ Player:
PlayerExperience:
ConditionManager:
GameSaveViewportManager:
PlayerRadarTerrain: