diff --git a/OpenRA.Game/OpenRA.Game.csproj b/OpenRA.Game/OpenRA.Game.csproj index fa6d6941db..ca101ce3fc 100644 --- a/OpenRA.Game/OpenRA.Game.csproj +++ b/OpenRA.Game/OpenRA.Game.csproj @@ -169,7 +169,6 @@ - @@ -177,7 +176,6 @@ - diff --git a/OpenRA.Game/Traits/CreatesShroud.cs b/OpenRA.Game/Traits/CreatesShroud.cs deleted file mode 100644 index 2b6a28b5fc..0000000000 --- a/OpenRA.Game/Traits/CreatesShroud.cs +++ /dev/null @@ -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; } } - } -} \ No newline at end of file diff --git a/OpenRA.Game/Traits/RevealsShroud.cs b/OpenRA.Game/Traits/RevealsShroud.cs deleted file mode 100644 index cea05d54f4..0000000000 --- a/OpenRA.Game/Traits/RevealsShroud.cs +++ /dev/null @@ -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; } } - } -} diff --git a/OpenRA.Game/Traits/World/Shroud.cs b/OpenRA.Game/Traits/World/Shroud.cs index ad8a58a5b3..473a1731b4 100644 --- a/OpenRA.Game/Traits/World/Shroud.cs +++ b/OpenRA.Game/Traits/World/Shroud.cs @@ -54,12 +54,6 @@ namespace OpenRA.Traits generatedShroudCount = new CellLayer(map); explored = new CellLayer(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; isExploredTest = IsExploredCore; isVisibleTest = IsVisibleCore; @@ -78,46 +72,27 @@ namespace OpenRA.Traits Hash += 1; } - public static void UpdateVisibility(IEnumerable shrouds, Actor actor) + public static IEnumerable CellsInRange(Map map, WPos pos, WRange range) { - CPos[] visbility = null; - foreach (var shroud in shrouds) - shroud.UpdateVisibility(actor, ref visbility); + var r = (range.Range + 1023) / 1024; + var limit = range.RangeSquared; + 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 shrouds, Actor actor) + public static IEnumerable CellsInRange(Map map, CPos cell, WRange range) { - CPos[] shrouded = null; - foreach (var shroud in shrouds) - shroud.UpdateShroudGeneration(actor, ref shrouded); + return CellsInRange(map, map.CenterOfCell(cell), range); } - 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(); - } - - static IEnumerable 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(); - if (rs == null || !a.Owner.IsAlliedWith(self.Owner) || rs.Range == WRange.Zero) + if (!a.Owner.IsAlliedWith(self.Owner)) 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) { var uv = c.ToMPos(map); @@ -137,7 +112,7 @@ namespace OpenRA.Traits Invalidate(visible); } - void RemoveVisibility(Actor a) + public void RemoveVisibility(Actor a) { CPos[] visible; if (!visibility.TryGetValue(a, out visible)) @@ -154,25 +129,11 @@ namespace OpenRA.Traits 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.IsInWorld) + if (a.Owner.IsAlliedWith(self.Owner)) return; - RemoveVisibility(a); - AddVisibility(a, ref visible); - } - - void AddShroudGeneration(Actor a, ref CPos[] shrouded) - { - var cs = a.TraitOrDefault(); - 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) generatedShroudCount[c]++; @@ -183,7 +144,7 @@ namespace OpenRA.Traits Invalidate(shrouded); } - void RemoveShroudGeneration(Actor a) + public void RemoveShroudGeneration(Actor a) { CPos[] shrouded; if (!generation.TryGetValue(a, out shrouded)) @@ -196,12 +157,6 @@ namespace OpenRA.Traits 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) { if (oldStance == newStance) @@ -210,12 +165,26 @@ namespace OpenRA.Traits foreach (var a in w.Actors.Where(a => a.Owner == player)) { CPos[] visible = null; - UpdateVisibility(a, ref visible); 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 GetVisOrigins(Actor a) { var ios = a.OccupiesSpace; @@ -229,10 +198,10 @@ namespace OpenRA.Traits return new[] { a.World.Map.CellContaining(a.CenterPosition) }; } - public void Explore(World world, CPos center, WRange range) + public void Explore(World world, IEnumerable cells) { - var changed = new List(); - foreach (var c in FindVisibleTiles(world, center, range)) + var changed = new HashSet(); + foreach (var c in cells) { if (!explored[c]) { diff --git a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj index 7ddbb3a6a0..bfd03510a5 100644 --- a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj +++ b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj @@ -681,6 +681,8 @@ + + diff --git a/OpenRA.Mods.Common/Traits/CreatesShroud.cs b/OpenRA.Mods.Common/Traits/CreatesShroud.cs new file mode 100644 index 0000000000..862a599175 --- /dev/null +++ b/OpenRA.Mods.Common/Traits/CreatesShroud.cs @@ -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(); + } + } +} \ No newline at end of file diff --git a/OpenRA.Mods.Common/Traits/RevealsShroud.cs b/OpenRA.Mods.Common/Traits/RevealsShroud.cs new file mode 100644 index 0000000000..0c5ba61cf0 --- /dev/null +++ b/OpenRA.Mods.Common/Traits/RevealsShroud.cs @@ -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 addCellsToPlayerShroud; + protected Action removeCellsFromPlayerShroud; + protected Func 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; } } + } +} diff --git a/OpenRA.Mods.Common/Traits/World/MPStartLocations.cs b/OpenRA.Mods.Common/Traits/World/MPStartLocations.cs index db50067aae..3cd90e25ad 100644 --- a/OpenRA.Mods.Common/Traits/World/MPStartLocations.cs +++ b/OpenRA.Mods.Common/Traits/World/MPStartLocations.cs @@ -17,14 +17,23 @@ using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { - public class MPStartLocationsInfo : TraitInfo + public class MPStartLocationsInfo : ITraitInfo { public readonly WRange InitialExploreRange = WRange.FromCells(5); + + public virtual object Create(ActorInitializer init) { return new MPStartLocations(this); } } public class MPStartLocations : IWorldLoaded { - public Dictionary Start = new Dictionary(); + readonly MPStartLocationsInfo info; + + public readonly Dictionary Start = new Dictionary(); + + public MPStartLocations(MPStartLocationsInfo info) + { + this.info = info; + } public void WorldLoaded(World world, WorldRenderer wr) { @@ -52,15 +61,18 @@ namespace OpenRA.Mods.Common.Traits } // Explore allied shroud - var explore = world.WorldActor.Info.Traits.Get().InitialExploreRange; + var map = world.Map; foreach (var p in Start.Keys) + { + var cells = Shroud.CellsInRange(map, Start[p], info.InitialExploreRange); foreach (var q in world.Players) if (p.IsAlliedWith(q)) - q.Shroud.Explore(world, Start[p], explore); + q.Shroud.Explore(world, cells); + } // Set viewport 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)