smart queries for World.Actors
This commit is contained in:
54
OpenRa.FileFormats/Collections/Set.cs
Executable file
54
OpenRa.FileFormats/Collections/Set.cs
Executable file
@@ -0,0 +1,54 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using IjwFramework.Types;
|
||||
using System.Collections;
|
||||
|
||||
namespace OpenRa.Collections
|
||||
{
|
||||
public class Set<T> : IEnumerable<T>
|
||||
{
|
||||
Dictionary<T, bool> data = new Dictionary<T, bool>();
|
||||
|
||||
public void Add( T obj )
|
||||
{
|
||||
data.Add( obj, false );
|
||||
if( OnAdd != null )
|
||||
OnAdd( obj );
|
||||
}
|
||||
|
||||
public void Remove( T obj )
|
||||
{
|
||||
data.Remove( obj );
|
||||
if( OnRemove != null )
|
||||
OnRemove( obj );
|
||||
}
|
||||
|
||||
public event Action<T> OnAdd;
|
||||
public event Action<T> OnRemove;
|
||||
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
return data.Keys.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
}
|
||||
|
||||
public class CachedView<T,U> : Set<U>
|
||||
{
|
||||
public CachedView( Set<T> set, Func<T,bool> include, Func<T,U> store )
|
||||
{
|
||||
foreach( var t in set )
|
||||
if( include( t ) )
|
||||
Add( store( t ) );
|
||||
|
||||
set.OnAdd += obj => { if( include( obj ) ) Add( store( obj ) ); };
|
||||
set.OnRemove += obj => { if( include( obj ) ) Remove( store( obj ) ); };
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -51,6 +51,7 @@
|
||||
<Compile Include="AudLoader.cs" />
|
||||
<Compile Include="Blowfish.cs" />
|
||||
<Compile Include="BlowfishKeyProvider.cs" />
|
||||
<Compile Include="Collections\Set.cs" />
|
||||
<Compile Include="DisposableAction.cs" />
|
||||
<Compile Include="Dune2ShpReader.cs" />
|
||||
<Compile Include="Exts.cs" />
|
||||
|
||||
@@ -196,5 +196,16 @@ namespace OpenRa
|
||||
{
|
||||
return currentActivity;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return (int)ActorID;
|
||||
}
|
||||
|
||||
public override bool Equals( object obj )
|
||||
{
|
||||
var o = obj as Actor;
|
||||
return ( o != null && o.ActorID == ActorID );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -503,9 +503,9 @@ namespace OpenRa
|
||||
|
||||
void DrawRadar( World world )
|
||||
{
|
||||
var hasNewRadar = world.Actors.Any(a => a.Owner == world.LocalPlayer
|
||||
&& a.traits.Contains<ProvidesRadar>()
|
||||
&& a.traits.Get<ProvidesRadar>().IsActive);
|
||||
var hasNewRadar = world.Queries.OwnedBy[world.LocalPlayer]
|
||||
.WithTrait<ProvidesRadar>()
|
||||
.Any(a => a.Trait.IsActive);
|
||||
|
||||
if (hasNewRadar != hasRadar)
|
||||
{
|
||||
@@ -661,7 +661,7 @@ namespace OpenRa
|
||||
Rectangle repairRect = new Rectangle(buttonOrigin.X, buttonOrigin.Y, repairButton.Image.bounds.Width, repairButton.Image.bounds.Height);
|
||||
var repairDrawPos = new float2(repairRect.Location);
|
||||
|
||||
var hasFact = world.Actors.Any(a => a.Owner == world.LocalPlayer && a.traits.Contains<ConstructionYard>());
|
||||
var hasFact = world.Queries.OwnedBy[world.LocalPlayer].WithTrait<ConstructionYard>().Any();
|
||||
|
||||
if (Game.Settings.RepairRequiresConyard && !hasFact)
|
||||
repairButton.ReplaceAnim("disabled");
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace OpenRa.GameRules
|
||||
public Cache<string, List<Actor>> GatherBuildings( Player player )
|
||||
{
|
||||
var ret = new Cache<string, List<Actor>>( x => new List<Actor>() );
|
||||
foreach( var b in player.World.Actors.Where( x => x.Owner == player && x.Info.Traits.Contains<BuildingInfo>() ) )
|
||||
foreach( var b in player.World.Queries.OwnedBy[player].Where( x=>x.Info.Traits.Contains<BuildingInfo>() ) )
|
||||
{
|
||||
ret[ b.Info.Name ].Add( b );
|
||||
var buildable = b.Info.Traits.GetOrDefault<BuildableInfo>();
|
||||
|
||||
@@ -93,7 +93,7 @@ namespace OpenRa.Graphics
|
||||
|
||||
mapOnlySheet.Texture.SetData(oreLayer);
|
||||
|
||||
if (!world.Actors.Any(a => a.Owner == world.LocalPlayer && a.traits.Contains<ProvidesRadar>()))
|
||||
if (!world.Queries.OwnedBy[world.LocalPlayer].WithTrait<ProvidesRadar>().Any())
|
||||
return;
|
||||
|
||||
var bitmap = new Bitmap(oreLayer);
|
||||
@@ -114,9 +114,9 @@ namespace OpenRa.Graphics
|
||||
(b.Owner != null ? playerColors[(int)b.Owner.Palette] : colors[4]).ToArgb();
|
||||
}
|
||||
|
||||
foreach (var a in world.Actors.Where(a => a.traits.Contains<Unit>()))
|
||||
*(c + (a.Location.Y * bitmapData.Stride >> 2) + a.Location.X) =
|
||||
playerColors[(int)a.Owner.Palette].ToArgb();
|
||||
foreach (var a in world.Queries.WithTrait<Unit>())
|
||||
*(c + (a.Actor.Location.Y * bitmapData.Stride >> 2) + a.Actor.Location.X) =
|
||||
playerColors[(int)a.Actor.Owner.Palette].ToArgb();
|
||||
|
||||
unchecked
|
||||
{
|
||||
|
||||
@@ -126,7 +126,7 @@ namespace OpenRa.Graphics
|
||||
|
||||
public void GoToStartLocation( Player player )
|
||||
{
|
||||
Center(player.World.Actors.Where(a => a.Owner == player && a.traits.Contains<Selectable>()));
|
||||
Center( player.World.Queries.OwnedBy[ player ].WithTrait<Selectable>().Select( a => a.Actor ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,8 +38,9 @@ namespace OpenRa.Orders
|
||||
if (!Game.Settings.RepairRequiresConyard)
|
||||
return;
|
||||
|
||||
var hasFact = world.Actors
|
||||
.Any(a => a.Owner == world.LocalPlayer && a.traits.Contains<ConstructionYard>());
|
||||
var hasFact = world.Queries.OwnedBy[world.LocalPlayer]
|
||||
.WithTrait<ConstructionYard>()
|
||||
.Any();
|
||||
|
||||
if (!hasFact)
|
||||
Game.controller.CancelInputMode();
|
||||
|
||||
@@ -49,12 +49,12 @@ namespace OpenRa
|
||||
PowerProvided = 0;
|
||||
PowerDrained = 0;
|
||||
|
||||
var myBuildings = World.Actors
|
||||
.Where(a => a.Owner == this && a.traits.Contains<Building>());
|
||||
var myBuildings = World.Queries.OwnedBy[this]
|
||||
.WithTrait<Building>();
|
||||
|
||||
foreach (var a in myBuildings)
|
||||
{
|
||||
var p = a.traits.Get<Building>().GetPowerUsage();
|
||||
var p = a.Trait.GetPowerUsage();
|
||||
if (p > 0)
|
||||
PowerProvided += p;
|
||||
else
|
||||
@@ -80,8 +80,8 @@ namespace OpenRa
|
||||
|
||||
void UpdateOreCapacity()
|
||||
{
|
||||
OreCapacity = World.Actors
|
||||
.Where(a => a.Owner == this && a.traits.Contains<StoresOre>())
|
||||
OreCapacity = World.Queries.OwnedBy[this]
|
||||
.Where(a => a.traits.Contains<StoresOre>())
|
||||
.Select(a => a.Info.Traits.Get<StoresOreInfo>())
|
||||
.Sum(b => b.Capacity);
|
||||
}
|
||||
|
||||
@@ -35,9 +35,9 @@ namespace OpenRa
|
||||
{
|
||||
// Clear active flags
|
||||
gapActive = new bool[128, 128];
|
||||
foreach (var a in world.Actors.Where(a => a.traits.Contains<GeneratesGap>() && owner != a.Owner))
|
||||
foreach (var a in world.Queries.WithTrait<GeneratesGap>().Where(a => owner != a.Actor.Owner))
|
||||
{
|
||||
foreach (var t in a.traits.Get<GeneratesGap>().GetShroudedTiles())
|
||||
foreach (var t in a.Trait.GetShroudedTiles())
|
||||
gapActive[t.X, t.Y] = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -42,8 +42,9 @@ namespace OpenRa.Traits.Activities
|
||||
umt = mobile.GetMovementType(),
|
||||
checkForBlocked = false,
|
||||
};
|
||||
var refineries = self.World.Actors.Where( x => x.traits.Contains<AcceptsOre>()
|
||||
&& x.Owner == self.Owner ).ToList();
|
||||
var refineries = self.World.Queries.OwnedBy[self.Owner]
|
||||
.Where( x => x.traits.Contains<AcceptsOre>())
|
||||
.ToList();
|
||||
if( refinery != null )
|
||||
search.AddInitialCell( self.World, refinery.Location + refineryDeliverOffset );
|
||||
else
|
||||
|
||||
@@ -9,9 +9,8 @@ namespace OpenRa.Traits.Activities
|
||||
|
||||
static Actor ChooseHelipad(Actor self)
|
||||
{
|
||||
return self.World.Actors.FirstOrDefault(
|
||||
return self.World.Queries.OwnedBy[self.Owner].FirstOrDefault(
|
||||
a => a.Info.Name == "hpad" &&
|
||||
a.Owner == self.Owner &&
|
||||
!Reservable.IsReserved(a));
|
||||
}
|
||||
|
||||
|
||||
@@ -18,9 +18,8 @@ namespace OpenRa.Traits.Activities
|
||||
|
||||
Actor ChooseAirfield(Actor self)
|
||||
{
|
||||
var airfield = self.World.Actors
|
||||
var airfield = self.World.Queries.OwnedBy[self.Owner]
|
||||
.Where(a => a.Info.Name == "afld"
|
||||
&& a.Owner == self.Owner
|
||||
&& !Reservable.IsReserved(a))
|
||||
.FirstOrDefault();
|
||||
|
||||
|
||||
@@ -46,8 +46,10 @@ namespace OpenRa.Traits
|
||||
if (!movement.CanEnterCell(order.TargetLocation))
|
||||
return;
|
||||
|
||||
var chronosphere = self.World.Actors.Where(a => a.Owner == self.Owner
|
||||
&& a.traits.Contains<Chronosphere>()).FirstOrDefault();
|
||||
var chronosphere = self.World.Queries
|
||||
.OwnedBy[self.Owner]
|
||||
.WithTrait<Chronosphere>()
|
||||
.Select(x=>x.Actor).FirstOrDefault();
|
||||
|
||||
bool success = order.TargetActor.traits.Get<Chronoshiftable>().Activate(order.TargetActor,
|
||||
order.TargetLocation,
|
||||
@@ -60,8 +62,8 @@ namespace OpenRa.Traits
|
||||
Sound.Play("chrono2.aud");
|
||||
|
||||
// Trigger screen desaturate effect
|
||||
foreach (var a in self.World.Actors.Where(a => a.traits.Contains<ChronoshiftPaletteEffect>()))
|
||||
a.traits.Get<ChronoshiftPaletteEffect>().DoChronoshift();
|
||||
foreach (var a in self.World.Queries.WithTrait<ChronoshiftPaletteEffect>())
|
||||
a.Trait.DoChronoshift();
|
||||
|
||||
if (chronosphere != null)
|
||||
chronosphere.traits.Get<RenderBuilding>().PlayCustomAnim(chronosphere, "active");
|
||||
@@ -98,8 +100,9 @@ namespace OpenRa.Traits
|
||||
|
||||
public void Tick( World world )
|
||||
{
|
||||
var hasChronosphere = world.Actors
|
||||
.Any(a => a.Owner == world.LocalPlayer && a.traits.Contains<Chronosphere>());
|
||||
var hasChronosphere = world.Queries.OwnedBy[world.LocalPlayer]
|
||||
.WithTrait<Chronosphere>()
|
||||
.Any();
|
||||
|
||||
if (!hasChronosphere)
|
||||
Game.controller.CancelInputMode();
|
||||
@@ -135,8 +138,9 @@ namespace OpenRa.Traits
|
||||
|
||||
public void Tick(World world)
|
||||
{
|
||||
var hasChronosphere = world.Actors
|
||||
.Any(a => a.Owner == world.LocalPlayer && a.traits.Contains<Chronosphere>());
|
||||
var hasChronosphere = world.Queries.OwnedBy[world.LocalPlayer]
|
||||
.WithTrait<Chronosphere>()
|
||||
.Any();
|
||||
|
||||
if (!hasChronosphere)
|
||||
Game.controller.CancelInputMode();
|
||||
|
||||
@@ -26,8 +26,9 @@ namespace OpenRa.Traits
|
||||
{
|
||||
if (order.OrderString == "NuclearMissile")
|
||||
{
|
||||
var silo = self.World.Actors.Where(a => a.Owner == self.Owner
|
||||
&& a.traits.Contains<NukeSilo>()).FirstOrDefault();
|
||||
var silo = self.World.Queries.OwnedBy[self.Owner]
|
||||
.Where(a => a.traits.Contains<NukeSilo>())
|
||||
.FirstOrDefault();
|
||||
if (silo != null)
|
||||
silo.traits.Get<RenderBuilding>().PlayCustomAnim(silo, "active");
|
||||
|
||||
@@ -70,8 +71,9 @@ namespace OpenRa.Traits
|
||||
|
||||
public void Tick(World world)
|
||||
{
|
||||
var hasStructure = world.Actors
|
||||
.Any(a => a.Owner == world.LocalPlayer && a.traits.Contains<NukeSilo>());
|
||||
var hasStructure = world.Queries.OwnedBy[world.LocalPlayer]
|
||||
.WithTrait<NukeSilo>()
|
||||
.Any();
|
||||
|
||||
if (!hasStructure)
|
||||
Game.controller.CancelInputMode();
|
||||
|
||||
@@ -86,12 +86,12 @@ namespace OpenRa.Traits
|
||||
// Cancel existing primaries
|
||||
foreach (var p in self.Info.Traits.Get<ProductionInfo>().Produces)
|
||||
{
|
||||
foreach (var b in self.World.Actors.Where(x => x.traits.Contains<Production>()
|
||||
&& x.Owner == self.Owner
|
||||
&& x.traits.Get<Production>().IsPrimary == true
|
||||
&& (x.Info.Traits.Get<ProductionInfo>().Produces.Contains(p))))
|
||||
foreach (var b in self.World.Queries.OwnedBy[self.Owner]
|
||||
.WithTrait<Production>()
|
||||
.Where(x => x.Trait.IsPrimary
|
||||
&& (x.Actor.Info.Traits.Get<ProductionInfo>().Produces.Contains(p))))
|
||||
{
|
||||
b.traits.Get<Production>().SetPrimaryProducer(b, false);
|
||||
b.Trait.SetPrimaryProducer(b.Actor, false);
|
||||
}
|
||||
}
|
||||
isPrimary = true;
|
||||
|
||||
@@ -131,18 +131,17 @@ namespace OpenRa.Traits
|
||||
Actor producer = null;
|
||||
|
||||
// Prioritise primary structure in build order
|
||||
var primaryProducers = self.World.Actors
|
||||
.Where(x => x.traits.Contains<Production>()
|
||||
&& producerTypes.Contains(x.Info)
|
||||
&& x.Owner == self.Owner
|
||||
&& x.traits.Get<Production>().IsPrimary == true);
|
||||
var primaryProducers = self.World.Queries.OwnedBy[self.Owner]
|
||||
.WithTrait<Production>()
|
||||
.Where(x => producerTypes.Contains(x.Actor.Info)
|
||||
&& x.Trait.IsPrimary);
|
||||
|
||||
foreach (var p in primaryProducers)
|
||||
{
|
||||
// Ignore buildings that are disabled
|
||||
if (p.traits.Contains<Building>() && p.traits.Get<Building>().Disabled)
|
||||
if (p.Actor.traits.Contains<Building>() && p.Actor.traits.Get<Building>().Disabled)
|
||||
continue;
|
||||
producer = p;
|
||||
producer = p.Actor;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -152,8 +151,8 @@ namespace OpenRa.Traits
|
||||
// Pick the first available producer
|
||||
if (producer == null)
|
||||
{
|
||||
producer = self.World.Actors
|
||||
.Where( x => producerTypes.Contains( x.Info ) && x.Owner == self.Owner )
|
||||
producer = self.World.Queries.OwnedBy[self.Owner]
|
||||
.Where( x => producerTypes.Contains( x.Info ) )
|
||||
.FirstOrDefault();
|
||||
}
|
||||
|
||||
|
||||
@@ -16,9 +16,8 @@ namespace OpenRa.Traits
|
||||
var b = self.traits.Get<Building>();
|
||||
if (b != null && b.Disabled) return false;
|
||||
|
||||
var isJammed = self.World.Actors.Any(a => a.traits.Contains<JamsRadar>()
|
||||
&& self.Owner != a.Owner
|
||||
&& (self.Location - a.Location).Length < a.Info.Traits.Get<JamsRadarInfo>().Range);
|
||||
var isJammed = self.World.Queries.WithTrait<JamsRadar>().Any(a => self.Owner != a.Actor.Owner
|
||||
&& (self.Location - a.Actor.Location).Length < a.Actor.Info.Traits.Get<JamsRadarInfo>().Range);
|
||||
|
||||
return !isJammed;
|
||||
}
|
||||
|
||||
@@ -30,8 +30,9 @@ namespace OpenRa.Traits
|
||||
// Does this belong here? NO, but it's your mess.
|
||||
|
||||
// Get the crushable actors
|
||||
foreach (var a in self.World.Actors.Where(b => b.traits.Contains<ICrushable>()))
|
||||
foreach (var aa in self.World.Queries.WithTrait<ICrushable>())
|
||||
{
|
||||
var a = aa.Actor;
|
||||
// Are there any units in the same cell that can crush this?
|
||||
foreach( var ios in a.traits.WithInterface<IOccupySpace>() )
|
||||
foreach( var cell in ios.OccupiedCells() )
|
||||
|
||||
@@ -6,12 +6,13 @@ using OpenRa.Support;
|
||||
using OpenRa.FileFormats;
|
||||
using OpenRa.Graphics;
|
||||
using OpenRa.Traits;
|
||||
using OpenRa.Collections;
|
||||
|
||||
namespace OpenRa
|
||||
{
|
||||
public class World
|
||||
{
|
||||
List<Actor> actors = new List<Actor>();
|
||||
Set<Actor> actors = new Set<Actor>();
|
||||
List<IEffect> effects = new List<IEffect>();
|
||||
List<Action<World>> frameEndActions = new List<Action<World>>();
|
||||
|
||||
@@ -77,6 +78,9 @@ namespace OpenRa
|
||||
WorldRenderer = new WorldRenderer(this, Game.renderer);
|
||||
Minimap = new Minimap(this, Game.renderer);
|
||||
Timer.Time( "renderer, minimap: {0}" );
|
||||
|
||||
Queries = new AllQueries( this );
|
||||
Timer.Time( "queries: {0}" );
|
||||
Timer.Time( "----end World.ctor" );
|
||||
}
|
||||
|
||||
@@ -153,5 +157,65 @@ namespace OpenRa
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
public class AllQueries
|
||||
{
|
||||
readonly World world;
|
||||
|
||||
public readonly Dictionary<Player, OwnedByCachedView> OwnedBy = new Dictionary<Player, OwnedByCachedView>();
|
||||
readonly TypeDictionary hasTrait = new TypeDictionary();
|
||||
|
||||
public AllQueries( World world )
|
||||
{
|
||||
this.world = world;
|
||||
foreach( var p in world.players.Values )
|
||||
{
|
||||
var player = p;
|
||||
OwnedBy.Add( player, new OwnedByCachedView( world, world.actors, x => x.Owner == player ) );
|
||||
}
|
||||
}
|
||||
|
||||
public CachedView<Actor, TraitPair<T>> WithTrait<T>()
|
||||
{
|
||||
return WithTraitInner<T>( world, hasTrait );
|
||||
}
|
||||
|
||||
static CachedView<Actor, TraitPair<T>> WithTraitInner<T>( World world, TypeDictionary hasTrait )
|
||||
{
|
||||
var ret = hasTrait.GetOrDefault<CachedView<Actor, TraitPair<T>>>();
|
||||
if( ret != null )
|
||||
return ret;
|
||||
ret = new CachedView<Actor, TraitPair<T>>(
|
||||
world.actors,
|
||||
x => x.traits.Contains<T>(),
|
||||
x => new TraitPair<T> { Actor = x, Trait = x.traits.Get<T>() } );
|
||||
hasTrait.Add( ret );
|
||||
return ret; }
|
||||
|
||||
public struct TraitPair<T>
|
||||
{
|
||||
public Actor Actor;
|
||||
public T Trait;
|
||||
}
|
||||
|
||||
public class OwnedByCachedView : CachedView<Actor, Actor>
|
||||
{
|
||||
readonly World world;
|
||||
readonly TypeDictionary hasTrait = new TypeDictionary();
|
||||
|
||||
public OwnedByCachedView( World world, Set<Actor> set, Func<Actor, bool> include )
|
||||
: base( set, include, a => a )
|
||||
{
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
public CachedView<Actor, TraitPair<T>> WithTrait<T>()
|
||||
{
|
||||
return WithTraitInner<T>( world, hasTrait );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public readonly AllQueries Queries;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,8 +55,8 @@ namespace OpenRa.Mods.Aftermath
|
||||
Sound.Play("chrotnk1.aud");
|
||||
chargeTick = chargeLength;
|
||||
|
||||
foreach (var a in self.World.Actors.Where(a => a.traits.Contains<ChronoshiftPaletteEffect>()))
|
||||
a.traits.Get<ChronoshiftPaletteEffect>().DoChronoshift();
|
||||
foreach (var a in self.World.Queries.WithTrait<ChronoshiftPaletteEffect>())
|
||||
a.Trait.DoChronoshift();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,8 +18,8 @@ namespace OpenRa.Mods.RA
|
||||
|
||||
protected override void OnFinishCharging()
|
||||
{
|
||||
var launchSite = Owner.World.Actors
|
||||
.FirstOrDefault(a => a.Owner == Owner && a.traits.Contains<GpsLaunchSite>());
|
||||
var launchSite = Owner.World.Queries.OwnedBy[Owner]
|
||||
.FirstOrDefault(a => a.traits.Contains<GpsLaunchSite>());
|
||||
|
||||
if (launchSite == null)
|
||||
return;
|
||||
|
||||
@@ -29,8 +29,9 @@ namespace OpenRa.Mods.RA
|
||||
if (self.Owner == self.World.LocalPlayer)
|
||||
Game.controller.CancelInputMode();
|
||||
|
||||
var curtain = self.World.Actors.Where(a => a.Owner != null
|
||||
&& a.traits.Contains<IronCurtain>()).FirstOrDefault();
|
||||
var curtain = self.World.Queries.WithTrait<IronCurtain>()
|
||||
.Where(a => a.Actor.Owner != null)
|
||||
.FirstOrDefault().Actor;
|
||||
if (curtain != null)
|
||||
curtain.traits.Get<RenderBuilding>().PlayCustomAnim(curtain, "active");
|
||||
|
||||
@@ -73,8 +74,9 @@ namespace OpenRa.Mods.RA
|
||||
|
||||
public void Tick(World world)
|
||||
{
|
||||
var hasStructure = world.Actors
|
||||
.Any(a => a.Owner == world.LocalPlayer && a.traits.Contains<IronCurtain>());
|
||||
var hasStructure = world.Queries.OwnedBy[world.LocalPlayer]
|
||||
.WithTrait<IronCurtain>()
|
||||
.Any();
|
||||
|
||||
if (!hasStructure)
|
||||
Game.controller.CancelInputMode();
|
||||
|
||||
Reference in New Issue
Block a user