Add a Utility class and update command interface.

This commit is contained in:
Paul Chote
2016-08-05 18:25:51 +01:00
parent 510555af5c
commit 45a596953e
36 changed files with 157 additions and 148 deletions

View File

@@ -9,8 +9,21 @@
*/ */
#endregion #endregion
using OpenRA.Traits;
namespace OpenRA namespace OpenRA
{ {
public class Utility
{
public readonly ModData ModData;
public Utility(ModData modData)
{
ModData = modData;
}
}
[RequireExplicitImplementation]
public interface IUtilityCommand public interface IUtilityCommand
{ {
/// <summary> /// <summary>
@@ -20,6 +33,6 @@ namespace OpenRA
bool ValidateArguments(string[] args); bool ValidateArguments(string[] args);
void Run(ModData modData, string[] args); void Run(Utility utility, string[] args);
} }
} }

View File

@@ -24,13 +24,11 @@ namespace OpenRA.Mods.Cnc.UtilityCommands
// NOTE: 64x64 map size is a C&C95 engine limitation // NOTE: 64x64 map size is a C&C95 engine limitation
public ImportTiberianDawnLegacyMapCommand() : base(64) { } public ImportTiberianDawnLegacyMapCommand() : base(64) { }
public string Name { get { return "--import-td-map"; } } string IUtilityCommand.Name { get { return "--import-td-map"; } }
bool IUtilityCommand.ValidateArguments(string[] args) { return ValidateArguments(args); }
[Desc("FILENAME", "Convert a legacy Tiberian Dawn INI/MPR map to the OpenRA format.")] [Desc("FILENAME", "Convert a legacy Tiberian Dawn INI/MPR map to the OpenRA format.")]
public override void Run(ModData modData, string[] args) void IUtilityCommand.Run(Utility utility, string[] args) { Run(utility, args); }
{
base.Run(modData, args);
}
public override void ValidateMapFormat(int format) public override void ValidateMapFormat(int format)
{ {

View File

@@ -17,22 +17,22 @@ namespace OpenRA.Mods.Common.UtilityCommands
{ {
class CheckCodeStyle : IUtilityCommand class CheckCodeStyle : IUtilityCommand
{ {
public string Name { get { return "--check-code-style"; } } string IUtilityCommand.Name { get { return "--check-code-style"; } }
int violationCount; int violationCount;
public bool ValidateArguments(string[] args) bool IUtilityCommand.ValidateArguments(string[] args)
{ {
return args.Length >= 2; return args.Length >= 2;
} }
[Desc("DIRECTORY", "Check the *.cs source code files in a directory for code style violations.")] [Desc("DIRECTORY", "Check the *.cs source code files in a directory for code style violations.")]
public void Run(ModData modData, string[] args) void IUtilityCommand.Run(Utility utility, string[] args)
{ {
var relativePath = args[1]; var relativePath = args[1];
var projectPath = Path.GetFullPath(relativePath); var projectPath = Path.GetFullPath(relativePath);
// HACK: The engine code assumes that Game.modData is set. // HACK: The engine code assumes that Game.modData is set.
Game.ModData = modData; Game.ModData = utility.ModData;
var console = new StyleCopConsole(null, false, null, null, true); var console = new StyleCopConsole(null, false, null, null, true);
var project = new CodeProject(0, projectPath, new Configuration(null)); var project = new CodeProject(0, projectPath, new Configuration(null));

View File

@@ -28,9 +28,9 @@ namespace OpenRA.Mods.Common.UtilityCommands
int violationCount; int violationCount;
[Desc("Check for explicit interface implementation violations in all assemblies referenced by the specified mod.")] [Desc("Check for explicit interface implementation violations in all assemblies referenced by the specified mod.")]
void IUtilityCommand.Run(ModData modData, string[] args) void IUtilityCommand.Run(Utility utility, string[] args)
{ {
var types = modData.ObjectCreator.GetTypes(); var types = utility.ModData.ObjectCreator.GetTypes();
foreach (var implementingType in types.Where(t => !t.IsInterface)) foreach (var implementingType in types.Where(t => !t.IsInterface))
{ {

View File

@@ -17,18 +17,18 @@ namespace OpenRA.Mods.Common.UtilityCommands
{ {
class CheckSquenceSprites : IUtilityCommand class CheckSquenceSprites : IUtilityCommand
{ {
public string Name { get { return "--check-sequence-sprites"; } } string IUtilityCommand.Name { get { return "--check-sequence-sprites"; } }
public bool ValidateArguments(string[] args) bool IUtilityCommand.ValidateArguments(string[] args)
{ {
return true; return true;
} }
[Desc("Check the sequence definitions for missing sprite files.")] [Desc("Check the sequence definitions for missing sprite files.")]
public void Run(ModData modData, string[] args) void IUtilityCommand.Run(Utility utility, string[] args)
{ {
// HACK: The engine code assumes that Game.modData is set. // HACK: The engine code assumes that Game.modData is set.
Game.ModData = modData; var modData = Game.ModData = utility.ModData;
var failed = false; var failed = false;
modData.SpriteSequenceLoader.OnMissingSpriteError = s => { Console.WriteLine("\t" + s); failed = true; }; modData.SpriteSequenceLoader.OnMissingSpriteError = s => { Console.WriteLine("\t" + s); failed = true; };

View File

@@ -18,7 +18,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
{ {
class CheckYaml : IUtilityCommand class CheckYaml : IUtilityCommand
{ {
public string Name { get { return "--check-yaml"; } } string IUtilityCommand.Name { get { return "--check-yaml"; } }
static int errors = 0; static int errors = 0;
@@ -34,16 +34,16 @@ namespace OpenRA.Mods.Common.UtilityCommands
Console.WriteLine("OpenRA.Utility(1,1): Warning: {0}", e); Console.WriteLine("OpenRA.Utility(1,1): Warning: {0}", e);
} }
public bool ValidateArguments(string[] args) bool IUtilityCommand.ValidateArguments(string[] args)
{ {
return true; return true;
} }
[Desc("[MAPFILE]", "Check a mod or map for certain yaml errors.")] [Desc("[MAPFILE]", "Check a mod or map for certain yaml errors.")]
public void Run(ModData modData, string[] args) void IUtilityCommand.Run(Utility utility, string[] args)
{ {
// HACK: The engine code assumes that Game.modData is set. // HACK: The engine code assumes that Game.modData is set.
Game.ModData = modData; var modData = Game.ModData = utility.ModData;
try try
{ {

View File

@@ -23,15 +23,15 @@ namespace OpenRA.Mods.Common.UtilityCommands
{ {
class ConvertPngToShpCommand : IUtilityCommand class ConvertPngToShpCommand : IUtilityCommand
{ {
public string Name { get { return "--shp"; } } string IUtilityCommand.Name { get { return "--shp"; } }
public bool ValidateArguments(string[] args) bool IUtilityCommand.ValidateArguments(string[] args)
{ {
return args.Length >= 2; return args.Length >= 2;
} }
[Desc("PNGFILE [PNGFILE ...]", "Combine a list of PNG images into a SHP")] [Desc("PNGFILE [PNGFILE ...]", "Combine a list of PNG images into a SHP")]
public void Run(ModData modData, string[] args) void IUtilityCommand.Run(Utility utility, string[] args)
{ {
var inputFiles = GlobArgs(args).OrderBy(a => a).ToList(); var inputFiles = GlobArgs(args).OrderBy(a => a).ToList();
var dest = inputFiles[0].Split('-').First() + ".shp"; var dest = inputFiles[0].Split('-').First() + ".shp";

View File

@@ -21,19 +21,19 @@ namespace OpenRA.Mods.Common.UtilityCommands
{ {
class ConvertSpriteToPngCommand : IUtilityCommand class ConvertSpriteToPngCommand : IUtilityCommand
{ {
public string Name { get { return "--png"; } } string IUtilityCommand.Name { get { return "--png"; } }
public bool ValidateArguments(string[] args) bool IUtilityCommand.ValidateArguments(string[] args)
{ {
return args.Length >= 3; return args.Length >= 3;
} }
[Desc("SPRITEFILE PALETTE [--noshadow] [--nopadding]", [Desc("SPRITEFILE PALETTE [--noshadow] [--nopadding]",
"Convert a shp/tmp/R8 to a series of PNGs, optionally removing shadow")] "Convert a shp/tmp/R8 to a series of PNGs, optionally removing shadow")]
public void Run(ModData modData, string[] args) void IUtilityCommand.Run(Utility utility, string[] args)
{ {
// HACK: The engine code assumes that Game.modData is set. // HACK: The engine code assumes that Game.modData is set.
Game.ModData = modData; var modData = Game.ModData = utility.ModData;
var src = args[1]; var src = args[1];
var shadowIndex = new int[] { }; var shadowIndex = new int[] { };

View File

@@ -16,15 +16,15 @@ namespace OpenRA.Mods.Common.UtilityCommands
{ {
class CreateManPage : IUtilityCommand class CreateManPage : IUtilityCommand
{ {
public string Name { get { return "--man-page"; } } string IUtilityCommand.Name { get { return "--man-page"; } }
public bool ValidateArguments(string[] args) bool IUtilityCommand.ValidateArguments(string[] args)
{ {
return true; return true;
} }
[Desc("Create a man page in troff format.")] [Desc("Create a man page in troff format.")]
public void Run(ModData modData, string[] args) void IUtilityCommand.Run(Utility utility, string[] args)
{ {
Console.WriteLine(".TH OPENRA 6"); Console.WriteLine(".TH OPENRA 6");
Console.WriteLine(".SH NAME"); Console.WriteLine(".SH NAME");

View File

@@ -17,21 +17,21 @@ namespace OpenRA.Mods.Common.UtilityCommands
{ {
class ExtractFilesCommand : IUtilityCommand class ExtractFilesCommand : IUtilityCommand
{ {
public string Name { get { return "--extract"; } } string IUtilityCommand.Name { get { return "--extract"; } }
public bool ValidateArguments(string[] args) bool IUtilityCommand.ValidateArguments(string[] args)
{ {
return args.Length >= 2; return args.Length >= 2;
} }
[Desc("Extract files from mod packages to the current directory")] [Desc("Extract files from mod packages to the current directory")]
public void Run(ModData modData, string[] args) void IUtilityCommand.Run(Utility utility, string[] args)
{ {
var files = args.Skip(1); var files = args.Skip(1);
foreach (var f in files) foreach (var f in files)
{ {
var src = modData.DefaultFileSystem.Open(f); var src = utility.ModData.DefaultFileSystem.Open(f);
if (src == null) if (src == null)
throw new InvalidOperationException("File not found: {0}".F(f)); throw new InvalidOperationException("File not found: {0}".F(f));
var data = src.ReadAllBytes(); var data = src.ReadAllBytes();

View File

@@ -18,20 +18,20 @@ namespace OpenRA.Mods.Common.UtilityCommands
{ {
class ExtractLanguageStringsCommand : IUtilityCommand class ExtractLanguageStringsCommand : IUtilityCommand
{ {
public string Name { get { return "--extract-language-strings"; } } string IUtilityCommand.Name { get { return "--extract-language-strings"; } }
public bool ValidateArguments(string[] args) bool IUtilityCommand.ValidateArguments(string[] args)
{ {
return true; return true;
} }
[Desc("Extract translatable strings that are not yet localized and update chrome layout.")] [Desc("Extract translatable strings that are not yet localized and update chrome layout.")]
public void Run(ModData modData, string[] args) void IUtilityCommand.Run(Utility utility, string[] args)
{ {
// HACK: The engine code assumes that Game.modData is set. // HACK: The engine code assumes that Game.modData is set.
Game.ModData = modData; var modData = Game.ModData = utility.ModData;
var types = Game.ModData.ObjectCreator.GetTypes(); var types = modData.ObjectCreator.GetTypes();
var translatableFields = types.SelectMany(t => t.GetFields()) var translatableFields = types.SelectMany(t => t.GetFields())
.Where(f => f.HasAttribute<TranslateAttribute>()).Distinct(); .Where(f => f.HasAttribute<TranslateAttribute>()).Distinct();

View File

@@ -18,18 +18,18 @@ namespace OpenRA.Mods.Common.UtilityCommands
{ {
class ExtractLuaDocsCommand : IUtilityCommand class ExtractLuaDocsCommand : IUtilityCommand
{ {
public string Name { get { return "--lua-docs"; } } string IUtilityCommand.Name { get { return "--lua-docs"; } }
public bool ValidateArguments(string[] args) bool IUtilityCommand.ValidateArguments(string[] args)
{ {
return true; return true;
} }
[Desc("Generate Lua API documentation in MarkDown format.")] [Desc("Generate Lua API documentation in MarkDown format.")]
public void Run(ModData modData, string[] args) void IUtilityCommand.Run(Utility utility, string[] args)
{ {
// HACK: The engine code assumes that Game.modData is set. // HACK: The engine code assumes that Game.modData is set.
Game.ModData = modData; Game.ModData = utility.ModData;
Console.WriteLine("This is an automatically generated listing of the new Lua map scripting API, generated for {0} of OpenRA.", Game.ModData.Manifest.Mod.Version); Console.WriteLine("This is an automatically generated listing of the new Lua map scripting API, generated for {0} of OpenRA.", Game.ModData.Manifest.Mod.Version);
Console.WriteLine(); Console.WriteLine();
@@ -55,7 +55,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
Console.WriteLine("For a basic guide about map scripts see the [`Map Scripting` wiki page](https://github.com/OpenRA/OpenRA/wiki/Map-scripting)."); Console.WriteLine("For a basic guide about map scripts see the [`Map Scripting` wiki page](https://github.com/OpenRA/OpenRA/wiki/Map-scripting).");
Console.WriteLine(); Console.WriteLine();
var tables = Game.ModData.ObjectCreator.GetTypesImplementing<ScriptGlobal>() var tables = utility.ModData.ObjectCreator.GetTypesImplementing<ScriptGlobal>()
.OrderBy(t => t.Name); .OrderBy(t => t.Name);
Console.WriteLine("<h3>Global Tables</h3>"); Console.WriteLine("<h3>Global Tables</h3>");
@@ -77,7 +77,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
Console.WriteLine("<h3>Actor Properties / Commands</h3>"); Console.WriteLine("<h3>Actor Properties / Commands</h3>");
var actorCategories = Game.ModData.ObjectCreator.GetTypesImplementing<ScriptActorProperties>().SelectMany(cg => var actorCategories = utility.ModData.ObjectCreator.GetTypesImplementing<ScriptActorProperties>().SelectMany(cg =>
{ {
var catAttr = cg.GetCustomAttributes<ScriptPropertyGroupAttribute>(false).FirstOrDefault(); var catAttr = cg.GetCustomAttributes<ScriptPropertyGroupAttribute>(false).FirstOrDefault();
var category = catAttr != null ? catAttr.Category : "Unsorted"; var category = catAttr != null ? catAttr.Category : "Unsorted";
@@ -122,7 +122,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
Console.WriteLine("<h3>Player Properties / Commands</h3>"); Console.WriteLine("<h3>Player Properties / Commands</h3>");
var playerCategories = Game.ModData.ObjectCreator.GetTypesImplementing<ScriptPlayerProperties>().SelectMany(cg => var playerCategories = utility.ModData.ObjectCreator.GetTypesImplementing<ScriptPlayerProperties>().SelectMany(cg =>
{ {
var catAttr = cg.GetCustomAttributes<ScriptPropertyGroupAttribute>(false).FirstOrDefault(); var catAttr = cg.GetCustomAttributes<ScriptPropertyGroupAttribute>(false).FirstOrDefault();
var category = catAttr != null ? catAttr.Category : "Unsorted"; var category = catAttr != null ? catAttr.Category : "Unsorted";

View File

@@ -50,9 +50,9 @@ namespace OpenRA.Mods.Common.UtilityCommands
} }
[Desc("MAPFILE", "Merge custom map rules into a form suitable for including in map.yaml.")] [Desc("MAPFILE", "Merge custom map rules into a form suitable for including in map.yaml.")]
void IUtilityCommand.Run(ModData modData, string[] args) void IUtilityCommand.Run(Utility utility, string[] args)
{ {
Game.ModData = modData; var modData = Game.ModData = utility.ModData;
var map = new Map(modData, modData.ModFiles.OpenPackage(args[1], new Folder("."))); var map = new Map(modData, modData.ModFiles.OpenPackage(args[1], new Folder(".")));
MergeAndPrint(map, "Rules", map.RuleDefinitions); MergeAndPrint(map, "Rules", map.RuleDefinitions);

View File

@@ -16,21 +16,21 @@ namespace OpenRA.Mods.Common.UtilityCommands
{ {
class ExtractSettingsDocsCommand : IUtilityCommand class ExtractSettingsDocsCommand : IUtilityCommand
{ {
public string Name { get { return "--settings-docs"; } } string IUtilityCommand.Name { get { return "--settings-docs"; } }
public bool ValidateArguments(string[] args) bool IUtilityCommand.ValidateArguments(string[] args)
{ {
return true; return true;
} }
[Desc("Generate settings documentation in markdown format.")] [Desc("Generate settings documentation in markdown format.")]
public void Run(ModData modData, string[] args) void IUtilityCommand.Run(Utility utility, string[] args)
{ {
Game.ModData = modData; Game.ModData = utility.ModData;
Console.WriteLine( Console.WriteLine(
"This documentation is aimed at server administrators. It displays all settings with default values and description. " + "This documentation is aimed at server administrators. It displays all settings with default values and description. " +
"Please do not edit it directly, but add new `[Desc(\"String\")]` tags to the source code. This file has been " + "Please do not edit it directly, but add new `[Desc(\"String\")]` tags to the source code. This file has been " +
"automatically generated for version {0} of OpenRA.", Game.ModData.Manifest.Mod.Version); "automatically generated for version {0} of OpenRA.", utility.ModData.Manifest.Mod.Version);
Console.WriteLine(); Console.WriteLine();
Console.WriteLine("All settings can be changed by starting the game via a command-line parameter like `Game.Mod=ra`."); Console.WriteLine("All settings can be changed by starting the game via a command-line parameter like `Game.Mod=ra`.");
Console.WriteLine(); Console.WriteLine();

View File

@@ -20,23 +20,23 @@ namespace OpenRA.Mods.Common.UtilityCommands
{ {
class ExtractTraitDocsCommand : IUtilityCommand class ExtractTraitDocsCommand : IUtilityCommand
{ {
public string Name { get { return "--docs"; } } string IUtilityCommand.Name { get { return "--docs"; } }
public bool ValidateArguments(string[] args) bool IUtilityCommand.ValidateArguments(string[] args)
{ {
return true; return true;
} }
[Desc("Generate trait documentation in MarkDown format.")] [Desc("Generate trait documentation in MarkDown format.")]
public void Run(ModData modData, string[] args) void IUtilityCommand.Run(Utility utility, string[] args)
{ {
// HACK: The engine code assumes that Game.modData is set. // HACK: The engine code assumes that Game.modData is set.
Game.ModData = modData; Game.ModData = utility.ModData;
Console.WriteLine( Console.WriteLine(
"This documentation is aimed at modders. It displays all traits with default values and developer commentary. " + "This documentation is aimed at modders. It displays all traits with default values and developer commentary. " +
"Please do not edit it directly, but add new `[Desc(\"String\")]` tags to the source code. This file has been " + "Please do not edit it directly, but add new `[Desc(\"String\")]` tags to the source code. This file has been " +
"automatically generated for version {0} of OpenRA.", Game.ModData.Manifest.Mod.Version); "automatically generated for version {0} of OpenRA.", utility.ModData.Manifest.Mod.Version);
Console.WriteLine(); Console.WriteLine();
var toc = new StringBuilder(); var toc = new StringBuilder();

View File

@@ -20,18 +20,18 @@ namespace OpenRA.Mods.Common.UtilityCommands
{ {
class FixClassicTilesets : IUtilityCommand class FixClassicTilesets : IUtilityCommand
{ {
public string Name { get { return "--fix-classic-tilesets"; } } string IUtilityCommand.Name { get { return "--fix-classic-tilesets"; } }
public bool ValidateArguments(string[] args) bool IUtilityCommand.ValidateArguments(string[] args)
{ {
return args.Length >= 2; return args.Length >= 2;
} }
[Desc("EXTENSIONS", "Fixes missing template tile definitions and adds filename extensions.")] [Desc("EXTENSIONS", "Fixes missing template tile definitions and adds filename extensions.")]
public void Run(ModData modData, string[] args) void IUtilityCommand.Run(Utility utility, string[] args)
{ {
// HACK: The engine code assumes that Game.modData is set. // HACK: The engine code assumes that Game.modData is set.
Game.ModData = modData; var modData = Game.ModData = utility.ModData;
var imageField = typeof(TerrainTemplateInfo).GetField("Image"); var imageField = typeof(TerrainTemplateInfo).GetField("Image");
var pickAnyField = typeof(TerrainTemplateInfo).GetField("PickAny"); var pickAnyField = typeof(TerrainTemplateInfo).GetField("PickAny");

View File

@@ -16,17 +16,17 @@ namespace OpenRA.Mods.Common.UtilityCommands
{ {
class GetMapHashCommand : IUtilityCommand class GetMapHashCommand : IUtilityCommand
{ {
public string Name { get { return "--map-hash"; } } string IUtilityCommand.Name { get { return "--map-hash"; } }
public bool ValidateArguments(string[] args) bool IUtilityCommand.ValidateArguments(string[] args)
{ {
return args.Length >= 2; return args.Length >= 2;
} }
[Desc("MAPFILE", "Generate hash of specified oramap file.")] [Desc("MAPFILE", "Generate hash of specified oramap file.")]
public void Run(ModData modData, string[] args) void IUtilityCommand.Run(Utility utility, string[] args)
{ {
using (var package = modData.ModFiles.OpenPackage(args[1], new Folder("."))) using (var package = utility.ModData.ModFiles.OpenPackage(args[1], new Folder(".")))
Console.WriteLine(Map.ComputeUID(package)); Console.WriteLine(Map.ComputeUID(package));
} }
} }

View File

@@ -38,18 +38,15 @@ namespace OpenRA.Mods.Common.UtilityCommands
bool singlePlayer; bool singlePlayer;
int spawnCount; int spawnCount;
public bool ValidateArguments(string[] args) protected bool ValidateArguments(string[] args)
{ {
return args.Length >= 2; return args.Length >= 2;
} }
[Desc("FILENAME", "Convert a legacy INI/MPR map to the OpenRA format.")] protected void Run(Utility utility, string[] args)
public virtual void Run(ModData modData, string[] args)
{ {
ModData = modData;
// HACK: The engine code assumes that Game.modData is set. // HACK: The engine code assumes that Game.modData is set.
Game.ModData = modData; Game.ModData = ModData = utility.ModData;
var filename = args[1]; var filename = args[1];
using (var stream = File.OpenRead(filename)) using (var stream = File.OpenRead(filename))
@@ -68,16 +65,16 @@ namespace OpenRA.Mods.Common.UtilityCommands
// The original game isn't case sensitive, but we are. // The original game isn't case sensitive, but we are.
var tileset = GetTileset(mapSection).ToUpperInvariant(); var tileset = GetTileset(mapSection).ToUpperInvariant();
if (!modData.DefaultTileSets.ContainsKey(tileset)) if (!ModData.DefaultTileSets.ContainsKey(tileset))
throw new InvalidDataException("Unknown tileset {0}".F(tileset)); throw new InvalidDataException("Unknown tileset {0}".F(tileset));
Map = new Map(modData, modData.DefaultTileSets[tileset], MapSize, MapSize) Map = new Map(ModData, ModData.DefaultTileSets[tileset], MapSize, MapSize)
{ {
Title = basic.GetValue("Name", Path.GetFileNameWithoutExtension(filename)), Title = basic.GetValue("Name", Path.GetFileNameWithoutExtension(filename)),
Author = "Westwood Studios", Author = "Westwood Studios",
}; };
Map.RequiresMod = modData.Manifest.Mod.Id; Map.RequiresMod = ModData.Manifest.Mod.Id;
SetBounds(Map, mapSection); SetBounds(Map, mapSection);

View File

@@ -19,15 +19,15 @@ namespace OpenRA.Mods.Common.UtilityCommands
{ {
class ListInstallShieldCabContentsCommand : IUtilityCommand class ListInstallShieldCabContentsCommand : IUtilityCommand
{ {
public string Name { get { return "--list-installshield-cab"; } } string IUtilityCommand.Name { get { return "--list-installshield-cab"; } }
public bool ValidateArguments(string[] args) bool IUtilityCommand.ValidateArguments(string[] args)
{ {
return args.Length == 2; return args.Length == 2;
} }
[Desc("DATA.HDR", "Lists the filenames contained within an Installshield CAB volume set")] [Desc("DATA.HDR", "Lists the filenames contained within an Installshield CAB volume set")]
public void Run(ModData modData, string[] args) void IUtilityCommand.Run(Utility utility, string[] args)
{ {
using (var file = File.OpenRead(args[1])) using (var file = File.OpenRead(args[1]))
{ {

View File

@@ -18,15 +18,15 @@ namespace OpenRA.Mods.Common.UtilityCommands
{ {
class ListInstallShieldContents : IUtilityCommand class ListInstallShieldContents : IUtilityCommand
{ {
public string Name { get { return "--list-installshield"; } } string IUtilityCommand.Name { get { return "--list-installshield"; } }
public bool ValidateArguments(string[] args) bool IUtilityCommand.ValidateArguments(string[] args)
{ {
return args.Length == 2; return args.Length == 2;
} }
[Desc("ARCHIVE.Z", "Lists the content ranges for a InstallShield V3 file")] [Desc("ARCHIVE.Z", "Lists the content ranges for a InstallShield V3 file")]
public void Run(ModData modData, string[] args) void IUtilityCommand.Run(Utility utility, string[] args)
{ {
var filename = Path.GetFileName(args[1]); var filename = Path.GetFileName(args[1]);
var path = Path.GetDirectoryName(args[1]); var path = Path.GetDirectoryName(args[1]);

View File

@@ -17,15 +17,15 @@ namespace OpenRA.Mods.Common.UtilityCommands
{ {
class ListMSCabContentsCommand : IUtilityCommand class ListMSCabContentsCommand : IUtilityCommand
{ {
public string Name { get { return "--list-mscab"; } } string IUtilityCommand.Name { get { return "--list-mscab"; } }
public bool ValidateArguments(string[] args) bool IUtilityCommand.ValidateArguments(string[] args)
{ {
return args.Length == 2; return args.Length == 2;
} }
[Desc("ARCHIVE.CAB", "Lists the filenames contained within a MSCAB file")] [Desc("ARCHIVE.CAB", "Lists the filenames contained within a MSCAB file")]
public void Run(ModData modData, string[] args) void IUtilityCommand.Run(Utility utility, string[] args)
{ {
var package = new MSCabCompression(File.OpenRead(args[1])); var package = new MSCabCompression(File.OpenRead(args[1]));
foreach (var file in package.Contents) foreach (var file in package.Contents)

View File

@@ -18,15 +18,15 @@ namespace OpenRA.Mods.Common.UtilityCommands
{ {
class ListMixContents : IUtilityCommand class ListMixContents : IUtilityCommand
{ {
public string Name { get { return "--list-mix"; } } string IUtilityCommand.Name { get { return "--list-mix"; } }
public bool ValidateArguments(string[] args) bool IUtilityCommand.ValidateArguments(string[] args)
{ {
return args.Length == 2; return args.Length == 2;
} }
[Desc("ARCHIVE.MIX", "Lists the content ranges for a mix file")] [Desc("ARCHIVE.MIX", "Lists the content ranges for a mix file")]
public void Run(ModData modData, string[] args) void IUtilityCommand.Run(Utility utility, string[] args)
{ {
var filename = Path.GetFileName(args[1]); var filename = Path.GetFileName(args[1]);
var path = Path.GetDirectoryName(args[1]); var path = Path.GetDirectoryName(args[1]);
@@ -34,7 +34,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
var fs = new OpenRA.FileSystem.FileSystem(); var fs = new OpenRA.FileSystem.FileSystem();
// Needed to access the global mix database // Needed to access the global mix database
fs.LoadFromManifest(modData.Manifest); fs.LoadFromManifest(utility.ModData.Manifest);
fs.Mount(path, "parent"); fs.Mount(path, "parent");
var package = new MixFile(fs, "parent|" + filename); var package = new MixFile(fs, "parent|" + filename);

View File

@@ -15,16 +15,17 @@ namespace OpenRA.Mods.Common.UtilityCommands
} }
[Desc("ACTOR-TYPE [PATH/TO/MAP]", "Display the finalized, merged MiniYaml tree for the given actor type. Input values are case-sensitive.")] [Desc("ACTOR-TYPE [PATH/TO/MAP]", "Display the finalized, merged MiniYaml tree for the given actor type. Input values are case-sensitive.")]
void IUtilityCommand.Run(ModData modData, string[] args) void IUtilityCommand.Run(Utility utility, string[] args)
{ {
// HACK: The engine code assumes that Game.modData is set. // HACK: The engine code assumes that Game.modData is set.
Game.ModData = modData; var modData = Game.ModData = utility.ModData;
var actorType = args[1]; var actorType = args[1];
string mapPath = null; string mapPath = null;
Map map = null; Map map = null;
if (args.Length == 3) if (args.Length == 3)
{
try try
{ {
mapPath = args[2]; mapPath = args[2];
@@ -35,6 +36,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
Console.WriteLine("Could not load map '{0}'.", mapPath); Console.WriteLine("Could not load map '{0}'.", mapPath);
Environment.Exit(2); Environment.Exit(2);
} }
}
var fs = map ?? modData.DefaultFileSystem; var fs = map ?? modData.DefaultFileSystem;
var topLevelNodes = MiniYaml.Load(fs, modData.Manifest.Rules, map == null ? null : map.RuleDefinitions); var topLevelNodes = MiniYaml.Load(fs, modData.Manifest.Rules, map == null ? null : map.RuleDefinitions);

View File

@@ -22,15 +22,15 @@ namespace OpenRA.Mods.Common.UtilityCommands
{ {
class RemapShpCommand : IUtilityCommand class RemapShpCommand : IUtilityCommand
{ {
public string Name { get { return "--remap"; } } string IUtilityCommand.Name { get { return "--remap"; } }
public bool ValidateArguments(string[] args) bool IUtilityCommand.ValidateArguments(string[] args)
{ {
return args.Length >= 5; return args.Length >= 5;
} }
[Desc("SRCMOD:PAL DESTMOD:PAL SRCSHP DESTSHP", "Remap SHPs to another palette")] [Desc("SRCMOD:PAL DESTMOD:PAL SRCSHP DESTSHP", "Remap SHPs to another palette")]
public void Run(ModData modData, string[] args) void IUtilityCommand.Run(Utility utility, string[] args)
{ {
var remap = new Dictionary<int, int>(); var remap = new Dictionary<int, int>();

View File

@@ -17,15 +17,15 @@ namespace OpenRA.Mods.Common.UtilityCommands
{ {
class ReplayMetadataCommand : IUtilityCommand class ReplayMetadataCommand : IUtilityCommand
{ {
public string Name { get { return "--replay-metadata"; } } string IUtilityCommand.Name { get { return "--replay-metadata"; } }
public bool ValidateArguments(string[] args) bool IUtilityCommand.ValidateArguments(string[] args)
{ {
return args.Length >= 2; return args.Length >= 2;
} }
[Desc("REPLAYFILE", "Print the game metadata from a replay file.")] [Desc("REPLAYFILE", "Print the game metadata from a replay file.")]
public void Run(ModData modData, string[] args) void IUtilityCommand.Run(Utility utility, string[] args)
{ {
var replay = ReplayMetadata.Read(args[1]); var replay = ReplayMetadata.Read(args[1]);
if (replay == null) if (replay == null)

View File

@@ -18,14 +18,14 @@ namespace OpenRA.Mods.Common.UtilityCommands
{ {
public class ResizeMapCommand : IUtilityCommand public class ResizeMapCommand : IUtilityCommand
{ {
public string Name { get { return "--resize-map"; } } string IUtilityCommand.Name { get { return "--resize-map"; } }
int width; int width;
int height; int height;
Map map; Map map;
public bool ValidateArguments(string[] args) bool IUtilityCommand.ValidateArguments(string[] args)
{ {
if (args.Length < 4) if (args.Length < 4)
return false; return false;
@@ -46,9 +46,9 @@ namespace OpenRA.Mods.Common.UtilityCommands
} }
[Desc("MAPFILE", "WIDTH", "HEIGHT", "Resize the map at the bottom corners.")] [Desc("MAPFILE", "WIDTH", "HEIGHT", "Resize the map at the bottom corners.")]
public void Run(ModData modData, string[] args) void IUtilityCommand.Run(Utility utility, string[] args)
{ {
Game.ModData = modData; var modData = Game.ModData = utility.ModData;
map = new Map(modData, modData.ModFiles.OpenPackage(args[1], new Folder("."))); map = new Map(modData, modData.ModFiles.OpenPackage(args[1], new Folder(".")));
Console.WriteLine("Resizing map {0} from {1} to {2},{3}", map.Title, map.MapSize, width, height); Console.WriteLine("Resizing map {0} from {1} to {2},{3}", map.Title, map.MapSize, width, height);
map.Resize(width, height); map.Resize(width, height);

View File

@@ -15,11 +15,11 @@ namespace OpenRA.Mods.Common.UtilityCommands
{ {
class Rgba2Hex : IUtilityCommand class Rgba2Hex : IUtilityCommand
{ {
public string Name { get { return "--rgba2hex"; } } string IUtilityCommand.Name { get { return "--rgba2hex"; } }
static readonly char[] Comma = new char[] { ',' }; static readonly char[] Comma = new char[] { ',' };
public bool ValidateArguments(string[] args) bool IUtilityCommand.ValidateArguments(string[] args)
{ {
if (args.Length <= 1) if (args.Length <= 1)
return PrintUsage(); return PrintUsage();
@@ -74,7 +74,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
} }
[Desc("Convert r,g,b[,a] triples/quads into hex colors")] [Desc("Convert r,g,b[,a] triples/quads into hex colors")]
public void Run(ModData modData, string[] args) void IUtilityCommand.Run(Utility utility, string[] args)
{ {
for (int i = 1; i < args.Length;) for (int i = 1; i < args.Length;)
{ {
@@ -104,11 +104,11 @@ namespace OpenRA.Mods.Common.UtilityCommands
class Argb2Hex : IUtilityCommand class Argb2Hex : IUtilityCommand
{ {
public string Name { get { return "--argb2hex"; } } string IUtilityCommand.Name { get { return "--argb2hex"; } }
static readonly char[] Comma = new char[] { ',' }; static readonly char[] Comma = new char[] { ',' };
public bool ValidateArguments(string[] args) bool IUtilityCommand.ValidateArguments(string[] args)
{ {
if (args.Length <= 1) if (args.Length <= 1)
return PrintUsage(); return PrintUsage();
@@ -180,7 +180,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
} }
[Desc("Convert a,r,g,b legacy colors into hex colors")] [Desc("Convert a,r,g,b legacy colors into hex colors")]
public void Run(ModData modData, string[] args) void IUtilityCommand.Run(Utility utility, string[] args)
{ {
for (int i = 1; i < args.Length;) for (int i = 1; i < args.Length;)
{ {

View File

@@ -19,9 +19,9 @@ namespace OpenRA.Mods.Common.UtilityCommands
{ {
class UpgradeMapCommand : IUtilityCommand class UpgradeMapCommand : IUtilityCommand
{ {
public string Name { get { return "--upgrade-map"; } } string IUtilityCommand.Name { get { return "--upgrade-map"; } }
public bool ValidateArguments(string[] args) bool IUtilityCommand.ValidateArguments(string[] args)
{ {
return args.Length >= 3; return args.Length >= 3;
} }
@@ -75,10 +75,10 @@ namespace OpenRA.Mods.Common.UtilityCommands
} }
[Desc("MAP", "CURRENTENGINE", "Upgrade map rules to the latest engine version.")] [Desc("MAP", "CURRENTENGINE", "Upgrade map rules to the latest engine version.")]
public void Run(ModData modData, string[] args) void IUtilityCommand.Run(Utility utility, string[] args)
{ {
// HACK: The engine code assumes that Game.modData is set. // HACK: The engine code assumes that Game.modData is set.
Game.ModData = modData; var modData = Game.ModData = utility.ModData;
// HACK: We know that maps can only be oramap or folders, which are ReadWrite // HACK: We know that maps can only be oramap or folders, which are ReadWrite
var package = modData.ModFiles.OpenPackage(args[1], new Folder(".")) as IReadWritePackage; var package = modData.ModFiles.OpenPackage(args[1], new Folder(".")) as IReadWritePackage;

View File

@@ -19,9 +19,9 @@ namespace OpenRA.Mods.Common.UtilityCommands
{ {
class UpgradeModCommand : IUtilityCommand class UpgradeModCommand : IUtilityCommand
{ {
public string Name { get { return "--upgrade-mod"; } } string IUtilityCommand.Name { get { return "--upgrade-mod"; } }
public bool ValidateArguments(string[] args) bool IUtilityCommand.ValidateArguments(string[] args)
{ {
return args.Length >= 2; return args.Length >= 2;
} }
@@ -53,10 +53,10 @@ namespace OpenRA.Mods.Common.UtilityCommands
} }
[Desc("CURRENTENGINE", "Upgrade mod rules to the latest engine version.")] [Desc("CURRENTENGINE", "Upgrade mod rules to the latest engine version.")]
public void Run(ModData modData, string[] args) void IUtilityCommand.Run(Utility utility, string[] args)
{ {
// HACK: The engine code assumes that Game.modData is set. // HACK: The engine code assumes that Game.modData is set.
Game.ModData = modData; var modData = Game.ModData = utility.ModData;
modData.MapCache.LoadMaps(); modData.MapCache.LoadMaps();
var engineDate = Exts.ParseIntegerInvariant(args[1]); var engineDate = Exts.ParseIntegerInvariant(args[1]);

View File

@@ -17,21 +17,21 @@ namespace OpenRA.Mods.D2k.UtilityCommands
{ {
class ImportD2kMapCommand : IUtilityCommand class ImportD2kMapCommand : IUtilityCommand
{ {
public string Name { get { return "--import-d2k-map"; } } string IUtilityCommand.Name { get { return "--import-d2k-map"; } }
public bool ValidateArguments(string[] args) bool IUtilityCommand.ValidateArguments(string[] args)
{ {
return args.Length >= 3; return args.Length >= 3;
} }
[Desc("FILENAME", "TILESET", "Convert a legacy Dune 2000 MAP file to the OpenRA format.")] [Desc("FILENAME", "TILESET", "Convert a legacy Dune 2000 MAP file to the OpenRA format.")]
public void Run(ModData modData, string[] args) void IUtilityCommand.Run(Utility utility, string[] args)
{ {
// HACK: The engine code assumes that Game.modData is set. // HACK: The engine code assumes that Game.modData is set.
Game.ModData = modData; Game.ModData = utility.ModData;
var rules = Ruleset.LoadDefaultsForTileSet(modData, "ARRAKIS"); var rules = Ruleset.LoadDefaultsForTileSet(utility.ModData, "ARRAKIS");
var map = D2kMapImporter.Import(args[1], modData.Manifest.Mod.Id, args[2], rules); var map = D2kMapImporter.Import(args[1], utility.ModData.Manifest.Mod.Id, args[2], rules);
if (map == null) if (map == null)
return; return;

View File

@@ -25,13 +25,11 @@ namespace OpenRA.Mods.RA.UtilityCommands
// TODO: 128x128 is probably not true for "mega maps" from the expansions. // TODO: 128x128 is probably not true for "mega maps" from the expansions.
public ImportRedAlertLegacyMapCommand() : base(128) { } public ImportRedAlertLegacyMapCommand() : base(128) { }
public string Name { get { return "--import-ra-map"; } } string IUtilityCommand.Name { get { return "--import-ra-map"; } }
bool IUtilityCommand.ValidateArguments(string[] args) { return ValidateArguments(args); }
[Desc("FILENAME", "Convert a legacy Red Alert INI/MPR map to the OpenRA format.")] [Desc("FILENAME", "Convert a legacy Red Alert INI/MPR map to the OpenRA format.")]
public override void Run(ModData modData, string[] args) void IUtilityCommand.Run(Utility utility, string[] args) { Run(utility, args); }
{
base.Run(modData, args);
}
public override void ValidateMapFormat(int format) public override void ValidateMapFormat(int format)
{ {

View File

@@ -149,10 +149,10 @@ namespace OpenRA.Mods.TS.UtilityCommands
}; };
[Desc("FILENAME", "Convert a Tiberian Sun map to the OpenRA format.")] [Desc("FILENAME", "Convert a Tiberian Sun map to the OpenRA format.")]
void IUtilityCommand.Run(ModData modData, string[] args) void IUtilityCommand.Run(Utility utility, string[] args)
{ {
// HACK: The engine code assumes that Game.modData is set. // HACK: The engine code assumes that Game.modData is set.
Game.ModData = modData; Game.ModData = utility.ModData;
var filename = args[1]; var filename = args[1];
var file = new IniFile(File.Open(args[1], FileMode.Open)); var file = new IniFile(File.Open(args[1], FileMode.Open));
@@ -163,12 +163,12 @@ namespace OpenRA.Mods.TS.UtilityCommands
var iniBounds = mapSection.GetValue("LocalSize", "0, 0, 0, 0").Split(',').Select(int.Parse).ToArray(); var iniBounds = mapSection.GetValue("LocalSize", "0, 0, 0, 0").Split(',').Select(int.Parse).ToArray();
var size = new Size(iniSize[2], 2 * iniSize[3]); var size = new Size(iniSize[2], 2 * iniSize[3]);
var map = new Map(Game.ModData, modData.DefaultTileSets[tileset], size.Width, size.Height) var map = new Map(Game.ModData, utility.ModData.DefaultTileSets[tileset], size.Width, size.Height)
{ {
Title = basic.GetValue("Name", Path.GetFileNameWithoutExtension(filename)), Title = basic.GetValue("Name", Path.GetFileNameWithoutExtension(filename)),
Author = "Westwood Studios", Author = "Westwood Studios",
Bounds = new Rectangle(iniBounds[0], iniBounds[1], iniBounds[2], 2 * iniBounds[3] + 2 * iniBounds[1]), Bounds = new Rectangle(iniBounds[0], iniBounds[1], iniBounds[2], 2 * iniBounds[3] + 2 * iniBounds[1]),
RequiresMod = modData.Manifest.Mod.Id RequiresMod = utility.ModData.Manifest.Mod.Id
}; };
var fullSize = new int2(iniSize[2], iniSize[3]); var fullSize = new int2(iniSize[2], iniSize[3]);

View File

@@ -20,21 +20,21 @@ namespace OpenRA.Mods.TS.UtilityCommands
{ {
class LegacyRulesImporter : IUtilityCommand class LegacyRulesImporter : IUtilityCommand
{ {
public bool ValidateArguments(string[] args) bool IUtilityCommand.ValidateArguments(string[] args)
{ {
return args.Length >= 3; return args.Length >= 3;
} }
public string Name { get { return "--rules-import"; } } string IUtilityCommand.Name { get { return "--rules-import"; } }
IniFile rulesIni; IniFile rulesIni;
IniFile artIni; IniFile artIni;
[Desc("RULES.INI", "ART.INI", "Convert ART.INI and RULES.INI to the OpenRA rules definition format.")] [Desc("RULES.INI", "ART.INI", "Convert ART.INI and RULES.INI to the OpenRA rules definition format.")]
public void Run(ModData modData, string[] args) void IUtilityCommand.Run(Utility utility, string[] args)
{ {
// HACK: The engine code assumes that Game.modData is set. // HACK: The engine code assumes that Game.modData is set.
Game.ModData = modData; Game.ModData = utility.ModData;
rulesIni = new IniFile(File.Open(args[1], FileMode.Open)); rulesIni = new IniFile(File.Open(args[1], FileMode.Open));
artIni = new IniFile(File.Open(args[2], FileMode.Open)); artIni = new IniFile(File.Open(args[2], FileMode.Open));

View File

@@ -19,21 +19,21 @@ namespace OpenRA.Mods.TS.UtilityCommands
{ {
class ImportLegacySequenceCommand : IUtilityCommand class ImportLegacySequenceCommand : IUtilityCommand
{ {
public bool ValidateArguments(string[] args) bool IUtilityCommand.ValidateArguments(string[] args)
{ {
return args.Length >= 2; return args.Length >= 2;
} }
public string Name { get { return "--sequence-import"; } } string IUtilityCommand.Name { get { return "--sequence-import"; } }
IniFile file; IniFile file;
MapGrid grid; MapGrid grid;
[Desc("FILENAME", "Convert ART.INI to the OpenRA sequence definition format.")] [Desc("FILENAME", "Convert ART.INI to the OpenRA sequence definition format.")]
public void Run(ModData modData, string[] args) void IUtilityCommand.Run(Utility utility, string[] args)
{ {
// HACK: The engine code assumes that Game.modData is set. // HACK: The engine code assumes that Game.modData is set.
Game.ModData = modData; Game.ModData = utility.ModData;
grid = Game.ModData.Manifest.Get<MapGrid>(); grid = Game.ModData.Manifest.Get<MapGrid>();

View File

@@ -20,22 +20,22 @@ namespace OpenRA.Mods.TS.UtilityCommands
{ {
class ImportLegacyTilesetCommand : IUtilityCommand class ImportLegacyTilesetCommand : IUtilityCommand
{ {
public string Name { get { return "--tileset-import"; } } string IUtilityCommand.Name { get { return "--tileset-import"; } }
public bool ValidateArguments(string[] args) bool IUtilityCommand.ValidateArguments(string[] args)
{ {
return args.Length >= 3; return args.Length >= 3;
} }
[Desc("FILENAME", "TEMPLATEEXTENSION", "[TILESETNAME]", "Convert a legacy tileset to the OpenRA format.")] [Desc("FILENAME", "TEMPLATEEXTENSION", "[TILESETNAME]", "Convert a legacy tileset to the OpenRA format.")]
public void Run(ModData modData, string[] args) void IUtilityCommand.Run(Utility utility, string[] args)
{ {
// HACK: The engine code assumes that Game.modData is set. // HACK: The engine code assumes that Game.modData is set.
Game.ModData = modData; var modData = Game.ModData = utility.ModData;
var file = new IniFile(File.Open(args[1], FileMode.Open)); var file = new IniFile(File.Open(args[1], FileMode.Open));
var extension = args[2]; var extension = args[2];
var tileSize = modData.Manifest.Get<MapGrid>().TileSize; var tileSize = utility.ModData.Manifest.Get<MapGrid>().TileSize;
var templateIndex = 0; var templateIndex = 0;

View File

@@ -14,7 +14,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Runtime.Serialization; using System.Runtime.Serialization;
namespace OpenRA.Utility namespace OpenRA
{ {
[Serializable] [Serializable]
public class NoSuchCommandException : Exception public class NoSuchCommandException : Exception
@@ -55,12 +55,13 @@ namespace OpenRA.Utility
Game.InitializeSettings(Arguments.Empty); Game.InitializeSettings(Arguments.Empty);
var modData = new ModData(modName); var modData = new ModData(modName);
var utility = new Utility(modData);
args = args.Skip(1).ToArray(); args = args.Skip(1).ToArray();
var actions = new Dictionary<string, KeyValuePair<Action<ModData, string[]>, Func<string[], bool>>>(); var actions = new Dictionary<string, KeyValuePair<Action<Utility, string[]>, Func<string[], bool>>>();
foreach (var commandType in modData.ObjectCreator.GetTypesImplementing<IUtilityCommand>()) foreach (var commandType in modData.ObjectCreator.GetTypesImplementing<IUtilityCommand>())
{ {
var command = (IUtilityCommand)Activator.CreateInstance(commandType); var command = (IUtilityCommand)Activator.CreateInstance(commandType);
var kvp = new KeyValuePair<Action<ModData, string[]>, Func<string[], bool>>(command.Run, command.ValidateArguments); var kvp = new KeyValuePair<Action<Utility, string[]>, Func<string[], bool>>(command.Run, command.ValidateArguments);
actions.Add(command.Name, kvp); actions.Add(command.Name, kvp);
} }
@@ -81,7 +82,7 @@ namespace OpenRA.Utility
if (validateActionArgs.Invoke(args)) if (validateActionArgs.Invoke(args))
{ {
action.Invoke(modData, args); action.Invoke(utility, args);
} }
else else
{ {
@@ -105,7 +106,7 @@ namespace OpenRA.Utility
} }
} }
static void PrintUsage(IDictionary<string, KeyValuePair<Action<ModData, string[]>, Func<string[], bool>>> actions) static void PrintUsage(IDictionary<string, KeyValuePair<Action<Utility, string[]>, Func<string[], bool>>> actions)
{ {
Console.WriteLine("Run `OpenRA.Utility.exe [MOD]` to see a list of available commands."); Console.WriteLine("Run `OpenRA.Utility.exe [MOD]` to see a list of available commands.");
Console.WriteLine("The available mods are: " + string.Join(", ", ModMetadata.AllMods.Keys)); Console.WriteLine("The available mods are: " + string.Join(", ", ModMetadata.AllMods.Keys));
@@ -122,7 +123,7 @@ namespace OpenRA.Utility
} }
} }
static void GetActionUsage(string key, Action<ModData, string[]> action) static void GetActionUsage(string key, Action<Utility, string[]> action)
{ {
var descParts = action.Method.GetCustomAttributes<DescAttribute>(true) var descParts = action.Method.GetCustomAttributes<DescAttribute>(true)
.SelectMany(d => d.Lines).ToArray(); .SelectMany(d => d.Lines).ToArray();