Merge pull request #8479 from pchote/merge-shroud-traits

Move more shroud logic to RevealsShroud / GeneratesShroud
This commit is contained in:
Pavel Penev
2015-06-21 19:16:42 +03:00
8 changed files with 180 additions and 172 deletions

View File

@@ -169,7 +169,6 @@
<Compile Include="Sync.cs" /> <Compile Include="Sync.cs" />
<Compile Include="TraitDictionary.cs" /> <Compile Include="TraitDictionary.cs" />
<Compile Include="Traits\Armor.cs" /> <Compile Include="Traits\Armor.cs" />
<Compile Include="Traits\CreatesShroud.cs" />
<Compile Include="Traits\DrawLineToTarget.cs" /> <Compile Include="Traits\DrawLineToTarget.cs" />
<Compile Include="Traits\EditorTilesetFilter.cs" /> <Compile Include="Traits\EditorTilesetFilter.cs" />
<Compile Include="Traits\Health.cs" /> <Compile Include="Traits\Health.cs" />
@@ -177,7 +176,6 @@
<Compile Include="Traits\RejectsOrders.cs" /> <Compile Include="Traits\RejectsOrders.cs" />
<Compile Include="Traits\Player\DeveloperMode.cs" /> <Compile Include="Traits\Player\DeveloperMode.cs" />
<Compile Include="Traits\Player\PlayerResources.cs" /> <Compile Include="Traits\Player\PlayerResources.cs" />
<Compile Include="Traits\RevealsShroud.cs" />
<Compile Include="Traits\Selectable.cs" /> <Compile Include="Traits\Selectable.cs" />
<Compile Include="Traits\Target.cs" /> <Compile Include="Traits\Target.cs" />
<Compile Include="Traits\TraitsInterfaces.cs" /> <Compile Include="Traits\TraitsInterfaces.cs" />

View File

@@ -1,51 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2015 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. For more information,
* see COPYING.
*/
#endregion
using System.Linq;
namespace OpenRA.Traits
{
public class CreatesShroudInfo : ITraitInfo
{
public readonly WRange Range = WRange.Zero;
public object Create(ActorInitializer init) { return new CreatesShroud(init.Self, this); }
}
public class CreatesShroud : ITick, ISync
{
readonly CreatesShroudInfo info;
readonly bool lobbyShroudFogDisabled;
[Sync] CPos cachedLocation;
[Sync] bool cachedDisabled;
public CreatesShroud(Actor self, CreatesShroudInfo info)
{
this.info = info;
lobbyShroudFogDisabled = !self.World.LobbyInfo.GlobalSettings.Shroud && !self.World.LobbyInfo.GlobalSettings.Fog;
}
public void Tick(Actor self)
{
if (lobbyShroudFogDisabled)
return;
var disabled = self.IsDisabled();
if (cachedLocation != self.Location || cachedDisabled != disabled)
{
cachedLocation = self.Location;
cachedDisabled = disabled;
Shroud.UpdateShroudGeneration(self.World.Players.Select(p => p.Shroud), self);
}
}
public WRange Range { get { return cachedDisabled ? WRange.Zero : info.Range; } }
}
}

View File

@@ -1,48 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2015 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. For more information,
* see COPYING.
*/
#endregion
using System.Linq;
namespace OpenRA.Traits
{
public class RevealsShroudInfo : ITraitInfo
{
public readonly WRange Range = WRange.Zero;
public object Create(ActorInitializer init) { return new RevealsShroud(init.Self, this); }
}
public class RevealsShroud : ITick, ISync
{
readonly RevealsShroudInfo info;
readonly bool lobbyShroudFogDisabled;
[Sync] CPos cachedLocation;
public RevealsShroud(Actor self, RevealsShroudInfo info)
{
this.info = info;
lobbyShroudFogDisabled = !self.World.LobbyInfo.GlobalSettings.Shroud && !self.World.LobbyInfo.GlobalSettings.Fog;
}
public void Tick(Actor self)
{
if (lobbyShroudFogDisabled)
return;
if (cachedLocation != self.Location)
{
cachedLocation = self.Location;
Shroud.UpdateVisibility(self.World.Players.Select(p => p.Shroud), self);
}
}
public WRange Range { get { return info.Range; } }
}
}

View File

