Fix CA1851

This commit is contained in:
RoosterDragon
2023-07-13 20:08:36 +01:00
committed by abcdefg30
parent 88f830a9e5
commit 3275875ae5
63 changed files with 349 additions and 267 deletions

View File

@@ -834,6 +834,12 @@ dotnet_diagnostic.CA1849.severity = warning
# Prefer static HashData method over ComputeHash. (Not available on mono)
dotnet_diagnostic.CA1850.severity = none
# Possible multiple enumerations of IEnumerable collection.
#dotnet_code_quality.CA1851.enumeration_methods =
#dotnet_code_quality.CA1851.linq_chain_methods =
#dotnet_code_quality.CA1851.assume_method_enumerates_parameters = false
dotnet_diagnostic.CA1851.severity = warning
# Seal internal types.
dotnet_diagnostic.CA1852.severity = warning

View File

@@ -185,7 +185,7 @@ namespace OpenRA
public bool HasTraitInfo<T>() where T : ITraitInfoInterface { return traits.Contains<T>(); }
public T TraitInfo<T>() where T : ITraitInfoInterface { return traits.Get<T>(); }
public T TraitInfoOrDefault<T>() where T : ITraitInfoInterface { return traits.GetOrDefault<T>(); }
public IEnumerable<T> TraitInfos<T>() where T : ITraitInfoInterface { return traits.WithInterface<T>(); }
public IReadOnlyCollection<T> TraitInfos<T>() where T : ITraitInfoInterface { return traits.WithInterface<T>(); }
public BitSet<TargetableType> GetAllTargetTypes()
{

View File

@@ -234,7 +234,7 @@ namespace OpenRA.Graphics
{
// PERF: We don't need to search for images if there are no definitions.
// PERF: It's more efficient to send an empty array rather than an array of 9 nulls.
if (!collection.Regions.Any())
if (collection.Regions.Count == 0)
return Array.Empty<Sprite>();
// Support manual definitions for unusual dialog layouts

View File

@@ -139,7 +139,7 @@ namespace OpenRA
return removed;
}
public IEnumerable<T> GetAll<T>() where T : ActorInit
public IReadOnlyCollection<T> GetAll<T>() where T : ActorInit
{
return initDict.Value.WithInterface<T>();
}

View File

@@ -12,7 +12,6 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace OpenRA
{
@@ -64,9 +63,9 @@ namespace OpenRA
}
/// <summary>Returns the minimal region that covers at least the specified cells.</summary>
public static CellRegion BoundingRegion(MapGridType shape, IEnumerable<CPos> cells)
public static CellRegion BoundingRegion(MapGridType shape, IReadOnlyCollection<CPos> cells)
{
if (cells == null || !cells.Any())
if (cells == null || cells.Count == 0)
throw new ArgumentException("cells must not be null or empty.", nameof(cells));
var minU = int.MaxValue;

View File

@@ -201,8 +201,12 @@ namespace OpenRA.Network
public TypeInfo(Type type)
{
const BindingFlags Flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
var fields = type.GetFields(Flags).Where(fi => !fi.IsLiteral && !fi.IsStatic && fi.HasAttribute<SyncAttribute>());
var properties = type.GetProperties(Flags).Where(pi => pi.HasAttribute<SyncAttribute>());
var fields = type.GetFields(Flags)
.Where(fi => !fi.IsLiteral && !fi.IsStatic && fi.HasAttribute<SyncAttribute>())
.ToList();
var properties = type.GetProperties(Flags)
.Where(pi => pi.HasAttribute<SyncAttribute>())
.ToList();
foreach (var prop in properties)
if (!prop.CanRead || prop.GetIndexParameters().Length > 0)

View File

@@ -134,8 +134,8 @@ namespace OpenRA
public ConstructorInfo GetCtor(Type type)
{
var flags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance;
var ctors = type.GetConstructors(flags).Where(x => x.HasAttribute<UseCtorAttribute>());
if (ctors.Count() > 1)
var ctors = type.GetConstructors(flags).Where(x => x.HasAttribute<UseCtorAttribute>()).ToList();
if (ctors.Count > 1)
throw new InvalidOperationException("ObjectCreator: UseCtor on multiple constructors; invalid.");
return ctors.FirstOrDefault();
}

View File

@@ -133,7 +133,7 @@ namespace OpenRA
static FactionInfo ResolveDisplayFaction(World world, string factionName)
{
var factions = world.Map.Rules.Actors[SystemActors.World].TraitInfos<FactionInfo>().ToArray();
var factions = world.Map.Rules.Actors[SystemActors.World].TraitInfos<FactionInfo>();
return factions.FirstOrDefault(f => f.InternalName == factionName) ?? factions.First();
}

View File

@@ -12,14 +12,20 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace OpenRA.Primitives
{
public class TypeDictionary : IEnumerable<object>
{
static readonly Func<Type, List<object>> CreateList = type => new List<object>();
readonly Dictionary<Type, List<object>> data = new();
static readonly Func<Type, ITypeContainer> CreateTypeContainer = t =>
(ITypeContainer)typeof(TypeContainer<>).MakeGenericType(t).GetConstructor(Type.EmptyTypes).Invoke(null);
readonly Dictionary<Type, ITypeContainer> data = new();
ITypeContainer InnerGet(Type t)
{
return data.GetOrAdd(t, CreateTypeContainer);
}
public void Add(object val)
{
@@ -33,7 +39,7 @@ namespace OpenRA.Primitives
void InnerAdd(Type t, object val)
{
data.GetOrAdd(t, CreateList).Add(val);
InnerGet(t).Add(val);
}
public bool Contains<T>()
@@ -48,35 +54,33 @@ namespace OpenRA.Primitives
public T Get<T>()
{
return (T)Get(typeof(T), true);
return Get<T>(true);
}
public T GetOrDefault<T>()
{
var result = Get(typeof(T), false);
if (result == null)
return default;
return (T)result;
return Get<T>(false);
}
object Get(Type t, bool throwsIfMissing)
T Get<T>(bool throwsIfMissing)
{
if (!data.TryGetValue(t, out var ret))
if (!data.TryGetValue(typeof(T), out var container))
{
if (throwsIfMissing)
throw new InvalidOperationException($"TypeDictionary does not contain instance of type `{t}`");
return null;
throw new InvalidOperationException($"TypeDictionary does not contain instance of type `{typeof(T)}`");
return default;
}
if (ret.Count > 1)
throw new InvalidOperationException($"TypeDictionary contains multiple instances of type `{t}`");
return ret[0];
var list = ((TypeContainer<T>)container).Objects;
if (list.Count > 1)
throw new InvalidOperationException($"TypeDictionary contains multiple instances of type `{typeof(T)}`");
return list[0];
}
public IEnumerable<T> WithInterface<T>()
public IReadOnlyCollection<T> WithInterface<T>()
{
if (data.TryGetValue(typeof(T), out var objs))
return objs.Cast<T>();
if (data.TryGetValue(typeof(T), out var container))
return ((TypeContainer<T>)container).Objects;
return Array.Empty<T>();
}
@@ -92,18 +96,19 @@ namespace OpenRA.Primitives
void InnerRemove(Type t, object val)
{
if (!data.TryGetValue(t, out var objs))
if (!data.TryGetValue(t, out var container))
return;
objs.Remove(val);
if (objs.Count == 0)
container.Remove(val);
if (container.Count == 0)
data.Remove(t);
}
public void TrimExcess()
{
data.TrimExcess();
foreach (var objs in data.Values)
objs.TrimExcess();
foreach (var t in data.Keys)
InnerGet(t).TrimExcess();
}
public IEnumerator<object> GetEnumerator()
@@ -115,6 +120,36 @@ namespace OpenRA.Primitives
{
return GetEnumerator();
}
interface ITypeContainer
{
int Count { get; }
void Add(object value);
void Remove(object value);
void TrimExcess();
}
sealed class TypeContainer<T> : ITypeContainer
{
public List<T> Objects { get; } = new List<T>();
public int Count => Objects.Count;
public void Add(object value)
{
Objects.Add((T)value);
}
public void Remove(object value)
{
Objects.Remove((T)value);
}
public void TrimExcess()
{
Objects.TrimExcess();
}
}
}
public static class TypeExts

View File

@@ -11,7 +11,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Eluant;
using Eluant.ObjectBinding;
using OpenRA.Scripting;
@@ -139,20 +138,21 @@ namespace OpenRA
{
public static WPos Average(this IEnumerable<WPos> source)
{
var length = source.Count();
if (length == 0)
return WPos.Zero;
var length = 0;
var x = 0L;
var y = 0L;
var z = 0L;
foreach (var pos in source)
{
length++;
x += pos.X;
y += pos.Y;
z += pos.Z;
}
if (length == 0)
return WPos.Zero;
x /= length;
y /= length;
z /= length;

View File

@@ -10,7 +10,6 @@
#endregion
using System;
using System.Linq;
using OpenRA.Activities;
using OpenRA.Mods.Cnc.Traits;
using OpenRA.Mods.Common.Traits;
@@ -120,7 +119,7 @@ namespace OpenRA.Mods.Cnc.Activities
if (teleporter == null)
return null;
var restrictTo = maximumDistance == null ? null : self.World.Map.FindTilesInCircle(self.Location, maximumDistance.Value);
var restrictTo = maximumDistance == null ? null : self.World.Map.FindTilesInCircle(self.Location, maximumDistance.Value).ToHashSet();
if (maximumDistance != null)
destination = restrictTo.MinBy(x => (x - destination).LengthSquared);

View File

@@ -80,7 +80,7 @@ namespace OpenRA.Mods.Cnc.Traits
{
var wasGranted = Granted;
var wasGrantedAllies = GrantedAllies;
var allyWatchers = owner.World.ActorsWithTrait<GpsWatcher>().Where(kv => kv.Actor.Owner.IsAlliedWith(owner));
var allyWatchers = owner.World.ActorsWithTrait<GpsWatcher>().Where(kv => kv.Actor.Owner.IsAlliedWith(owner)).ToList();
Granted = actors.Count > 0 && Launched;
GrantedAllies = allyWatchers.Any(w => w.Trait.Granted);

View File

@@ -358,14 +358,11 @@ namespace OpenRA.Mods.Cnc.Traits
bool IsValidTarget(CPos xy)
{
// Don't teleport if there are no units in range (either all moved out of range, or none yet moved into range)
var unitsInRange = power.UnitsInRange(sourceLocation);
if (!unitsInRange.Any())
return false;
var canTeleport = false;
foreach (var unit in unitsInRange)
var anyUnitsInRange = false;
foreach (var unit in power.UnitsInRange(sourceLocation))
{
anyUnitsInRange = true;
var targetCell = unit.Location + (xy - sourceLocation);
if (manager.Self.Owner.Shroud.IsExplored(targetCell) && unit.Trait<Chronoshiftable>().CanChronoshiftTo(unit, targetCell))
{
@@ -374,6 +371,10 @@ namespace OpenRA.Mods.Cnc.Traits
}
}
// Don't teleport if there are no units in range (either all moved out of range, or none yet moved into range)
if (!anyUnitsInRange)
return false;
if (!canTeleport)
{
// Check the terrain types. This will allow chronoshifts to occur on empty terrain to terrain of

View File

@@ -196,8 +196,8 @@ namespace OpenRA.Mods.Common.Activities
// Update ranges. Exclude paused armaments except when ALL weapons are paused
// (e.g. out of ammo), in which case use the paused, valid weapon with highest range.
var activeArmaments = armaments.Where(x => !x.IsTraitPaused);
if (activeArmaments.Any())
var activeArmaments = armaments.Where(x => !x.IsTraitPaused).ToList();
if (activeArmaments.Count != 0)
{
minRange = activeArmaments.Max(a => a.Weapon.MinRange);
maxRange = activeArmaments.Min(a => a.MaxRange());

View File

@@ -10,7 +10,6 @@
#endregion
using System;
using System.Linq;
using OpenRA.Mods.Common.Traits;
namespace OpenRA.Mods.Common.Lint
@@ -21,8 +20,8 @@ namespace OpenRA.Mods.Common.Lint
{
foreach (var actorInfo in rules.Actors)
{
var selectable = actorInfo.Value.TraitInfos<SelectableInfo>().Count();
var interactable = actorInfo.Value.TraitInfos<InteractableInfo>().Count();
var selectable = actorInfo.Value.TraitInfos<SelectableInfo>().Count;
var interactable = actorInfo.Value.TraitInfos<InteractableInfo>().Count;
if (selectable > 0 && selectable != interactable)
emitWarning($"Actor `{actorInfo.Value.Name}` defines both Interactable and Selectable traits. This may cause unexpected results.");
}

View File

@@ -37,7 +37,7 @@ namespace OpenRA.Mods.Common.Lint
try
{
var visibilityTypes = actorInfo.Value.TraitInfos<IDefaultVisibilityInfo>();
var count = visibilityTypes.Count();
var count = visibilityTypes.Count;
if (count == 0)
emitError($"Actor type `{actorInfo.Key}` does not define a default visibility type.");

View File

@@ -10,7 +10,6 @@
#endregion
using System;
using System.Linq;
using OpenRA.Mods.Common.Traits;
using OpenRA.Server;
using OpenRA.Traits;
@@ -41,7 +40,7 @@ namespace OpenRA.Mods.Common.Lint
continue;
var hitShapes = actorInfo.Value.TraitInfos<HitShapeInfo>();
if (!hitShapes.Any())
if (hitShapes.Count == 0)
emitError($"Actor type `{actorInfo.Key}` has a Health trait but no HitShape trait.");
}
catch (InvalidOperationException e)

View File

@@ -10,6 +10,7 @@
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Mods.Common.Traits;
using OpenRA.Server;
@@ -32,12 +33,15 @@ namespace OpenRA.Mods.Common.Lint
static void Run(Action<string> emitError, Ruleset rules)
{
var worldActor = rules.Actors[SystemActors.World];
var locomotorInfos = worldActor.TraitInfos<LocomotorInfo>().ToArray();
foreach (var li in locomotorInfos)
foreach (var otherLocomotor in locomotorInfos)
if (li != otherLocomotor && li.Name == otherLocomotor.Name)
emitError($"More than one Locomotor exists with the name `{li.Name}`.");
var locomotorNames = worldActor.TraitInfos<LocomotorInfo>().Select(li => li.Name).ToList();
var duplicateNames = locomotorNames
.GroupBy(name => name)
.Where(g => g.Count() > 1)
.Select(g => g.Key);
foreach (var duplicateName in duplicateNames)
emitError($"More than one Locomotor exists with the name `{duplicateName}`.");
var locomotorNamesSet = locomotorNames.ToHashSet();
foreach (var actorInfo in rules.Actors)
{
foreach (var traitInfo in actorInfo.Value.TraitInfos<TraitInfo>())
@@ -51,16 +55,16 @@ namespace OpenRA.Mods.Common.Lint
if (string.IsNullOrEmpty(locomotor))
continue;
CheckLocomotors(actorInfo.Value, emitError, locomotorInfos, locomotor);
CheckLocomotors(actorInfo.Value, emitError, locomotorNamesSet, locomotor);
}
}
}
}
}
static void CheckLocomotors(ActorInfo actorInfo, Action<string> emitError, LocomotorInfo[] locomotorInfos, string locomotor)
static void CheckLocomotors(ActorInfo actorInfo, Action<string> emitError, HashSet<string> locomotorNames, string locomotor)
{
if (!locomotorInfos.Any(l => l.Name == locomotor))
if (!locomotorNames.Contains(locomotor))
emitError($"Actor `{actorInfo.Name}` defines Locomotor `{locomotor}` not found on World actor.");
}
}

View File

@@ -32,10 +32,12 @@ namespace OpenRA.Mods.Common.Lint
{
foreach (var actorInfo in rules.Actors)
{
var wsbs = actorInfo.Value.TraitInfos<WithSpriteBodyInfo>();
foreach (var wsb in wsbs)
if (wsbs.Any(w => w != wsb && w.Name == wsb.Name))
emitError($"Actor type `{actorInfo.Key}` has more than one *SpriteBody with Name: {wsb.Name}.");
var duplicateNames = actorInfo.Value.TraitInfos<WithSpriteBodyInfo>()
.GroupBy(wsb => wsb.Name)
.Where(g => g.Count() > 1)
.Select(g => g.Key);
foreach (var duplicateName in duplicateNames)
emitError($"Actor type `{actorInfo.Key}` has more than one *SpriteBody with Name: {duplicateName}.");
}
}
}

View File

@@ -50,13 +50,13 @@ namespace OpenRA.Mods.Common.Orders
.Where(o => o != null)
.ToList();
var actorsInvolved = orders.Select(o => o.Actor).Distinct();
if (!actorsInvolved.Any())
var actorsInvolved = orders.Select(o => o.Actor).Distinct().ToArray();
if (actorsInvolved.Length == 0)
yield break;
// HACK: This is required by the hacky player actions-per-minute calculation
// TODO: Reimplement APM properly and then remove this
yield return new Order("CreateGroup", actorsInvolved.First().Owner.PlayerActor, false, actorsInvolved.ToArray());
yield return new Order("CreateGroup", actorsInvolved.First().Owner.PlayerActor, false, actorsInvolved);
foreach (var o in orders)
yield return CheckSameOrder(o.Order, o.Trait.IssueOrder(o.Actor, o.Order, o.Target, mi.Modifiers.HasModifier(Modifiers.Shift)));
@@ -165,7 +165,8 @@ namespace OpenRA.Mods.Common.Orders
var orders = self.TraitsImplementing<IIssueOrder>()
.SelectMany(trait => trait.Orders.Select(x => new { Trait = trait, Order = x }))
.Select(x => x)
.OrderByDescending(x => x.Order.OrderPriority);
.OrderByDescending(x => x.Order.OrderPriority)
.ToList();
for (var i = 0; i < 2; i++)
{

View File

@@ -245,7 +245,7 @@ namespace OpenRA.Mods.Common.Scripting
foreach (var actorType in actorTypes.Distinct())
typeToQueueMap.Add(actorType, GetBuildableInfo(actorType).Queue.First());
var queueTypes = typeToQueueMap.Values.Distinct();
var queueTypes = typeToQueueMap.Values.Distinct().ToList();
if (queueTypes.Any(t => !queues.ContainsKey(t) || productionHandlers.ContainsKey(t)))
return false;

View File

@@ -748,10 +748,11 @@ namespace OpenRA.Mods.Common.Server
teamCount = teamCount.Clamp(0, maxTeams);
var clients = server.LobbyInfo.Slots
.Select(slot => server.LobbyInfo.ClientInSlot(slot.Key))
.Where(c => c != null && !server.LobbyInfo.Slots[c.Slot].LockTeam);
.Where(c => c != null && !server.LobbyInfo.Slots[c.Slot].LockTeam)
.ToList();
var assigned = 0;
var clientCount = clients.Count();
var clientCount = clients.Count;
foreach (var player in clients)
{
// Free for all

View File

@@ -41,8 +41,8 @@ namespace OpenRA.Mods.Common.Traits
else
{
var owner = map.PlayerDefinitions.Single(p => s.Get<OwnerInit>().InternalName == p.Value.Nodes.Last(k => k.Key == "Name").Value.Value);
var colorValue = owner.Value.Nodes.Where(n => n.Key == "Color");
var ownerColor = colorValue.Any() ? colorValue.First().Value.Value : "FFFFFF";
var colorValue = owner.Value.Nodes.FirstOrDefault(n => n.Key == "Color");
var ownerColor = colorValue?.Value.Value ?? "FFFFFF";
Color.TryParse(ownerColor, out color);
}

View File

@@ -445,15 +445,15 @@ namespace OpenRA.Mods.Common.Traits
modifiers |= TargetModifiers.ForceAttack;
var forceAttack = modifiers.HasModifier(TargetModifiers.ForceAttack);
var armaments = ab.ChooseArmamentsForTarget(target, forceAttack);
if (!armaments.Any())
return false;
// Use valid armament with highest range out of those that have ammo
// If all are out of ammo, just use valid armament with highest range
armaments = armaments.OrderByDescending(x => x.MaxRange());
var a = armaments.FirstOrDefault(x => !x.IsTraitPaused);
a ??= armaments.First();
var a = ab.ChooseArmamentsForTarget(target, forceAttack)
.OrderBy(x => x.IsTraitPaused)
.ThenByDescending(x => x.MaxRange())
.FirstOrDefault();
if (a == null)
return false;
var outOfRange = !target.IsInRange(self.CenterPosition, a.MaxRange()) ||
(!forceAttack && target.Type == TargetType.FrozenActor && !ab.Info.TargetFrozenActors);
@@ -482,15 +482,15 @@ namespace OpenRA.Mods.Common.Traits
return false;
var target = Target.FromCell(self.World, location);
var armaments = ab.ChooseArmamentsForTarget(target, true);
if (!armaments.Any())
return false;
// Use valid armament with highest range out of those that have ammo
// If all are out of ammo, just use valid armament with highest range
armaments = armaments.OrderByDescending(x => x.MaxRange());
var a = armaments.FirstOrDefault(x => !x.IsTraitPaused);
a ??= armaments.First();
var a = ab.ChooseArmamentsForTarget(target, true)
.OrderBy(x => x.IsTraitPaused)
.ThenByDescending(x => x.MaxRange())
.FirstOrDefault();
if (a == null)
return false;
cursor = !target.IsInRange(self.CenterPosition, a.MaxRange())
? ab.Info.OutsideRangeCursor ?? a.Info.OutsideRangeCursor

View File

@@ -163,7 +163,7 @@ namespace OpenRA.Mods.Common.Traits.BotModules.Squads
fuzzyEngine.Rules.Add(fuzzyEngine.ParseRule(rule));
}
public bool CanAttack(IEnumerable<Actor> ownUnits, IEnumerable<Actor> enemyUnits)
public bool CanAttack(IReadOnlyCollection<Actor> ownUnits, IReadOnlyCollection<Actor> enemyUnits)
{
double attackChance;
var inputValues = new Dictionary<FuzzyVariable, double>();
@@ -201,7 +201,7 @@ namespace OpenRA.Mods.Common.Traits.BotModules.Squads
return (int)((long)sumOfHp * normalizeByValue / sumOfMaxHp);
}
static float RelativePower(IEnumerable<Actor> own, IEnumerable<Actor> enemy)
static float RelativePower(IReadOnlyCollection<Actor> own, IReadOnlyCollection<Actor> enemy)
{
return RelativeValue(own, enemy, 100, SumOfValues<AttackBaseInfo>, a =>
{
@@ -225,18 +225,18 @@ namespace OpenRA.Mods.Common.Traits.BotModules.Squads
});
}
static float RelativeSpeed(IEnumerable<Actor> own, IEnumerable<Actor> enemy)
static float RelativeSpeed(IReadOnlyCollection<Actor> own, IReadOnlyCollection<Actor> enemy)
{
return RelativeValue(own, enemy, 100, Average<MobileInfo>, (Actor a) => a.Info.TraitInfo<MobileInfo>().Speed);
}
static float RelativeValue(IEnumerable<Actor> own, IEnumerable<Actor> enemy, float normalizeByValue,
Func<IEnumerable<Actor>, Func<Actor, int>, float> relativeFunc, Func<Actor, int> getValue)
static float RelativeValue(IReadOnlyCollection<Actor> own, IReadOnlyCollection<Actor> enemy, float normalizeByValue,
Func<IReadOnlyCollection<Actor>, Func<Actor, int>, float> relativeFunc, Func<Actor, int> getValue)
{
if (!enemy.Any())
if (enemy.Count == 0)
return 999.0f;
if (!own.Any())
if (own.Count == 0)
return 0.0f;
var relative = relativeFunc(own, getValue) / relativeFunc(enemy, getValue) * normalizeByValue;

View File

@@ -22,9 +22,9 @@ namespace OpenRA.Mods.Common.Traits.BotModules.Squads
protected const int MissileUnitMultiplier = 3;
protected static int CountAntiAirUnits(IEnumerable<Actor> units)
protected static int CountAntiAirUnits(IReadOnlyCollection<Actor> units)
{
if (!units.Any())
if (units.Count == 0)
return 0;
var missileUnitsCount = 0;

View File

@@ -80,7 +80,7 @@ namespace OpenRA.Mods.Common.Traits.BotModules.Squads
return false;
}
protected virtual bool ShouldFlee(Squad squad, Func<IEnumerable<Actor>, bool> flee)
protected virtual bool ShouldFlee(Squad squad, Func<IReadOnlyCollection<Actor>, bool> flee)
{
if (!squad.IsValid)
return false;
@@ -95,8 +95,10 @@ namespace OpenRA.Mods.Common.Traits.BotModules.Squads
if (u.Owner == squad.Bot.Player && u.Info.HasTraitInfo<BuildingInfo>())
return false;
var enemyAroundUnit = units.Where(unit => squad.SquadManager.IsPreferredEnemyUnit(unit) && unit.Info.HasTraitInfo<AttackBaseInfo>());
if (!enemyAroundUnit.Any())
var enemyAroundUnit = units
.Where(unit => squad.SquadManager.IsPreferredEnemyUnit(unit) && unit.Info.HasTraitInfo<AttackBaseInfo>())
.ToList();
if (enemyAroundUnit.Count == 0)
return false;
return flee(enemyAroundUnit);

View File

@@ -172,17 +172,18 @@ namespace OpenRA.Mods.Common.Traits
ActorInfo ChooseUnitToBuild(ProductionQueue queue)
{
var buildableThings = queue.BuildableItems();
if (!buildableThings.Any())
var buildableThings = queue.BuildableItems().Select(b => b.Name).ToHashSet();
if (buildableThings.Count == 0)
return null;
var myUnits = player.World
.ActorsHavingTrait<IPositionable>()
.Where(a => a.Owner == player)
.Select(a => a.Info.Name).ToList();
.Select(a => a.Info.Name)
.ToList();
foreach (var unit in Info.UnitsToBuild.Shuffle(world.LocalRandom))
if (buildableThings.Any(b => b.Name == unit.Key))
if (buildableThings.Contains(unit.Key))
if (myUnits.Count(a => a == unit.Key) * 100 < unit.Value * myUnits.Count)
if (HasAdequateAirUnitReloadBuildings(world.Map.Rules.Actors[unit.Key]))
return world.Map.Rules.Actors[unit.Key];

View File

@@ -80,9 +80,6 @@ namespace OpenRA.Mods.Common.Traits
return null;
var allOfType = Exits(actor, productionType);
if (!allOfType.Any())
return null;
foreach (var g in allOfType.GroupBy(e => e.Info.Priority))
{
var shuffled = g.Shuffle(world.SharedRandom);

View File

@@ -54,13 +54,15 @@ namespace OpenRA.Mods.Common.Traits
public override void RulesetLoaded(Ruleset rules, ActorInfo ai)
{
var locomotorInfos = rules.Actors[SystemActors.World].TraitInfos<LocomotorInfo>();
LocomotorInfo = locomotorInfos.FirstOrDefault(li => li.Name == Locomotor);
if (LocomotorInfo == null)
var locomotorInfos = rules.Actors[SystemActors.World].TraitInfos<LocomotorInfo>()
.Where(li => li.Name == Locomotor).ToList();
if (locomotorInfos.Count == 0)
throw new YamlException($"A locomotor named '{Locomotor}' doesn't exist.");
else if (locomotorInfos.Count(li => li.Name == Locomotor) > 1)
else if (locomotorInfos.Count > 1)
throw new YamlException($"There is more than one locomotor named '{Locomotor}'.");
LocomotorInfo = locomotorInfos[0];
base.RulesetLoaded(rules, ai);
}
}

View File

@@ -113,23 +113,32 @@ namespace OpenRA.Mods.Common.Traits
void INotifyParachute.OnLanded(Actor self)
{
// Check whether the crate landed on anything
var landedOn = self.World.ActorMap.GetActorsAt(self.Location)
.Where(a => a != self);
if (!landedOn.Any())
return;
var collector = landedOn.FirstOrDefault(a =>
var anyOtherActors = false;
Actor collector = null;
foreach (var otherActor in self.World.ActorMap.GetActorsAt(self.Location))
{
if (self == otherActor)
continue;
anyOtherActors = true;
// Mobile is (currently) the only trait that supports crushing
var mi = a.Info.TraitInfoOrDefault<MobileInfo>();
var mi = otherActor.Info.TraitInfoOrDefault<MobileInfo>();
if (mi == null)
return false;
continue;
// Make sure that the actor can collect this crate type
// Crate can only be crushed if it is not in the air.
return self.IsAtGroundLevel() && mi.LocomotorInfo.Crushes.Contains(info.CrushClass);
});
if (self.IsAtGroundLevel() && mi.LocomotorInfo.Crushes.Contains(info.CrushClass))
{
collector = otherActor;
break;
}
}
// The crate can land unhindered.
if (!anyOtherActors)
return;
// Destroy the crate if none of the units in the cell are valid collectors
if (collector != null)
@@ -148,10 +157,11 @@ namespace OpenRA.Mods.Common.Traits
self.Dispose();
collected = true;
if (crateActions.Any())
var shares = crateActions
.Select(a => (Action: a, Shares: a.GetSelectionSharesOuter(crusher)))
.ToList();
if (shares.Count != 0)
{
var shares = crateActions.Select(a => (Action: a, Shares: a.GetSelectionSharesOuter(crusher)));
var totalShares = shares.Sum(a => a.Shares);
var n = self.World.SharedRandom.Next(totalShares);

View File

@@ -76,7 +76,8 @@ namespace OpenRA.Mods.Common.Traits
void GrantCondition(Actor actor)
{
var externals = actor.TraitsImplementing<ExternalCondition>()
.Where(t => t.Info.Condition == info.Condition);
.Where(t => t.Info.Condition == info.Condition)
.ToList();
ExternalCondition external = null;
for (var n = 0; n < info.Levels; n++)

View File

@@ -104,13 +104,15 @@ namespace OpenRA.Mods.Common.Traits
public override void RulesetLoaded(Ruleset rules, ActorInfo ai)
{
var locomotorInfos = rules.Actors[SystemActors.World].TraitInfos<LocomotorInfo>();
LocomotorInfo = locomotorInfos.FirstOrDefault(li => li.Name == Locomotor);
if (LocomotorInfo == null)
var locomotorInfos = rules.Actors[SystemActors.World].TraitInfos<LocomotorInfo>()
.Where(li => li.Name == Locomotor).ToList();
if (locomotorInfos.Count == 0)
throw new YamlException($"A locomotor named '{Locomotor}' doesn't exist.");
else if (locomotorInfos.Count(li => li.Name == Locomotor) > 1)
else if (locomotorInfos.Count > 1)
throw new YamlException($"There is more than one locomotor named '{Locomotor}'.");
LocomotorInfo = locomotorInfos[0];
// We need to reset the reference to the locomotor between each worlds, otherwise we are reference the previous state.
locomotor = null;

View File

@@ -133,15 +133,15 @@ namespace OpenRA.Mods.Common.Traits
public override TraitPair<Production> MostLikelyProducer()
{
var productionActors = self.World.ActorsWithTrait<Production>()
var productionActor = self.World.ActorsWithTrait<Production>()
.Where(x => x.Actor.Owner == self.Owner
&& !x.Trait.IsTraitDisabled && x.Trait.Info.Produces.Contains(Info.Type))
.OrderByDescending(x => x.Actor.IsPrimaryBuilding())
.OrderBy(x => x.Trait.IsTraitPaused)
.ThenByDescending(x => x.Actor.IsPrimaryBuilding())
.ThenByDescending(x => x.Actor.ActorID)
.ToList();
.FirstOrDefault();
var unpaused = productionActors.FirstOrDefault(a => !a.Trait.IsTraitPaused);
return unpaused.Trait != null ? unpaused : productionActors.FirstOrDefault();
return productionActor;
}
protected override bool BuildUnit(ActorInfo unit)
@@ -159,14 +159,10 @@ namespace OpenRA.Mods.Common.Traits
.OrderByDescending(x => x.Actor.IsPrimaryBuilding())
.ThenByDescending(x => x.Actor.ActorID);
if (!producers.Any())
{
CancelProduction(unit.Name, 1);
return false;
}
var anyProducers = false;
foreach (var p in producers)
{
anyProducers = true;
if (p.Trait.IsTraitPaused)
continue;
@@ -184,6 +180,12 @@ namespace OpenRA.Mods.Common.Traits
}
}
if (!anyProducers)
{
CancelProduction(unit.Name, 1);
return false;
}
return false;
}

View File

@@ -83,15 +83,15 @@ namespace OpenRA.Mods.Common.Traits
public override TraitPair<Production> MostLikelyProducer()
{
var productionActors = self.World.ActorsWithTrait<Production>()
var productionActor = self.World.ActorsWithTrait<Production>()
.Where(x => x.Actor.Owner == self.Owner
&& !x.Trait.IsTraitDisabled && x.Trait.Info.Produces.Contains(Info.Type))
.OrderByDescending(x => x.Actor.IsPrimaryBuilding())
.OrderBy(x => x.Trait.IsTraitPaused)
.ThenByDescending(x => x.Actor.IsPrimaryBuilding())
.ThenByDescending(x => x.Actor.ActorID)
.ToList();
.FirstOrDefault();
var unpaused = productionActors.FirstOrDefault(a => !a.Trait.IsTraitPaused);
return unpaused.Trait != null ? unpaused : productionActors.FirstOrDefault();
return productionActor;
}
protected override bool BuildUnit(ActorInfo unit)
@@ -109,14 +109,10 @@ namespace OpenRA.Mods.Common.Traits
.OrderByDescending(x => x.Actor.IsPrimaryBuilding())
.ThenByDescending(x => x.Actor.ActorID);
if (!producers.Any())
{
CancelProduction(unit.Name, 1);
return false;
}
var anyProducers = false;
foreach (var p in producers)
{
anyProducers = true;
if (p.Trait.IsTraitPaused)
continue;
@@ -134,6 +130,12 @@ namespace OpenRA.Mods.Common.Traits
}
}
if (!anyProducers)
{
CancelProduction(unit.Name, 1);
return false;
}
return false;
}

View File

@@ -81,13 +81,14 @@ namespace OpenRA.Mods.Common.Traits
return;
var myTeam = self.World.LobbyInfo.ClientWithIndex(self.Owner.ClientIndex).Team;
var teams = self.World.Players.Where(p => !p.NonCombatant && p.Playable)
var victoriousTeam = self.World.Players.Where(p => !p.NonCombatant && p.Playable)
.Select(p => (Player: p, PlayerStatistics: p.PlayerActor.TraitOrDefault<PlayerStatistics>()))
.OrderByDescending(p => p.PlayerStatistics?.Experience ?? 0)
.GroupBy(p => (self.World.LobbyInfo.ClientWithIndex(p.Player.ClientIndex) ?? new Session.Client()).Team)
.OrderByDescending(g => g.Sum(gg => gg.PlayerStatistics?.Experience ?? 0));
.OrderByDescending(g => g.Sum(gg => gg.PlayerStatistics?.Experience ?? 0))
.First();
if (teams.First().Key == myTeam && (myTeam != 0 || teams.First().First().Player == self.Owner))
if (victoriousTeam.Key == myTeam && (myTeam != 0 || victoriousTeam.First().Player == self.Owner))
{
mo.MarkCompleted(self.Owner, objectiveID);
return;

View File

@@ -594,9 +594,11 @@ namespace OpenRA.Mods.Common.Traits
// Returns the actor/trait that is most likely (but not necessarily guaranteed) to produce something in this queue
public virtual TraitPair<Production> MostLikelyProducer()
{
var traits = productionTraits.Where(p => !p.IsTraitDisabled && p.Info.Produces.Contains(Info.Type));
var unpaused = traits.FirstOrDefault(a => !a.IsTraitPaused);
return new TraitPair<Production>(Actor, unpaused ?? traits.FirstOrDefault());
var trait = productionTraits
.Where(p => !p.IsTraitDisabled && p.Info.Produces.Contains(Info.Type))
.OrderBy(p => p.IsTraitPaused)
.FirstOrDefault();
return new TraitPair<Production>(Actor, trait);
}
// Builds a unit from the actor that holds this queue (1 queue per building)

View File

@@ -89,13 +89,21 @@ namespace OpenRA.Mods.Common.Traits
if (!self.Owner.NonCombatant && self.Owner.HasNoRequiredUnits(shortGame))
mo.MarkFailed(self.Owner, objectiveID);
var others = self.World.Players.Where(p => !p.NonCombatant
&& !p.IsAlliedWith(self.Owner));
var allOthersLost = true;
var anyOtherWon = false;
foreach (var other in self.World.Players)
{
if (other.NonCombatant || other.IsAlliedWith(self.Owner))
continue;
if (others.All(p => p.WinState == WinState.Lost))
allOthersLost = allOthersLost && other.WinState == WinState.Lost;
anyOtherWon = anyOtherWon || other.WinState == WinState.Won;
}
if (allOthersLost)
mo.MarkCompleted(player, objectiveID);
if (others.Any(p => p.WinState == WinState.Won))
if (anyOtherWon)
mo.MarkFailed(player, objectiveID);
// See if any of the conditions are met to increase the count
@@ -119,13 +127,14 @@ namespace OpenRA.Mods.Common.Traits
return;
var myTeam = self.World.LobbyInfo.ClientWithIndex(self.Owner.ClientIndex).Team;
var teams = self.World.Players.Where(p => !p.NonCombatant && p.Playable)
var victoriousTeam = self.World.Players.Where(p => !p.NonCombatant && p.Playable)
.Select(p => (Player: p, PlayerStatistics: p.PlayerActor.TraitOrDefault<PlayerStatistics>()))
.OrderByDescending(p => p.PlayerStatistics?.Experience ?? 0)
.GroupBy(p => (self.World.LobbyInfo.ClientWithIndex(p.Player.ClientIndex) ?? new Session.Client()).Team)
.OrderByDescending(g => g.Sum(gg => gg.PlayerStatistics?.Experience ?? 0));
.OrderByDescending(g => g.Sum(gg => gg.PlayerStatistics?.Experience ?? 0))
.First();
if (teams.First().Key == myTeam && (myTeam != 0 || teams.First().First().Player == self.Owner))
if (victoriousTeam.Key == myTeam && (myTeam != 0 || victoriousTeam.First().Player == self.Owner))
{
mo.MarkCompleted(self.Owner, objectiveID);
return;

View File

@@ -44,10 +44,19 @@ namespace OpenRA.Mods.Common.Traits
if (rejectsOrdersTraits.Length == 0)
return true;
var reject = rejectsOrdersTraits.SelectMany(t => t.Reject);
var except = rejectsOrdersTraits.SelectMany(t => t.Except);
foreach (var rejectsOrdersTrait in rejectsOrdersTraits)
if (rejectsOrdersTrait.Except.Contains(orderString))
return true;
return except.Contains(orderString) || (reject.Any() && !reject.Contains(orderString));
var anyRejects = false;
foreach (var rejectsOrdersTrait in rejectsOrdersTraits)
{
anyRejects = anyRejects || rejectsOrdersTrait.Reject.Count > 0;
if (rejectsOrdersTrait.Reject.Contains(orderString))
return false;
}
return anyRejects;
}
}
}

View File

@@ -51,29 +51,27 @@ namespace OpenRA.Mods.Common.Traits.Render
if (IsTraitDisabled)
return r;
var renderables = r.ToList();
var height = self.World.Map.DistanceAboveTerrain(self.CenterPosition).Length;
var shadowSprites = r.Where(s => !s.IsDecoration && s is IModifyableRenderable)
var shadowSprites = renderables.Where(s => !s.IsDecoration && s is IModifyableRenderable)
.Select(ma => ((IModifyableRenderable)ma).WithTint(shadowColor, ((IModifyableRenderable)ma).TintModifiers | TintModifiers.ReplaceColor)
.WithAlpha(shadowAlpha)
.OffsetBy(info.Offset - new WVec(0, 0, height))
.WithZOffset(ma.ZOffset + height + info.ZOffset)
.AsDecoration());
return shadowSprites.Concat(r);
return shadowSprites.Concat(renderables);
}
IEnumerable<Rectangle> IRenderModifier.ModifyScreenBounds(Actor self, WorldRenderer wr, IEnumerable<Rectangle> bounds)
{
foreach (var r in bounds)
yield return r;
if (IsTraitDisabled)
yield break;
return bounds;
var boundsList = bounds.ToList();
var height = self.World.Map.DistanceAboveTerrain(self.CenterPosition).Length;
var offset = wr.ScreenPxOffset(info.Offset - new WVec(0, 0, height));
foreach (var r in bounds)
yield return new Rectangle(r.X + offset.X, r.Y + offset.Y, r.Width, r.Height);
return boundsList.Concat(boundsList.Select(r => new Rectangle(r.X + offset.X, r.Y + offset.Y, r.Width, r.Height)));
}
}
}

View File

@@ -205,8 +205,8 @@ namespace OpenRA.Mods.Common.Traits
actorShouldBeRemoved = removeActorPosition.Contains;
LargestActorRadius = map.Rules.Actors.SelectMany(a => a.Value.TraitInfos<HitShapeInfo>()).Max(h => h.Type.OuterRadius);
var blockers = map.Rules.Actors.Where(a => a.Value.HasTraitInfo<IBlocksProjectilesInfo>());
LargestBlockingActorRadius = blockers.Any() ? blockers.SelectMany(a => a.Value.TraitInfos<HitShapeInfo>()).Max(h => h.Type.OuterRadius) : WDist.Zero;
var blockers = map.Rules.Actors.Where(a => a.Value.HasTraitInfo<IBlocksProjectilesInfo>()).ToList();
LargestBlockingActorRadius = blockers.Count != 0 ? blockers.SelectMany(a => a.Value.TraitInfos<HitShapeInfo>()).Max(h => h.Type.OuterRadius) : WDist.Zero;
}
void INotifyCreated.Created(Actor self)

View File

@@ -28,7 +28,7 @@ namespace OpenRA.Mods.Common.Traits
/// </summary>
void ICreatePlayersInfo.CreateServerPlayers(MapPreview map, Session lobbyInfo, List<GameInformation.Player> players, MersenneTwister playerRandom)
{
var factions = map.WorldActorInfo.TraitInfos<FactionInfo>().ToArray();
var factions = map.WorldActorInfo.TraitInfos<FactionInfo>();
var assignSpawnLocations = map.WorldActorInfo.TraitInfoOrDefault<IAssignSpawnPointsInfo>();
var spawnState = assignSpawnLocations?.InitializeState(map, lobbyInfo);
@@ -41,7 +41,7 @@ namespace OpenRA.Mods.Common.Traits
}
// Create the regular playable players.
var bots = map.PlayerActorInfo.TraitInfos<IBotInfo>().ToArray();
var bots = map.PlayerActorInfo.TraitInfos<IBotInfo>();
foreach (var kv in lobbyInfo.Slots)
{

View File

@@ -178,7 +178,7 @@ namespace OpenRA.Mods.Common.Traits
return reference.GetOrDefault<T>(info);
}
public IEnumerable<T> GetInits<T>() where T : ActorInit
public IReadOnlyCollection<T> GetInits<T>() where T : ActorInit
{
return reference.GetAll<T>();
}

View File

@@ -136,7 +136,7 @@ namespace OpenRA.Mods.Common.Traits
public readonly LongBitSet<PlayerBitMask> Crushable;
public readonly CellFlag CellFlag;
public CellCache(LongBitSet<PlayerBitMask> immovable, CellFlag cellFlag, LongBitSet<PlayerBitMask> crushable = default)
public CellCache(LongBitSet<PlayerBitMask> immovable, CellFlag cellFlag, LongBitSet<PlayerBitMask> crushable)
{
Immovable = immovable;
Crushable = crushable;
@@ -459,26 +459,17 @@ namespace OpenRA.Mods.Common.Traits
using (new PerfSample("locomotor_cache"))
{
var cache = blockingCache[cell.Layer];
var actors = actorMap.GetActorsAt(cell);
var cellFlag = CellFlag.HasFreeSpace;
if (!actors.Any())
{
cache[cell] = new CellCache(default, cellFlag);
return;
}
if (sharesCell && actorMap.HasFreeSubCell(cell))
{
cache[cell] = new CellCache(default, cellFlag);
return;
}
var cellImmovablePlayers = default(LongBitSet<PlayerBitMask>);
var cellCrushablePlayers = world.AllPlayersMask;
foreach (var actor in actors)
if (sharesCell && actorMap.HasFreeSubCell(cell))
{
cache[cell] = new CellCache(cellImmovablePlayers, cellFlag, cellCrushablePlayers);
return;
}
foreach (var actor in actorMap.GetActorsAt(cell))
{
var actorImmovablePlayers = world.AllPlayersMask;
var actorCrushablePlayers = world.NoPlayersMask;
@@ -493,11 +484,10 @@ namespace OpenRA.Mods.Common.Traits
if (isTransitOnly)
cellFlag |= CellFlag.HasTransitOnlyActor;
if (crushables.Any())
foreach (var crushable in crushables)
{
cellFlag |= CellFlag.HasCrushableActor;
foreach (var crushable in crushables)
actorCrushablePlayers = actorCrushablePlayers.Union(crushable.CrushableBy(actor, Info.Crushes));
actorCrushablePlayers = actorCrushablePlayers.Union(crushable.CrushableBy(actor, Info.Crushes));
}
if (isMoving)

View File

@@ -10,7 +10,6 @@
#endregion
using System.Collections.Generic;
using System.Linq;
namespace OpenRA.Mods.Common.UpdateRules.Rules
{
@@ -24,7 +23,7 @@ namespace OpenRA.Mods.Common.UpdateRules.Rules
public override IEnumerable<string> AfterUpdate(ModData modData)
{
if (locations.Any())
if (locations.Count != 0)
yield return "Icon overlay logic has been split from ProducibleWithLevel to WithProductionIconOverlay trait.\n" +
"If you have been using VeteranProductionIconOverlay trait, add WithProductionIconOverlay to following actors:\n" +
UpdateUtils.FormatMessageList(locations);

View File

@@ -45,16 +45,16 @@ namespace OpenRA.Mods.Common.UpdateRules.Rules
foreach (var sequenceNode in imageNode.Value.Nodes)
{
var useTilesetExtensionNode = sequenceNode.LastChildMatching("UseTilesetExtension");
if (useTilesetExtensionNode != null && !tilesetExtensions.Any())
if (useTilesetExtensionNode != null && tilesetExtensions.Count == 0)
requiredMetadata.Add("TilesetExtensions");
var useTilesetCodeNode = sequenceNode.LastChildMatching("UseTilesetCode");
if (useTilesetCodeNode != null && !tilesetCodes.Any())
if (useTilesetCodeNode != null && tilesetCodes.Count == 0)
requiredMetadata.Add("TilesetCodes");
}
}
if (requiredMetadata.Any())
if (requiredMetadata.Count != 0)
{
yield return $"The ExplicitSequenceFilenames rule requires {requiredMetadata.JoinWith(", ")}\n" +
"to be defined under the SpriteSequenceFormat definition in mod.yaml.\n" +
@@ -317,7 +317,7 @@ namespace OpenRA.Mods.Common.UpdateRules.Rules
if (allSequencesHaveTilesetFilenames)
sequenceNode.RemoveNodes("TilesetFilenames");
if (!sequenceNode.Value.Nodes.Any())
if (sequenceNode.Value.Nodes.Count == 0)
imageNode.RemoveNode(sequenceNode);
}
@@ -328,13 +328,13 @@ namespace OpenRA.Mods.Common.UpdateRules.Rules
sequenceNode.RemoveNodes("TilesetFilenames");
var tilesetFilenamesNode = sequenceNode.LastChildMatching("TilesetFilenames");
if (allSequencesHaveTilesetFilenames && tilesetFilenamesNode != null && !tilesetFilenamesNode.Value.Nodes.Any())
if (allSequencesHaveTilesetFilenames && tilesetFilenamesNode != null && tilesetFilenamesNode.Value.Nodes.Count == 0)
sequenceNode.RemoveNode(tilesetFilenamesNode);
}
}
foreach (var sequenceNode in imageNode.Value.Nodes.ToList())
if (implicitInheritedSequences.Contains(sequenceNode.Key) && !sequenceNode.Value.Nodes.Any())
if (implicitInheritedSequences.Contains(sequenceNode.Key) && sequenceNode.Value.Nodes.Count == 0)
imageNode.RemoveNode(sequenceNode);
}
@@ -424,7 +424,7 @@ namespace OpenRA.Mods.Common.UpdateRules.Rules
if (overrideNode.Value.Value == filenameNode.Value.Value)
tilesetFilenamesNode.Value.Nodes.Remove(overrideNode);
if (!tilesetFilenamesNode.Value.Nodes.Any())
if (tilesetFilenamesNode.Value.Nodes.Count == 0)
sequenceNode.RemoveNode(tilesetFilenamesNode);
sequenceNode.Value.Nodes.Insert(0, filenameNode);

View File

@@ -114,7 +114,7 @@ namespace OpenRA.Mods.Common.UpdateRules
}),
};
public static IEnumerable<UpdateRule> FromSource(ObjectCreator objectCreator, string source, bool chain = true)
public static IReadOnlyCollection<UpdateRule> FromSource(ObjectCreator objectCreator, string source, bool chain = true)
{
// Use reflection to identify types
var namedType = objectCreator.FindType(source);
@@ -143,12 +143,12 @@ namespace OpenRA.Mods.Common.UpdateRules
this.chainToSource = chainToSource;
}
IEnumerable<UpdateRule> Rules(bool chain = true)
IReadOnlyCollection<UpdateRule> Rules(bool chain = true)
{
if (chainToSource != null && chain)
{
var child = Paths.First(p => p.source == chainToSource);
return rules.Concat(child.Rules(chain));
return rules.Concat(child.Rules(chain)).ToList();
}
return rules;

View File

@@ -271,7 +271,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
if (isActivity)
Console.WriteLine(" --- *Queued Activity*");
if (requiredTraits.Any())
if (requiredTraits.Length != 0)
Console.WriteLine($" --- **Requires {(requiredTraits.Length == 1 ? "Trait" : "Traits")}:** {requiredTraits.Select(GetDocumentationUrl).JoinWith(", ")}");
if (memberInfo is MethodInfo methodInfo)

View File

@@ -38,7 +38,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
if (folder.OpenPackage(args[1], modData.ModFiles) is not IReadWritePackage package)
throw new FileNotFoundException(args[1]);
IEnumerable<UpdateRule> rules = null;
IReadOnlyCollection<UpdateRule> rules = null;
if (args.Length > 2)
rules = UpdatePath.FromSource(modData.ObjectCreator, args[2]);
@@ -77,9 +77,10 @@ namespace OpenRA.Mods.Common.UtilityCommands
}
var other = UpdatePath.KnownRules(modData.ObjectCreator)
.Where(r => !ruleGroups.Values.Any(g => g.Contains(r)));
.Where(r => !ruleGroups.Values.Any(g => g.Contains(r)))
.ToList();
if (other.Any())
if (other.Count != 0)
{
Console.WriteLine(" Other:");
foreach (var r in other)

View File

@@ -32,7 +32,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
// HACK: The engine code assumes that Game.modData is set.
var modData = Game.ModData = utility.ModData;
IEnumerable<UpdateRule> rules = null;
IReadOnlyCollection<UpdateRule> rules = null;
if (args.Length > 1)
rules = UpdatePath.FromSource(modData.ObjectCreator, args[1]);
@@ -71,9 +71,10 @@ namespace OpenRA.Mods.Common.UtilityCommands
}
var other = UpdatePath.KnownRules(modData.ObjectCreator)
.Where(r => !ruleGroups.Values.Any(g => g.Contains(r)));
.Where(r => !ruleGroups.Values.Any(g => g.Contains(r)))
.ToList();
if (other.Any())
if (other.Count != 0)
{
Console.WriteLine(" Other:");
foreach (var r in other)
@@ -111,9 +112,9 @@ namespace OpenRA.Mods.Common.UtilityCommands
PrintSummary(rules, args.Contains("--detailed"));
}
public static void PrintSummary(IEnumerable<UpdateRule> rules, bool detailed)
public static void PrintSummary(IReadOnlyCollection<UpdateRule> rules, bool detailed)
{
var count = rules.Count();
var count = rules.Count;
if (count == 1)
Console.WriteLine("Found 1 API change:");
else

View File

@@ -60,9 +60,9 @@ namespace OpenRA.Mods.Common.Warheads
if (RandomClusterCount != 0)
{
var randomTargetCells = CellsMatching(targetCell, true);
var clusterCount = RandomClusterCount < 0 ? randomTargetCells.Count() : RandomClusterCount;
if (randomTargetCells.Any())
var randomTargetCells = CellsMatching(targetCell, true).ToList();
var clusterCount = RandomClusterCount < 0 ? randomTargetCells.Count : RandomClusterCount;
if (randomTargetCells.Count != 0)
for (var i = 0; i < clusterCount; i++)
FireProjectileAtCell(map, firedBy, target, randomTargetCells.Random(firedBy.World.SharedRandom), args);
}

View File

@@ -84,7 +84,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
var actors = new List<KeyValuePair<ActorInfo, EncyclopediaInfo>>();
foreach (var actor in modData.DefaultRules.Actors.Values)
{
if (!actor.TraitInfos<IRenderActorPreviewSpritesInfo>().Any())
if (actor.TraitInfos<IRenderActorPreviewSpritesInfo>().Count == 0)
continue;
var statistics = actor.TraitInfoOrDefault<UpdatesPlayerStatisticsInfo>();

View File

@@ -113,7 +113,8 @@ namespace OpenRA.Mods.Common.Widgets.Logic
.Select(p => (Player: p, PlayerStatistics: p.PlayerActor.TraitOrDefault<PlayerStatistics>()))
.OrderByDescending(p => p.PlayerStatistics?.Experience ?? 0)
.GroupBy(p => (world.LobbyInfo.ClientWithIndex(p.Player.ClientIndex) ?? new Session.Client()).Team)
.OrderByDescending(g => g.Sum(gg => gg.PlayerStatistics?.Experience ?? 0));
.OrderByDescending(g => g.Sum(gg => gg.PlayerStatistics?.Experience ?? 0))
.ToList();
void KickAction(Session.Client client)
{
@@ -133,7 +134,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
foreach (var t in teams)
{
if (teams.Count() > 1)
if (teams.Count > 1)
{
var teamHeader = ScrollItemWidget.Setup(teamTemplate, () => false, () => { });
var team = t.Key > 0

View File

@@ -114,9 +114,10 @@ namespace OpenRA.Mods.Common.Widgets.Logic
.GroupBy(p => (world.LobbyInfo.ClientWithIndex(p.Player.ClientIndex) ?? new Session.Client()).Team)
.OrderBy(g => g.Key);
var noTeams = teams.Count() == 1;
var teamsList = teams.ToList();
var noTeams = teamsList.Count == 1;
var totalPlayers = 0;
foreach (var t in teams)
foreach (var t in teamsList)
{
totalPlayers += t.Count();
var label = noTeams ? TranslationProvider.GetString(Players) : t.Key > 0
@@ -209,12 +210,12 @@ namespace OpenRA.Mods.Common.Widgets.Logic
if (e.Key >= Keycode.NUMBER_0 && e.Key <= Keycode.NUMBER_9)
{
var key = (int)e.Key - (int)Keycode.NUMBER_0;
var team = teams.Where(t => t.Key == key).SelectMany(s => s);
if (!team.Any())
var team = teams.Where(t => t.Key == key).SelectMany(s => s).ToList();
if (team.Count == 0)
return false;
if (e.Modifiers == Modifiers.Shift)
team = team.Reverse();
team.Reverse();
selected = team.SkipWhile(t => t.Player != selected.Player).Skip(1).FirstOrDefault() ?? team.FirstOrDefault();
selected.OnClick();

View File

@@ -183,7 +183,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
selectedPackages = availablePackages.ToDictionary(x => x.Identifier, y => y.Required);
// Ignore source if content is already installed
if (availablePackages.Any())
if (availablePackages.Length != 0)
{
Game.RunAfterTick(() =>
{
@@ -218,10 +218,10 @@ namespace OpenRA.Mods.Common.Widgets.Logic
var options = new Dictionary<string, IEnumerable<string>>();
if (gameSources.Any())
if (gameSources.Count != 0)
options.Add(TranslationProvider.GetString(GameSources), gameSources);
if (digitalInstalls.Any())
if (digitalInstalls.Count != 0)
options.Add(TranslationProvider.GetString(DigitalInstalls), digitalInstalls);
Game.RunAfterTick(() =>

View File

@@ -322,18 +322,19 @@ namespace OpenRA.Mods.Common.Widgets.Logic
if (!int.TryParse(mapFilter, out var playerCountFilter))
playerCountFilter = -1;
var validMaps = tabMaps[tab]
var maps = tabMaps[tab]
.Where(m => category == null || m.Categories.Contains(category))
.Where(m => mapFilter == null ||
(m.Title != null && m.Title.Contains(mapFilter, StringComparison.CurrentCultureIgnoreCase)) ||
(m.Author != null && m.Author.Contains(mapFilter, StringComparison.CurrentCultureIgnoreCase)) ||
m.PlayerCount == playerCountFilter);
IOrderedEnumerable<MapPreview> maps;
if (orderByFunc == null)
maps = validMaps.OrderBy(m => m.Title);
maps = maps.OrderBy(m => m.Title);
else
maps = validMaps.OrderBy(orderByFunc).ThenBy(m => m.Title);
maps = maps.OrderBy(orderByFunc).ThenBy(m => m.Title);
maps = maps.ToList();
scrollpanels[tab].RemoveChildren();
foreach (var loop in maps)

View File

@@ -715,10 +715,11 @@ namespace OpenRA.Mods.Common.Widgets.Logic
var players = replay.GameInfo.Players
.GroupBy(p => p.Team)
.OrderBy(g => g.Key);
.OrderBy(g => g.Key)
.ToList();
var teams = new Dictionary<string, IEnumerable<GameInformation.Player>>();
var noTeams = players.Count() == 1;
var noTeams = players.Count == 1;
foreach (var p in players)
{
var label = noTeams ? TranslationProvider.GetString(Players) : p.Key > 0

View File

@@ -572,10 +572,11 @@ namespace OpenRA.Mods.Common.Widgets.Logic
var players = server.Clients
.Where(c => !c.IsSpectator)
.GroupBy(p => p.Team)
.OrderBy(g => g.Key);
.OrderBy(g => g.Key)
.ToList();
var teams = new Dictionary<string, IEnumerable<GameClient>>();
var noTeams = players.Count() == 1;
var noTeams = players.Count == 1;
foreach (var p in players)
{
var label = noTeams ? TranslationProvider.GetString(Players) : p.Key > 0

View File

@@ -183,9 +183,10 @@ namespace OpenRA.Mods.Common.Widgets.Logic
{
var typesInGroup = hg.Value;
var keysInGroup = modData.Hotkeys.Definitions
.Where(hd => IsHotkeyVisibleInFilter(hd) && hd.Types.Overlaps(typesInGroup));
.Where(hd => IsHotkeyVisibleInFilter(hd) && hd.Types.Overlaps(typesInGroup))
.ToList();
if (!keysInGroup.Any())
if (keysInGroup.Count == 0)
continue;
var header = headerTemplate.Clone();

View File

@@ -102,14 +102,15 @@ namespace OpenRA.Mods.Common.Widgets
var queues = world.ActorsWithTrait<ProductionQueue>()
.Where(a => a.Actor.Owner == player)
.Select((a, i) => new { a.Trait, i });
.Select(a => a.Trait)
.ToList();
foreach (var queue in queues)
if (!clocks.ContainsKey(queue.Trait))
clocks.Add(queue.Trait, new Animation(world, ClockAnimation));
if (!clocks.ContainsKey(queue))
clocks.Add(queue, new Animation(world, ClockAnimation));
var currentItemsByItem = queues
.Select(a => a.Trait.CurrentItem())
.Select(q => q.CurrentItem())
.Where(pi => pi != null)
.GroupBy(pr => pr.Item)
.OrderBy(g => g.First().Queue.Info.DisplayOrder)

View File

@@ -183,9 +183,9 @@ namespace OpenRA.Mods.Common.Widgets
public override void Draw()
{
var tabs = Groups[queueGroup].Tabs.Where(t => t.Queue.BuildableItems().Any());
var tabs = Groups[queueGroup].Tabs.Where(t => t.Queue.BuildableItems().Any()).ToList();
if (!tabs.Any())
if (tabs.Count == 0)
return;
var rb = RenderBounds;

View File

@@ -51,7 +51,7 @@ namespace OpenRA.Mods.D2k.Activities
swallow = self.Trait<AttackSwallow>();
}
bool AttackTargets(Actor self, IEnumerable<Actor> targets)
bool AttackTargets(Actor self, IReadOnlyCollection<Actor> targets)
{
var targetLocation = target.Actor.Location;
foreach (var t in targets)
@@ -129,9 +129,10 @@ namespace OpenRA.Mods.D2k.Activities
}
var targets = self.World.ActorMap.GetActorsAt(targetLocation)
.Where(t => !t.Equals(self) && weapon.IsValidAgainst(t, self));
.Where(t => !t.Equals(self) && weapon.IsValidAgainst(t, self))
.ToList();
if (!targets.Any())
if (targets.Count == 0)
{
RevokeCondition(self);
return true;

View File

@@ -509,17 +509,12 @@ namespace OpenRA.Mods.D2k.UtilityCommands
// HACK: The arrakis.yaml tileset file seems to be missing some tiles, so just get a replacement for them
// Also used for duplicate tiles that are taken from only tileset
if (template == null)
// Just get a template that contains a tile with the same ID as requested
template ??= terrainInfo.Templates.FirstOrDefault(t =>
{
// Just get a template that contains a tile with the same ID as requested
var templates = terrainInfo.Templates.Where(t =>
{
var templateInfo = (DefaultTerrainTemplateInfo)t.Value;
return templateInfo.Frames != null && templateInfo.Frames.Contains(tileIndex);
});
if (templates.Any())
template = templates.First().Value;
}
var templateInfo = (DefaultTerrainTemplateInfo)t.Value;
return templateInfo.Frames != null && templateInfo.Frames.Contains(tileIndex);
}).Value;
if (template == null)
{