Fix CA1851, assume_method_enumerates_parameters = true

This commit is contained in:
RoosterDragon
2023-07-14 20:30:08 +01:00
committed by abcdefg30
parent 3275875ae5
commit 93a97d5d6f
37 changed files with 108 additions and 96 deletions

View File

@@ -836,8 +836,8 @@ dotnet_diagnostic.CA1850.severity = none
# Possible multiple enumerations of IEnumerable collection. # Possible multiple enumerations of IEnumerable collection.
#dotnet_code_quality.CA1851.enumeration_methods = #dotnet_code_quality.CA1851.enumeration_methods =
#dotnet_code_quality.CA1851.linq_chain_methods = dotnet_code_quality.CA1851.linq_chain_methods = M:OpenRA.Traits.IRenderModifier.Modify*
#dotnet_code_quality.CA1851.assume_method_enumerates_parameters = false dotnet_code_quality.CA1851.assume_method_enumerates_parameters = true
dotnet_diagnostic.CA1851.severity = warning dotnet_diagnostic.CA1851.severity = warning
# Seal internal types. # Seal internal types.

View File

@@ -147,7 +147,7 @@ namespace OpenRA
static T Random<T>(IEnumerable<T> ts, MersenneTwister r, bool throws) static T Random<T>(IEnumerable<T> ts, MersenneTwister r, bool throws)
{ {
var xs = ts as ICollection<T>; var xs = ts as IReadOnlyCollection<T>;
xs ??= ts.ToList(); xs ??= ts.ToList();
if (xs.Count == 0) if (xs.Count == 0)
{ {

View File

@@ -523,10 +523,11 @@ namespace OpenRA
.Where(m => m.Status == MapStatus.Available && m.Visibility.HasFlag(MapVisibility.Shellmap)) .Where(m => m.Status == MapStatus.Available && m.Visibility.HasFlag(MapVisibility.Shellmap))
.Select(m => m.Uid); .Select(m => m.Uid);
if (!shellmaps.Any()) var shellmap = shellmaps.RandomOrDefault(CosmeticRandom);
if (shellmap == null)
throw new InvalidDataException("No valid shellmaps available"); throw new InvalidDataException("No valid shellmaps available");
return shellmaps.Random(CosmeticRandom); return shellmap;
} }
public static void SwitchToExternalMod(ExternalMod mod, string[] launchArguments = null, Action onFailed = null) public static void SwitchToExternalMod(ExternalMod mod, string[] launchArguments = null, Action onFailed = null)

View File

@@ -130,6 +130,7 @@ namespace OpenRA
// Continue resolving traits as long as possible. // Continue resolving traits as long as possible.
// Each time we resolve some traits, this means dependencies for other traits may then be possible to satisfy in the next pass. // Each time we resolve some traits, this means dependencies for other traits may then be possible to satisfy in the next pass.
#pragma warning disable CA1851 // Possible multiple enumerations of 'IEnumerable' collection
var readyToResolve = more.ToList(); var readyToResolve = more.ToList();
while (readyToResolve.Count != 0) while (readyToResolve.Count != 0)
{ {
@@ -138,6 +139,7 @@ namespace OpenRA
readyToResolve.Clear(); readyToResolve.Clear();
readyToResolve.AddRange(more); readyToResolve.AddRange(more);
} }
#pragma warning restore CA1851
if (unresolved.Count != 0) if (unresolved.Count != 0)
{ {

View File

@@ -299,10 +299,13 @@ namespace OpenRA.Graphics
public void Center(IEnumerable<Actor> actors) public void Center(IEnumerable<Actor> actors)
{ {
if (!actors.Any()) var actorsCollection = actors as IReadOnlyCollection<Actor>;
actorsCollection ??= actors.ToList();
if (actorsCollection.Count == 0)
return; return;
Center(actors.Select(a => a.CenterPosition).Average()); Center(actorsCollection.Select(a => a.CenterPosition).Average());
} }
public void Center(WPos pos) public void Center(WPos pos)

View File

@@ -62,10 +62,7 @@ namespace OpenRA.Traits
public static Actor WithHighestSelectionPriority(this IEnumerable<ActorBoundsPair> actors, int2 selectionPixel, Modifiers modifiers) public static Actor WithHighestSelectionPriority(this IEnumerable<ActorBoundsPair> actors, int2 selectionPixel, Modifiers modifiers)
{ {
if (!actors.Any()) return actors.MaxByOrDefault(a => CalculateActorSelectionPriority(a.Actor.Info, a.Bounds, selectionPixel, modifiers)).Actor;
return null;
return actors.MaxBy(a => CalculateActorSelectionPriority(a.Actor.Info, a.Bounds, selectionPixel, modifiers)).Actor;
} }
public static FrozenActor WithHighestSelectionPriority(this IEnumerable<FrozenActor> actors, int2 selectionPixel, Modifiers modifiers) public static FrozenActor WithHighestSelectionPriority(this IEnumerable<FrozenActor> actors, int2 selectionPixel, Modifiers modifiers)

View File

@@ -349,7 +349,7 @@ namespace OpenRA.Support
return Enumerable.Concat(new[] { runtimeGraph.Runtime }, runtimeGraph?.Fallbacks ?? Enumerable.Empty<string>()); return Enumerable.Concat(new[] { runtimeGraph.Runtime }, runtimeGraph?.Fallbacks ?? Enumerable.Empty<string>());
} }
static IEnumerable<string> SelectAssets(IEnumerable<string> rids, IEnumerable<RuntimeAssetGroup> groups) static IEnumerable<string> SelectAssets(IEnumerable<string> rids, IReadOnlyCollection<RuntimeAssetGroup> groups)
{ {
foreach (var rid in rids) foreach (var rid in rids)
{ {

View File

@@ -455,7 +455,7 @@ namespace OpenRA.Traits
public interface ISelection public interface ISelection
{ {
int Hash { get; } int Hash { get; }
IEnumerable<Actor> Actors { get; } IReadOnlyCollection<Actor> Actors { get; }
void Add(Actor a); void Add(Actor a);
void Remove(Actor a); void Remove(Actor a);

View File

@@ -11,6 +11,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using OpenRA.Activities; using OpenRA.Activities;
using OpenRA.Mods.Common.Traits; using OpenRA.Mods.Common.Traits;
using OpenRA.Primitives; using OpenRA.Primitives;
@@ -211,7 +212,7 @@ namespace OpenRA.Mods.Common.Activities
if (!landingInitiated) if (!landingInitiated)
{ {
var blockingCells = clearCells.Append(landingCell); var blockingCells = clearCells.Append(landingCell).ToList();
if (!aircraft.CanLand(blockingCells, target.Actor)) if (!aircraft.CanLand(blockingCells, target.Actor))
{ {

View File

@@ -66,12 +66,12 @@ namespace OpenRA.Mods.Common.Lint
granted.Add(g); granted.Add(g);
} }
var unconsumed = granted.Except(consumed); var unconsumed = granted.Except(consumed).ToList();
if (unconsumed.Any()) if (unconsumed.Count != 0)
emitWarning($"Actor type `{actorInfo.Key}` grants conditions that are not consumed: {unconsumed.JoinWith(", ")}."); emitWarning($"Actor type `{actorInfo.Key}` grants conditions that are not consumed: {unconsumed.JoinWith(", ")}.");
var ungranted = consumed.Except(granted); var ungranted = consumed.Except(granted).ToList();
if (ungranted.Any()) if (ungranted.Count != 0)
emitError($"Actor type `{actorInfo.Key}` consumes conditions that are not granted: {ungranted.JoinWith(", ")}."); emitError($"Actor type `{actorInfo.Key}` consumes conditions that are not granted: {ungranted.JoinWith(", ")}.");
} }
} }

View File

@@ -21,8 +21,7 @@ namespace OpenRA.Mods.Common.Lint
public void Run(Action<string> emitError, Action<string> emitWarning, ModData modData) public void Run(Action<string> emitError, Action<string> emitWarning, ModData modData)
{ {
var modTypes = modData.ObjectCreator.GetTypes(); var modTypes = modData.ObjectCreator.GetTypes();
CheckTypesWithSyncableMembersImplementSyncInterface(modTypes, emitWarning); CheckTypes(modTypes, emitWarning);
CheckTypesImplementingSyncInterfaceHaveSyncableMembers(modTypes, emitWarning);
} }
static readonly Type SyncInterface = typeof(ISync); static readonly Type SyncInterface = typeof(ISync);
@@ -45,18 +44,18 @@ namespace OpenRA.Mods.Common.Lint
return false; return false;
} }
static void CheckTypesWithSyncableMembersImplementSyncInterface(IEnumerable<Type> types, Action<string> emitWarning) static void CheckTypes(IEnumerable<Type> types, Action<string> emitWarning)
{ {
foreach (var type in types) foreach (var type in types)
if (!TypeImplementsSync(type) && AnyTypeMemberIsSynced(type)) {
emitWarning($"{type.FullName} has members with the Sync attribute but does not implement ISync."); var typeImplementsSync = TypeImplementsSync(type);
} var anyTypeMemberIsSynced = AnyTypeMemberIsSynced(type);
static void CheckTypesImplementingSyncInterfaceHaveSyncableMembers(IEnumerable<Type> types, Action<string> emitWarning) if (!typeImplementsSync && anyTypeMemberIsSynced)
{ emitWarning($"{type.FullName} has members with the Sync attribute but does not implement ISync.");
foreach (var type in types) else if (typeImplementsSync && !anyTypeMemberIsSynced)
if (TypeImplementsSync(type) && !AnyTypeMemberIsSynced(type))
emitWarning($"{type.FullName} implements ISync but does not use the Sync attribute on any members."); emitWarning($"{type.FullName} implements ISync but does not use the Sync attribute on any members.");
}
} }
} }
} }