@@ -54,12 +54,6 @@ namespace OpenRA.Traits
generatedShroudCount = new CellLayer<short>(map); generatedShroudCount = new CellLayer<short>(map);
explored = new CellLayer<bool>(map); explored = new CellLayer<bool>(map);
self.World.ActorAdded += a => { CPos[] visible = null; AddVisibility(a, ref visible); };
self.World.ActorRemoved += RemoveVisibility;
self.World.ActorAdded += a => { CPos[] shrouded = null; AddShroudGeneration(a, ref shrouded); };
self.World.ActorRemoved += RemoveShroudGeneration;
shroudEdgeTest = map.Contains; shroudEdgeTest = map.Contains;
isExploredTest = IsExploredCore; isExploredTest = IsExploredCore;
isVisibleTest = IsVisibleCore; isVisibleTest = IsVisibleCore;
@@ -78,46 +72,27 @@ namespace OpenRA.Traits
Hash += 1; Hash += 1;
} }
public static void UpdateVisibility(IEnumerable<Shroud> shrouds, Actor actor) public static IEnumerable<CPos> CellsInRange(Map map, WPos pos, WRange range)
{ {
CPos[] visbility = null; var r = (range.Range + 1023) / 1024;
foreach (var shroud in shrouds) var limit = range.RangeSquared;
shroud.UpdateVisibility(actor, ref visbility); var cell = map.CellContaining(pos);
foreach (var c in map.FindTilesInCircle(cell, r, true))
if ((map.CenterOfCell(c) - pos).HorizontalLengthSquared <= limit)
yield return c;
} }
public static void UpdateShroudGeneration(IEnumerable<Shroud> shrouds, Actor actor) public static IEnumerable<CPos> CellsInRange(Map map, CPos cell, WRange range)
{ {
CPos[] shrouded = null; return CellsInRange(map, map.CenterOfCell(cell), range);
foreach (var shroud in shrouds)
shroud.UpdateShroudGeneration(actor, ref shrouded);
} }
static CPos[] FindVisibleTiles(Actor actor, WRange range) public void AddVisibility(Actor a, CPos[] visible)
{ {
return GetVisOrigins(actor).SelectMany(o => FindVisibleTiles(actor.World, o, range)).Distinct().ToArray(); if (!a.Owner.IsAlliedWith(self.Owner))
}
static IEnumerable<CPos> FindVisibleTiles(World world, CPos position, WRange radius)
{
var map = world.Map;
var r = (radius.Range + 1023) / 1024;
var limit = radius.RangeSquared;
var pos = map.CenterOfCell(position);
foreach (var cell in map.FindTilesInCircle(position, r, true))
if ((map.CenterOfCell(cell) - pos).HorizontalLengthSquared <= limit)
yield return cell;
}
void AddVisibility(Actor a, ref CPos[] visible)
{
var rs = a.TraitOrDefault<RevealsShroud>();
if (rs == null || !a.Owner.IsAlliedWith(self.Owner) || rs.Range == WRange.Zero)
return; return;
// Lazily generate the visible tiles, allowing the caller to re-use them if desired.
visible = visible ?? FindVisibleTiles(a, rs.Range);
foreach (var c in visible) foreach (var c in visible)
{ {
var uv = c.ToMPos(map); var uv = c.ToMPos(map);
@@ -137,7 +112,7 @@ namespace OpenRA.Traits
Invalidate(visible); Invalidate(visible);
} }
void RemoveVisibility(Actor a) public void RemoveVisibility(Actor a)
{ {
CPos[] visible; CPos[] visible;
if (!visibility.TryGetValue(a, out visible)) if (!visibility.TryGetValue(a, out visible))
@@ -154,25 +129,11 @@ namespace OpenRA.Traits
Invalidate(visible); Invalidate(visible);
} }
void UpdateVisibility(Actor a, ref CPos[] visible) public void AddShroudGeneration(Actor a, CPos[] shrouded)
{ {
// Actors outside the world don't have any vis if (a.Owner.IsAlliedWith(self.Owner))
if (!a.IsInWorld)
return; return;
RemoveVisibility(a);
AddVisibility(a, ref visible);
}
void AddShroudGeneration(Actor a, ref CPos[] shrouded)
{
var cs = a.TraitOrDefault<CreatesShroud>();
if (cs == null || a.Owner.IsAlliedWith(self.Owner) || cs.Range == WRange.Zero)
return;
// Lazily generate the shrouded tiles, allowing the caller to re-use them if desired.
shrouded = shrouded ?? FindVisibleTiles(a, cs.Range);
foreach (var c in shrouded) foreach (var c in shrouded)
generatedShroudCount[c]++; generatedShroudCount[c]++;
@@ -183,7 +144,7 @@ namespace OpenRA.Traits
Invalidate(shrouded); Invalidate(shrouded);
} }
void RemoveShroudGeneration(Actor a) public void RemoveShroudGeneration(Actor a)
{ {
CPos[] shrouded; CPos[] shrouded;
if (!generation.TryGetValue(a, out shrouded)) if (!generation.TryGetValue(a, out shrouded))
@@ -196,12 +157,6 @@ namespace OpenRA.Traits
Invalidate(shrouded); Invalidate(shrouded);
} }
void UpdateShroudGeneration(Actor a, ref CPos[] shrouded)
{
RemoveShroudGeneration(a);
AddShroudGeneration(a, ref shrouded);
}
public void UpdatePlayerStance(World w, Player player, Stance oldStance, Stance newStance) public void UpdatePlayerStance(World w, Player player, Stance oldStance, Stance newStance)
{ {
if (oldStance == newStance) if (oldStance == newStance)
@@ -210,12 +165,26 @@ namespace OpenRA.Traits
foreach (var a in w.Actors.Where(a => a.Owner == player)) foreach (var a in w.Actors.Where(a => a.Owner == player))
{ {
CPos[] visible = null; CPos[] visible = null;
UpdateVisibility(a, ref visible);
CPos[] shrouded = null; CPos[] shrouded = null;
UpdateShroudGeneration(a, ref shrouded); foreach (var p in self.World.Players)
{
if (p.Shroud.visibility.TryGetValue(self, out visible))
{
p.Shroud.RemoveVisibility(self);
p.Shroud.AddVisibility(self, visible);
}
if (p.Shroud.generation.TryGetValue(self, out shrouded))
{
p.Shroud.RemoveShroudGeneration(self);
p.Shroud.AddShroudGeneration(self, shrouded);
}
}
} }
} }
// TODO: Actor vis will be split into separate cases for
// "cells that I reveal from" and "cells that reveal me"
public static IEnumerable<CPos> GetVisOrigins(Actor a) public static IEnumerable<CPos> GetVisOrigins(Actor a)
{ {
var ios = a.OccupiesSpace; var ios = a.OccupiesSpace;
@@ -229,10 +198,10 @@ namespace OpenRA.Traits
return new[] { a.World.Map.CellContaining(a.CenterPosition) }; return new[] { a.World.Map.CellContaining(a.CenterPosition) };
} }
public void Explore(World world, CPos center, WRange range) public void Explore(World world, IEnumerable<CPos> cells)
{ {
var changed = new List<CPos>(); var changed = new HashSet<CPos>();
foreach (var c in FindVisibleTiles(world, center, range)) foreach (var c in cells)
{ {
if (!explored[c]) if (!explored[c])
{ {

View File

@@ -681,6 +681,8 @@
<Compile Include="Traits\Modifiers\HiddenUnderShroud.cs" /> <Compile Include="Traits\Modifiers\HiddenUnderShroud.cs" />
<Compile Include="Lint\CheckDefaultVisibility.cs" /> <Compile Include="Lint\CheckDefaultVisibility.cs" />
<Compile Include="Traits\Modifiers\AlwaysVisible.cs" /> <Compile Include="Traits\Modifiers\AlwaysVisible.cs" />
<Compile Include="Traits\CreatesShroud.cs" />
<Compile Include="Traits\RevealsShroud.cs" />
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup> <PropertyGroup>

View File

@@ -0,0 +1,28 @@
#region Copyright & License Information
/*
* Copyright 2007-2015 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. For more information,
* see COPYING.
*/
#endregion
namespace OpenRA.Mods.Common.Traits
{
public class CreatesShroudInfo : RevealsShroudInfo
{
public override object Create(ActorInitializer init) { return new CreatesShroud(init.Self, this); }
}
public class CreatesShroud : RevealsShroud
{
public CreatesShroud(Actor self, CreatesShroudInfo info)
: base(self, info)
{
addCellsToPlayerShroud = (p, c) => p.Shroud.AddShroudGeneration(self, c);
removeCellsFromPlayerShroud = p => p.Shroud.RemoveShroudGeneration(self);
isDisabled = () => self.IsDisabled();
}
}
}

View File

@@ -0,0 +1,98 @@
#region Copyright & License Information
/*
* Copyright 2007-2015 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. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Linq;
using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits
{
public class RevealsShroudInfo : ITraitInfo
{
public readonly WRange Range = WRange.Zero;
public virtual object Create(ActorInitializer init) { return new RevealsShroud(init.Self, this); }
}
public class RevealsShroud : ITick, ISync, INotifyAddedToWorld, INotifyRemovedFromWorld
{
static readonly CPos[] NoCells = { };
readonly RevealsShroudInfo info;
readonly bool lobbyShroudFogDisabled;
[Sync] CPos cachedLocation;
[Sync] bool cachedDisabled;
protected Action<Player, CPos[]> addCellsToPlayerShroud;
protected Action<Player> removeCellsFromPlayerShroud;
protected Func<bool> isDisabled;
public RevealsShroud(Actor self, RevealsShroudInfo info)
{
this.info = info;
lobbyShroudFogDisabled = !self.World.LobbyInfo.GlobalSettings.Shroud && !self.World.LobbyInfo.GlobalSettings.Fog;
addCellsToPlayerShroud = (p, c) => p.Shroud.AddVisibility(self, c);
removeCellsFromPlayerShroud = p => p.Shroud.RemoveVisibility(self);
isDisabled = () => false;
}
CPos[] Cells(Actor self)
{
var map = self.World.Map;
var range = Range;
if (range == WRange.Zero)
return NoCells;
return Shroud.GetVisOrigins(self)
.SelectMany(c => Shroud.CellsInRange(map, c, range))
.Distinct().ToArray();
}
public void Tick(Actor self)
{
if (lobbyShroudFogDisabled || !self.IsInWorld)
return;
var location = self.Location;
var disabled = isDisabled();
if (cachedLocation == location && cachedDisabled == disabled)
return;
cachedLocation = location;
cachedDisabled = disabled;
var cells = Cells(self);
foreach (var p in self.World.Players)
{
removeCellsFromPlayerShroud(p);
addCellsToPlayerShroud(p, cells);
}
}
public void AddedToWorld(Actor self)
{
cachedLocation = self.Location;
cachedDisabled = isDisabled();
var cells = Cells(self);
foreach (var p in self.World.Players)
addCellsToPlayerShroud(p, cells);
}
public void RemovedFromWorld(Actor self)
{
foreach (var p in self.World.Players)
removeCellsFromPlayerShroud(p);
}
public WRange Range { get { return cachedDisabled ? WRange.Zero : info.Range; } }
}
}

View File

@@ -17,14 +17,23 @@ using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits namespace OpenRA.Mods.Common.Traits
{ {
public class MPStartLocationsInfo : TraitInfo<MPStartLocations> public class MPStartLocationsInfo : ITraitInfo
{ {
public readonly WRange InitialExploreRange = WRange.FromCells(5); public readonly WRange InitialExploreRange = WRange.FromCells(5);
public virtual object Create(ActorInitializer init) { return new MPStartLocations(this); }
} }
public class MPStartLocations : IWorldLoaded public class MPStartLocations : IWorldLoaded
{ {
public Dictionary<Player, CPos> Start = new Dictionary<Player, CPos>(); readonly MPStartLocationsInfo info;
public readonly Dictionary<Player, CPos> Start = new Dictionary<Player, CPos>();
public MPStartLocations(MPStartLocationsInfo info)
{
this.info = info;
}
public void WorldLoaded(World world, WorldRenderer wr) public void WorldLoaded(World world, WorldRenderer wr)
{ {
@@ -52,15 +61,18 @@ namespace OpenRA.Mods.Common.Traits
} }
// Explore allied shroud // Explore allied shroud
var explore = world.WorldActor.Info.Traits.Get<MPStartLocationsInfo>().InitialExploreRange; var map = world.Map;
foreach (var p in Start.Keys) foreach (var p in Start.Keys)
{
var cells = Shroud.CellsInRange(map, Start[p], info.InitialExploreRange);
foreach (var q in world.Players) foreach (var q in world.Players)
if (p.IsAlliedWith(q)) if (p.IsAlliedWith(q))
q.Shroud.Explore(world, Start[p], explore); q.Shroud.Explore(world, cells);
}
// Set viewport // Set viewport
if (world.LocalPlayer != null && Start.ContainsKey(world.LocalPlayer)) if (world.LocalPlayer != null && Start.ContainsKey(world.LocalPlayer))
wr.Viewport.Center(world.Map.CenterOfCell(Start[world.LocalPlayer])); wr.Viewport.Center(map.CenterOfCell(Start[world.LocalPlayer]));
} }
static Player FindPlayerInSlot(World world, string pr) static Player FindPlayerInSlot(World world, string pr)