View File

@@ -85,7 +85,7 @@ namespace OpenRA.Mods.Common.Orders
return cursorOrder.Cursor; return cursorOrder.Cursor;
useSelect = target.Type == TargetType.Actor && target.Actor.Info.HasTraitInfo<ISelectableInfo>() && useSelect = target.Type == TargetType.Actor && target.Actor.Info.HasTraitInfo<ISelectableInfo>() &&
(mi.Modifiers.HasModifier(Modifiers.Shift) || !world.Selection.Actors.Any()); (mi.Modifiers.HasModifier(Modifiers.Shift) || world.Selection.Actors.Count == 0);
} }
return useSelect ? worldSelectCursor : worldDefaultCursor; return useSelect ? worldSelectCursor : worldDefaultCursor;

View File

@@ -72,7 +72,8 @@ namespace OpenRA.Mods.Common.Scripting
} }
var initializers = initType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) var initializers = initType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
.Where(m => m.Name == "Initialize" && m.GetParameters().Length == 1); .Where(m => m.Name == "Initialize" && m.GetParameters().Length == 1)
.ToList();
foreach (var initializer in initializers) foreach (var initializer in initializers)
{ {

View File

@@ -530,9 +530,9 @@ namespace OpenRA.Mods.Common.Server
// Pick a random color for the bot // Pick a random color for the bot
var colorManager = server.ModData.DefaultRules.Actors[SystemActors.World].TraitInfo<IColorPickerManagerInfo>(); var colorManager = server.ModData.DefaultRules.Actors[SystemActors.World].TraitInfo<IColorPickerManagerInfo>();
var terrainColors = server.ModData.DefaultTerrainInfo[server.Map.TileSet].RestrictedPlayerColors; var terrainColors = server.ModData.DefaultTerrainInfo[server.Map.TileSet].RestrictedPlayerColors.ToList();
var playerColors = server.LobbyInfo.Clients.Select(c => c.Color) var playerColors = server.LobbyInfo.Clients.Select(c => c.Color)
.Concat(server.Map.Players.Players.Values.Select(p => p.Color)); .Concat(server.Map.Players.Players.Values.Select(p => p.Color)).ToList();
bot.Color = bot.PreferredColor = colorManager.RandomPresetColor(server.Random, terrainColors, playerColors); bot.Color = bot.PreferredColor = colorManager.RandomPresetColor(server.Random, terrainColors, playerColors);
@@ -935,7 +935,8 @@ namespace OpenRA.Mods.Common.Server
return true; return true;
var factions = server.Map.WorldActorInfo.TraitInfos<FactionInfo>() var factions = server.Map.WorldActorInfo.TraitInfos<FactionInfo>()
.Where(f => f.Selectable).Select(f => f.InternalName); .Where(f => f.Selectable).Select(f => f.InternalName)
.ToList();
var faction = parts[1]; var faction = parts[1];
if (!factions.Contains(faction)) if (!factions.Contains(faction))
@@ -1250,7 +1251,7 @@ namespace OpenRA.Mods.Common.Server
server.SendLocalizedMessageTo(connectionToEcho, message); server.SendLocalizedMessageTo(connectionToEcho, message);
} }
var terrainColors = server.ModData.DefaultTerrainInfo[server.Map.TileSet].RestrictedPlayerColors; var terrainColors = server.ModData.DefaultTerrainInfo[server.Map.TileSet].RestrictedPlayerColors.ToList();
var playerColors = server.LobbyInfo.Clients.Where(c => c.Index != playerIndex).Select(c => c.Color) var playerColors = server.LobbyInfo.Clients.Where(c => c.Index != playerIndex).Select(c => c.Color)
.Concat(server.Map.Players.Players.Values.Select(p => p.Color)).ToList(); .Concat(server.Map.Players.Players.Values.Select(p => p.Color)).ToList();

View File

@@ -239,9 +239,10 @@ namespace OpenRA.Mods.Common.Traits
CPos ChooseRallyLocationNear(Actor producer) CPos ChooseRallyLocationNear(Actor producer)
{ {
var possibleRallyPoints = world.Map.FindTilesInCircle(producer.Location, Info.RallyPointScanRadius) var possibleRallyPoints = world.Map.FindTilesInCircle(producer.Location, Info.RallyPointScanRadius)
.Where(c => IsRallyPointValid(c, producer.Info.TraitInfoOrDefault<BuildingInfo>())); .Where(c => IsRallyPointValid(c, producer.Info.TraitInfoOrDefault<BuildingInfo>()))
.ToList();
if (!possibleRallyPoints.Any()) if (possibleRallyPoints.Count == 0)
{ {
AIUtils.BotDebug("{0} has no possible rallypoint near {1}", producer.Owner, producer.Location); AIUtils.BotDebug("{0} has no possible rallypoint near {1}", producer.Owner, producer.Location);
return producer.Location; return producer.Location;

View File

@@ -229,7 +229,7 @@ namespace OpenRA.Mods.Common.Traits
ActorInfo ChooseBuildingToBuild(ProductionQueue queue) ActorInfo ChooseBuildingToBuild(ProductionQueue queue)
{ {
var buildableThings = queue.BuildableItems(); var buildableThings = queue.BuildableItems().ToList();
// This gets used quite a bit, so let's cache it here // This gets used quite a bit, so let's cache it here
var power = GetProducibleBuilding(baseBuilder.Info.PowerTypes, buildableThings, var power = GetProducibleBuilding(baseBuilder.Info.PowerTypes, buildableThings,

View File

@@ -154,12 +154,13 @@ namespace OpenRA.Mods.Common.Traits
if (Info.CapturableActorTypes.Count > 0) if (Info.CapturableActorTypes.Count > 0)
capturableTargetOptions = capturableTargetOptions.Where(target => Info.CapturableActorTypes.Contains(target.Info.Name.ToLowerInvariant())); capturableTargetOptions = capturableTargetOptions.Where(target => Info.CapturableActorTypes.Contains(target.Info.Name.ToLowerInvariant()));
if (!capturableTargetOptions.Any()) var capturableTargetOptionsList = capturableTargetOptions.ToList();
if (capturableTargetOptionsList.Count == 0)
return; return;
foreach (var capturer in capturers) foreach (var capturer in capturers)
{ {
var targetActor = capturableTargetOptions.MinByOrDefault(target => (target.CenterPosition - capturer.Actor.CenterPosition).LengthSquared); var targetActor = capturableTargetOptionsList.MinByOrDefault(target => (target.CenterPosition - capturer.Actor.CenterPosition).LengthSquared);
if (targetActor == null) if (targetActor == null)
continue; continue;

View File

@@ -197,7 +197,7 @@ namespace OpenRA.Mods.Common.Traits
internal Actor FindClosestEnemy(WPos pos) internal Actor FindClosestEnemy(WPos pos)
{ {
var units = World.Actors.Where(IsPreferredEnemyUnit); var units = World.Actors.Where(IsPreferredEnemyUnit).ToList();
return units.Where(IsNotHiddenUnit).ClosestTo(pos) ?? units.ClosestTo(pos); return units.Where(IsNotHiddenUnit).ClosestTo(pos) ?? units.ClosestTo(pos);
} }

View File

@@ -35,10 +35,9 @@ namespace OpenRA.Mods.Common.Traits.BotModules.Squads
&& mobile.PathFinder.PathExistsForLocomotor(mobile.Locomotor, first.Location, a.Location) && mobile.PathFinder.PathExistsForLocomotor(mobile.Locomotor, first.Location, a.Location)
&& a.AppearsHostileTo(first)); && a.AppearsHostileTo(first));
if (navalProductions.Any()) var nearest = navalProductions.ClosestTo(first);
if (nearest != null)
{ {
var nearest = navalProductions.ClosestTo(first);
// Return nearest when it is FAR enough. // Return nearest when it is FAR enough.
// If the naval production is within MaxBaseRadius, it implies that // If the naval production is within MaxBaseRadius, it implies that
// this squad is close to enemy territory and they should expect a naval combat; // this squad is close to enemy territory and they should expect a naval combat;

View File

@@ -163,11 +163,8 @@ namespace OpenRA.Mods.Common.Traits
ActorInfo ChooseRandomUnitToBuild(ProductionQueue queue) ActorInfo ChooseRandomUnitToBuild(ProductionQueue queue)
{ {
var buildableThings = queue.BuildableItems(); var buildableThings = queue.BuildableItems();
if (!buildableThings.Any()) var unit = buildableThings.RandomOrDefault(world.LocalRandom);
return null; return unit != null && HasAdequateAirUnitReloadBuildings(unit) ? unit : null;
var unit = buildableThings.Random(world.LocalRandom);
return HasAdequateAirUnitReloadBuildings(unit) ? unit : null;
} }
ActorInfo ChooseUnitToBuild(ProductionQueue queue) ActorInfo ChooseUnitToBuild(ProductionQueue queue)

View File

@@ -115,7 +115,7 @@ namespace OpenRA.Mods.Common.Traits
if (Repairers.Remove(player)) if (Repairers.Remove(player))
{ {
UpdateCondition(self); UpdateCondition(self);
if (!Repairers.Any()) if (Repairers.Count == 0)
{ {
Game.Sound.PlayNotification(self.World.Map.Rules, player, "Speech", Info.RepairingStoppedNotification, player.Faction.InternalName); Game.Sound.PlayNotification(self.World.Map.Rules, player, "Speech", Info.RepairingStoppedNotification, player.Faction.InternalName);
TextNotificationsManager.AddTransientLine(self.Owner, Info.RepairingStoppedTextNotification); TextNotificationsManager.AddTransientLine(self.Owner, Info.RepairingStoppedTextNotification);

View File

@@ -111,11 +111,9 @@ namespace OpenRA.Mods.Common.Traits
CPos? ChooseEmptyCellNear(Actor a, string unit) CPos? ChooseEmptyCellNear(Actor a, string unit)
{ {
var possibleCells = GetSuitableCells(a.Location, unit); return GetSuitableCells(a.Location, unit)
if (!possibleCells.Any()) .Cast<CPos?>()
return null; .RandomOrDefault(self.World.SharedRandom);
return possibleCells.Random(self.World.SharedRandom);
} }
} }
} }

View File

@@ -82,7 +82,7 @@ namespace OpenRA.Mods.Common.Traits
return false; return false;
} }
Color MakeValid(float hue, float sat, float val, MersenneTwister random, IEnumerable<Color> terrainColors, IEnumerable<Color> playerColors, Action<string> onError) Color MakeValid(float hue, float sat, float val, MersenneTwister random, IReadOnlyCollection<Color> terrainColors, IReadOnlyCollection<Color> playerColors, Action<string> onError)
{ {
// Clamp saturation without triggering a warning // Clamp saturation without triggering a warning
// This can only happen due to rounding errors (common) or modified clients (rare) // This can only happen due to rounding errors (common) or modified clients (rare)
@@ -132,7 +132,7 @@ namespace OpenRA.Mods.Common.Traits
Color[] IColorPickerManagerInfo.PresetColors => PresetColors; Color[] IColorPickerManagerInfo.PresetColors => PresetColors;
Color IColorPickerManagerInfo.RandomPresetColor(MersenneTwister random, IEnumerable<Color> terrainColors, IEnumerable<Color> playerColors) Color IColorPickerManagerInfo.RandomPresetColor(MersenneTwister random, IReadOnlyCollection<Color> terrainColors, IReadOnlyCollection<Color> playerColors)
{ {
foreach (var color in PresetColors.Shuffle(random)) foreach (var color in PresetColors.Shuffle(random))
{ {
@@ -148,13 +148,13 @@ namespace OpenRA.Mods.Common.Traits
return MakeValid(randomHue, randomSat, randomVal, random, terrainColors, playerColors, null); return MakeValid(randomHue, randomSat, randomVal, random, terrainColors, playerColors, null);
} }
Color IColorPickerManagerInfo.MakeValid(Color color, MersenneTwister random, IEnumerable<Color> terrainColors, IEnumerable<Color> playerColors, Action<string> onError) Color IColorPickerManagerInfo.MakeValid(Color color, MersenneTwister random, IReadOnlyCollection<Color> terrainColors, IReadOnlyCollection<Color> playerColors, Action<string> onError)
{ {
var (_, h, s, v) = color.ToAhsv(); var (_, h, s, v) = color.ToAhsv();
return MakeValid(h, s, v, random, terrainColors, playerColors, onError); return MakeValid(h, s, v, random, terrainColors, playerColors, onError);
} }
Color IColorPickerManagerInfo.RandomValidColor(MersenneTwister random, IEnumerable<Color> terrainColors, IEnumerable<Color> playerColors) Color IColorPickerManagerInfo.RandomValidColor(MersenneTwister random, IReadOnlyCollection<Color> terrainColors, IReadOnlyCollection<Color> playerColors)
{ {
var h = random.NextFloat(); var h = random.NextFloat();
var s = float2.Lerp(HsvSaturationRange[0], HsvSaturationRange[1], random.NextFloat()); var s = float2.Lerp(HsvSaturationRange[0], HsvSaturationRange[1], random.NextFloat());

View File

@@ -47,7 +47,7 @@ namespace OpenRA.Mods.Common.Traits
public void CreateControlGroup(int group) public void CreateControlGroup(int group)
{ {
if (!world.Selection.Actors.Any()) if (world.Selection.Actors.Count == 0)
return; return;
controlGroups[group].Clear(); controlGroups[group].Clear();
@@ -59,7 +59,7 @@ namespace OpenRA.Mods.Common.Traits
public void AddSelectionToControlGroup(int group) public void AddSelectionToControlGroup(int group)
{ {
if (!world.Selection.Actors.Any()) if (world.Selection.Actors.Count == 0)
return; return;
RemoveActorsFromAllControlGroups(world.Selection.Actors); RemoveActorsFromAllControlGroups(world.Selection.Actors);

View File

@@ -94,7 +94,7 @@ namespace OpenRA.Mods.Common.Traits
Actor ignoreActor = null, Actor ignoreActor = null,
bool laneBias = true) bool laneBias = true)
{ {
return FindPathToTarget(self, sources, target, check, customCost, ignoreActor, laneBias); return FindPathToTarget(self, sources.ToList(), target, check, customCost, ignoreActor, laneBias);
} }
/// <summary> /// <summary>
@@ -125,11 +125,14 @@ namespace OpenRA.Mods.Common.Traits
// and calling the existing methods that allow multiple sources and one target. // and calling the existing methods that allow multiple sources and one target.
// However there is a case of asymmetry we must handle, an actor may move out of a inaccessible source, // However there is a case of asymmetry we must handle, an actor may move out of a inaccessible source,
// but may not move onto a inaccessible target. We must account for this when performing the swap. // but may not move onto a inaccessible target. We must account for this when performing the swap.
var targetsList = targets.ToList();
if (targetsList.Count == 0)
return NoPath;
// As targets must be accessible, determine accessible targets in advance so when they becomes the sources // As targets must be accessible, determine accessible targets in advance so when they becomes the sources
// we don't accidentally allow an inaccessible position to become viable. // we don't accidentally allow an inaccessible position to become viable.
var locomotor = GetActorLocomotor(self); var locomotor = GetActorLocomotor(self);
var accessibleTargets = targets var accessibleTargets = targetsList
.Where(target => .Where(target =>
PathSearch.CellAllowsMovement(self.World, locomotor, target, customCost) PathSearch.CellAllowsMovement(self.World, locomotor, target, customCost)
&& locomotor.MovementCostToEnterCell(self, target, check, ignoreActor, true) != PathGraph.MovementCostForUnreachableCell) && locomotor.MovementCostToEnterCell(self, target, check, ignoreActor, true) != PathGraph.MovementCostForUnreachableCell)
@@ -146,7 +149,7 @@ namespace OpenRA.Mods.Common.Traits
if (sourceIsAccessible) if (sourceIsAccessible)
{ {
// As both ends are accessible, we can freely swap them. // As both ends are accessible, we can freely swap them.
path = FindPathToTarget(self, targets, source, check, customCost, ignoreActor, laneBias); path = FindPathToTarget(self, targetsList, source, check, customCost, ignoreActor, laneBias);
} }
else else
{ {
@@ -167,11 +170,10 @@ namespace OpenRA.Mods.Common.Traits
} }
List<CPos> FindPathToTarget( List<CPos> FindPathToTarget(
Actor self, IEnumerable<CPos> sources, CPos target, BlockedByActor check, Actor self, List<CPos> sources, CPos target, BlockedByActor check,
Func<CPos, int> customCost, Actor ignoreActor, bool laneBias) Func<CPos, int> customCost, Actor ignoreActor, bool laneBias)
{ {
var sourcesList = sources.ToList(); if (sources.Count == 0)
if (sourcesList.Count == 0)
return NoPath; return NoPath;
var locomotor = GetActorLocomotor(self); var locomotor = GetActorLocomotor(self);
@@ -183,9 +185,9 @@ namespace OpenRA.Mods.Common.Traits
return NoPath; return NoPath;
// When searching from only one source cell, some optimizations are possible. // When searching from only one source cell, some optimizations are possible.
if (sourcesList.Count == 1) if (sources.Count == 1)
{ {
var source = sourcesList[0]; var source = sources[0];
// For adjacent cells on the same layer, we can return the path without invoking a full search. // For adjacent cells on the same layer, we can return the path without invoking a full search.
if (source.Layer == target.Layer && (source - target).LengthSquared < 3) if (source.Layer == target.Layer && (source - target).LengthSquared < 3)
@@ -204,7 +206,7 @@ namespace OpenRA.Mods.Common.Traits
// Use a hierarchical path search, which performs a guided unidirectional search. // Use a hierarchical path search, which performs a guided unidirectional search.
return GetHierarchicalPathFinder(locomotor, check, ignoreActor).FindPath( return GetHierarchicalPathFinder(locomotor, check, ignoreActor).FindPath(
self, sourcesList, target, check, DefaultHeuristicWeightPercentage, customCost, ignoreActor, laneBias, pathFinderOverlay); self, sources, target, check, DefaultHeuristicWeightPercentage, customCost, ignoreActor, laneBias, pathFinderOverlay);
} }
HierarchicalPathFinder GetHierarchicalPathFinder(Locomotor locomotor, BlockedByActor check, Actor ignoreActor) HierarchicalPathFinder GetHierarchicalPathFinder(Locomotor locomotor, BlockedByActor check, Actor ignoreActor)

View File

@@ -25,7 +25,7 @@ namespace OpenRA.Mods.Common.Traits
public class Selection : ISelection, INotifyCreated, INotifyOwnerChanged, ITick, IGameSaveTraitData public class Selection : ISelection, INotifyCreated, INotifyOwnerChanged, ITick, IGameSaveTraitData
{ {
public int Hash { get; private set; } public int Hash { get; private set; }
public IEnumerable<Actor> Actors => actors; public IReadOnlyCollection<Actor> Actors => actors;
readonly HashSet<Actor> actors = new(); readonly HashSet<Actor> actors = new();
readonly List<Actor> rolloverActors = new(); readonly List<Actor> rolloverActors = new();
@@ -91,10 +91,13 @@ namespace OpenRA.Mods.Common.Traits
public virtual void Combine(World world, IEnumerable<Actor> newSelection, bool isCombine, bool isClick) public virtual void Combine(World world, IEnumerable<Actor> newSelection, bool isCombine, bool isClick)
{ {
var newSelectionCollection = newSelection as IReadOnlyCollection<Actor>;
newSelectionCollection ??= newSelection.ToList();
if (isClick) if (isClick)
{ {
// TODO: select BEST, not FIRST // TODO: select BEST, not FIRST
var adjNewSelection = newSelection.Take(1); var adjNewSelection = newSelectionCollection.Take(1);
if (isCombine) if (isCombine)
actors.SymmetricExceptWith(adjNewSelection); actors.SymmetricExceptWith(adjNewSelection);
else else
@@ -106,17 +109,17 @@ namespace OpenRA.Mods.Common.Traits
else else
{ {
if (isCombine) if (isCombine)
actors.UnionWith(newSelection); actors.UnionWith(newSelectionCollection);
else else
{ {
actors.Clear(); actors.Clear();
actors.UnionWith(newSelection); actors.UnionWith(newSelectionCollection);
} }
} }
UpdateHash(); UpdateHash();
foreach (var a in newSelection) foreach (var a in newSelectionCollection)
foreach (var sel in a.TraitsImplementing<INotifySelected>()) foreach (var sel in a.TraitsImplementing<INotifySelected>())
sel.Selected(a); sel.Selected(a);

View File

@@ -380,9 +380,9 @@ namespace OpenRA.Mods.Common.Traits
(float VMin, float VMax) ValueRange { get; } (float VMin, float VMax) ValueRange { get; }
event Action<Color> OnColorPickerColorUpdate; event Action<Color> OnColorPickerColorUpdate;
Color[] PresetColors { get; } Color[] PresetColors { get; }
Color RandomPresetColor(MersenneTwister random, IEnumerable<Color> terrainColors, IEnumerable<Color> playerColors); Color RandomPresetColor(MersenneTwister random, IReadOnlyCollection<Color> terrainColors, IReadOnlyCollection<Color> playerColors);
Color RandomValidColor(MersenneTwister random, IEnumerable<Color> terrainColors, IEnumerable<Color> playerColors); Color RandomValidColor(MersenneTwister random, IReadOnlyCollection<Color> terrainColors, IReadOnlyCollection<Color> playerColors);
Color MakeValid(Color color, MersenneTwister random, IEnumerable<Color> terrainColors, IEnumerable<Color> playerColors, Action<string> onError = null); Color MakeValid(Color color, MersenneTwister random, IReadOnlyCollection<Color> terrainColors, IReadOnlyCollection<Color> playerColors, Action<string> onError = null);
void ShowColorDropDown(DropDownButtonWidget dropdownButton, Color initialColor, string initialFaction, WorldRenderer worldRenderer, Action<Color> onExit); void ShowColorDropDown(DropDownButtonWidget dropdownButton, Color initialColor, string initialFaction, WorldRenderer worldRenderer, Action<Color> onExit);
} }

View File

@@ -57,7 +57,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
.SelectMany(t => t.Value.RestrictedPlayerColors) .SelectMany(t => t.Value.RestrictedPlayerColors)
.Distinct() .Distinct()
.ToList(); .ToList();
var playerColors = Enumerable.Empty<Color>(); var playerColors = Array.Empty<Color>();
randomButton.OnClick = () => randomButton.OnClick = () =>
{ {
var randomColor = colorManager.RandomValidColor(world.LocalRandom, terrainColors, playerColors); var randomColor = colorManager.RandomValidColor(world.LocalRandom, terrainColors, playerColors);
@@ -140,7 +140,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
var colorIndex = j * paletteCols + i; var colorIndex = j * paletteCols + i;
var newSwatch = (ColorBlockWidget)customColorTemplate.Clone(); var newSwatch = (ColorBlockWidget)customColorTemplate.Clone();
var getColor = new CachedTransform<Color, Color>(c => colorManager.MakeValid(c, world.LocalRandom, Enumerable.Empty<Color>(), Enumerable.Empty<Color>())); var getColor = new CachedTransform<Color, Color>(c => colorManager.MakeValid(c, world.LocalRandom, Array.Empty<Color>(), Array.Empty<Color>()));
newSwatch.GetColor = () => getColor.Update(Game.Settings.Player.CustomColors[colorIndex]); newSwatch.GetColor = () => getColor.Update(Game.Settings.Player.CustomColors[colorIndex]);
newSwatch.IsVisible = () => Game.Settings.Player.CustomColors.Length > colorIndex; newSwatch.IsVisible = () => Game.Settings.Player.CustomColors.Length > colorIndex;

View File

@@ -79,7 +79,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
}; };
} }
IEnumerable<KeyValuePair<ActorInfo, EncyclopediaInfo>> GetFilteredActorEncyclopediaPairs() IReadOnlyCollection<KeyValuePair<ActorInfo, EncyclopediaInfo>> GetFilteredActorEncyclopediaPairs()
{ {
var actors = new List<KeyValuePair<ActorInfo, EncyclopediaInfo>>(); var actors = new List<KeyValuePair<ActorInfo, EncyclopediaInfo>>();
foreach (var actor in modData.DefaultRules.Actors.Values) foreach (var actor in modData.DefaultRules.Actors.Values)
@@ -149,9 +149,11 @@ namespace OpenRA.Mods.Common.Widgets.Logic
var buildable = actor.TraitInfoOrDefault<BuildableInfo>(); var buildable = actor.TraitInfoOrDefault<BuildableInfo>();
if (buildable != null) if (buildable != null)
{ {
var prerequisites = buildable.Prerequisites.Select(a => ActorName(modData.DefaultRules, a)) var prerequisites = buildable.Prerequisites
.Where(s => !s.StartsWith('~') && !s.StartsWith('!')); .Select(a => ActorName(modData.DefaultRules, a))
if (prerequisites.Any()) .Where(s => !s.StartsWith('~') && !s.StartsWith('!'))
.ToList();
if (prerequisites.Count != 0)
text += $"Requires {prerequisites.JoinWith(", ")}\n\n"; text += $"Requires {prerequisites.JoinWith(", ")}\n\n";
} }

View File

@@ -53,7 +53,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic.Ingame
var newSelection = SelectionUtils.SelectActorsOnScreen(world, worldRenderer, null, eligiblePlayers).SubsetWithHighestSelectionPriority(e.Modifiers).ToList(); var newSelection = SelectionUtils.SelectActorsOnScreen(world, worldRenderer, null, eligiblePlayers).SubsetWithHighestSelectionPriority(e.Modifiers).ToList();
// Check if selecting actors on the screen has selected new units // Check if selecting actors on the screen has selected new units
if (newSelection.Count > selection.Actors.Count()) if (newSelection.Count > selection.Actors.Count)
TextNotificationsManager.AddFeedbackLine(SelectedUnitsAcrossScreen, Translation.Arguments("units", newSelection.Count)); TextNotificationsManager.AddFeedbackLine(SelectedUnitsAcrossScreen, Translation.Arguments("units", newSelection.Count));
else else
{ {

View File

@@ -52,7 +52,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic.Ingame
if (world.IsGameOver) if (world.IsGameOver)
return false; return false;
if (!selection.Actors.Any()) if (selection.Actors.Count == 0)
{ {
TextNotificationsManager.AddFeedbackLine(NothingSelected); TextNotificationsManager.AddFeedbackLine(NothingSelected);
Game.Sound.PlayNotification(world.Map.Rules, world.LocalPlayer, "Sounds", ClickDisabledSound, null); Game.Sound.PlayNotification(world.Map.Rules, world.LocalPlayer, "Sounds", ClickDisabledSound, null);
@@ -78,7 +78,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic.Ingame
var newSelection = SelectionUtils.SelectActorsOnScreen(world, worldRenderer, selectedClasses, eligiblePlayers).ToList(); var newSelection = SelectionUtils.SelectActorsOnScreen(world, worldRenderer, selectedClasses, eligiblePlayers).ToList();
// Check if selecting actors on the screen has selected new units // Check if selecting actors on the screen has selected new units
if (newSelection.Count > selection.Actors.Count()) if (newSelection.Count > selection.Actors.Count)
TextNotificationsManager.AddFeedbackLine(SelectedUnitsAcrossScreen, Translation.Arguments("units", newSelection.Count)); TextNotificationsManager.AddFeedbackLine(SelectedUnitsAcrossScreen, Translation.Arguments("units", newSelection.Count));
else else
{ {

View File

@@ -112,9 +112,9 @@ namespace OpenRA.Mods.Common.Widgets.Logic
requiredWidget.IsVisible = () => p.Value.Required; requiredWidget.IsVisible = () => p.Value.Required;
var sourceWidget = container.Get<ImageWidget>("SOURCE"); var sourceWidget = container.Get<ImageWidget>("SOURCE");
var sourceTitles = p.Value.Sources.Select(s => sources[s].Title).Distinct(); var sourceTitles = p.Value.Sources.Select(s => sources[s].Title).Distinct().ToList();
var sourceList = sourceTitles.JoinWith("\n"); var sourceList = sourceTitles.JoinWith("\n");
var isSourceAvailable = sourceTitles.Any(); var isSourceAvailable = sourceTitles.Count != 0;
sourceWidget.GetTooltipText = () => sourceList; sourceWidget.GetTooltipText = () => sourceList;
sourceWidget.IsVisible = () => isSourceAvailable; sourceWidget.IsVisible = () => isSourceAvailable;

View File

@@ -136,9 +136,10 @@ namespace OpenRA.Mods.Common.Widgets.Logic
}) })
.Where(x => x.Index != -1) .Where(x => x.Index != -1)
.OrderBy(x => x.Index) .OrderBy(x => x.Index)
.Select(x => x.Preview); .Select(x => x.Preview)
.ToList();
if (previews.Any()) if (previews.Count != 0)
{ {
CreateMissionGroup(kv.Key, previews, onExit); CreateMissionGroup(kv.Key, previews, onExit);
allPreviews.AddRange(previews); allPreviews.AddRange(previews);
@@ -148,9 +149,12 @@ namespace OpenRA.Mods.Common.Widgets.Logic
// Add an additional group for loose missions // Add an additional group for loose missions
var loosePreviews = modData.MapCache var loosePreviews = modData.MapCache
.Where(p => p.Status == MapStatus.Available && p.Visibility.HasFlag(MapVisibility.MissionSelector) && !allPreviews.Any(a => a.Uid == p.Uid)); .Where(p => p.Status == MapStatus.Available &&
p.Visibility.HasFlag(MapVisibility.MissionSelector) &&
!allPreviews.Any(a => a.Uid == p.Uid))
.ToList();
if (loosePreviews.Any()) if (loosePreviews.Count != 0)
{ {
CreateMissionGroup("Missions", loosePreviews, onExit); CreateMissionGroup("Missions", loosePreviews, onExit);
allPreviews.AddRange(loosePreviews); allPreviews.AddRange(loosePreviews);

View File

@@ -443,7 +443,7 @@ namespace OpenRA.Mods.Common.Widgets
if (facility == null || facility.OccupiesSpace == null) if (facility == null || facility.OccupiesSpace == null)
return true; return true;
if (selection.Actors.Count() == 1 && selection.Contains(facility)) if (selection.Actors.Count == 1 && selection.Contains(facility))
viewport.Center(selection.Actors); viewport.Center(selection.Actors);
else else
selection.Combine(World, new[] { facility }, false, true); selection.Combine(World, new[] { facility }, false, true);

View File

@@ -109,7 +109,7 @@ namespace OpenRA.Mods.Common.Widgets
{ {
if (useClassicMouseStyle && HasMouseFocus) if (useClassicMouseStyle && HasMouseFocus)
{ {
if (!IsValidDragbox && World.Selection.Actors.Any() && !multiClick && uog.InputOverridesSelection(World, mousePos, mi)) if (!IsValidDragbox && World.Selection.Actors.Count != 0 && !multiClick && uog.InputOverridesSelection(World, mousePos, mi))
{ {
// Order units instead of selecting // Order units instead of selecting
ApplyOrders(World, mi); ApplyOrders(World, mi);

View File

@@ -120,7 +120,7 @@ namespace OpenRA.Mods.D2k.Traits
if (pieces < info.Pieces[0]) if (pieces < info.Pieces[0])
pieces = info.Pieces[0]; pieces = info.Pieces[0];
var cells = self.World.Map.FindTilesInAnnulus(self.Location, 1, info.Range); var cells = self.World.Map.FindTilesInAnnulus(self.Location, 1, info.Range).ToList();
for (var i = 0; i < pieces; i++) for (var i = 0; i < pieces; i++)
{ {

View File

@@ -53,7 +53,7 @@ namespace OpenRA.Test
public void PriorityQueueAddThenRemoveTest(int count, int seed) public void PriorityQueueAddThenRemoveTest(int count, int seed)
{ {
var mt = new MersenneTwister(seed); var mt = new MersenneTwister(seed);
var values = Enumerable.Range(0, count); var values = Enumerable.Range(0, count).ToList();
var shuffledValues = values.Shuffle(mt).ToArray(); var shuffledValues = values.Shuffle(mt).ToArray();
var queue = new Primitives.PriorityQueue<int, Int32Comparer>(default); var queue = new Primitives.PriorityQueue<int, Int32Comparer>(default);