Rework mod enumeration / caching.
- Replaced ModMetadata.AllMods with Game.Mods. - Store / reference mod Manifest instead of ModMetadata. - Removes engine dependency on ModContent class.
This commit is contained in:
@@ -13,7 +13,6 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
|
||||||
using OpenRA.Primitives;
|
using OpenRA.Primitives;
|
||||||
|
|
||||||
namespace OpenRA.FileSystem
|
namespace OpenRA.FileSystem
|
||||||
@@ -34,9 +33,15 @@ namespace OpenRA.FileSystem
|
|||||||
|
|
||||||
// Mod packages that should not be disposed
|
// Mod packages that should not be disposed
|
||||||
readonly List<IReadOnlyPackage> modPackages = new List<IReadOnlyPackage>();
|
readonly List<IReadOnlyPackage> modPackages = new List<IReadOnlyPackage>();
|
||||||
|
readonly IReadOnlyDictionary<string, Manifest> installedMods;
|
||||||
|
|
||||||
Cache<string, List<IReadOnlyPackage>> fileIndex = new Cache<string, List<IReadOnlyPackage>>(_ => new List<IReadOnlyPackage>());
|
Cache<string, List<IReadOnlyPackage>> fileIndex = new Cache<string, List<IReadOnlyPackage>>(_ => new List<IReadOnlyPackage>());
|
||||||
|
|
||||||
|
public FileSystem(IReadOnlyDictionary<string, Manifest> installedMods)
|
||||||
|
{
|
||||||
|
this.installedMods = installedMods;
|
||||||
|
}
|
||||||
|
|
||||||
public IReadOnlyPackage OpenPackage(string filename)
|
public IReadOnlyPackage OpenPackage(string filename)
|
||||||
{
|
{
|
||||||
if (filename.EndsWith(".mix", StringComparison.InvariantCultureIgnoreCase))
|
if (filename.EndsWith(".mix", StringComparison.InvariantCultureIgnoreCase))
|
||||||
@@ -108,9 +113,9 @@ namespace OpenRA.FileSystem
|
|||||||
{
|
{
|
||||||
name = name.Substring(1);
|
name = name.Substring(1);
|
||||||
|
|
||||||
ModMetadata mod;
|
Manifest mod;
|
||||||
if (!ModMetadata.AllMods.TryGetValue(name, out mod))
|
if (!installedMods.TryGetValue(name, out mod))
|
||||||
throw new InvalidOperationException("Could not load mod '{0}'. Available mods: {1}".F(name, ModMetadata.AllMods.Keys.JoinWith(", ")));
|
throw new InvalidOperationException("Could not load mod '{0}'. Available mods: {1}".F(name, installedMods.Keys.JoinWith(", ")));
|
||||||
|
|
||||||
package = mod.Package;
|
package = mod.Package;
|
||||||
modPackages.Add(package);
|
modPackages.Add(package);
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ using System.Reflection;
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using OpenRA.Chat;
|
using OpenRA.Chat;
|
||||||
|
using OpenRA.FileSystem;
|
||||||
using OpenRA.Graphics;
|
using OpenRA.Graphics;
|
||||||
using OpenRA.Network;
|
using OpenRA.Network;
|
||||||
using OpenRA.Primitives;
|
using OpenRA.Primitives;
|
||||||
@@ -35,6 +36,8 @@ namespace OpenRA
|
|||||||
public const int Timestep = 40;
|
public const int Timestep = 40;
|
||||||
public const int TimestepJankThreshold = 250; // Don't catch up for delays larger than 250ms
|
public const int TimestepJankThreshold = 250; // Don't catch up for delays larger than 250ms
|
||||||
|
|
||||||
|
public static InstalledMods Mods { get; private set; }
|
||||||
|
|
||||||
public static ModData ModData;
|
public static ModData ModData;
|
||||||
public static Settings Settings;
|
public static Settings Settings;
|
||||||
public static ICursor Cursor;
|
public static ICursor Cursor;
|
||||||
@@ -300,22 +303,23 @@ namespace OpenRA
|
|||||||
|
|
||||||
GlobalChat = new GlobalChat();
|
GlobalChat = new GlobalChat();
|
||||||
|
|
||||||
|
Mods = new InstalledMods();
|
||||||
Console.WriteLine("Available mods:");
|
Console.WriteLine("Available mods:");
|
||||||
foreach (var mod in ModMetadata.AllMods)
|
foreach (var mod in Mods)
|
||||||
Console.WriteLine("\t{0}: {1} ({2})", mod.Key, mod.Value.Title, mod.Value.Version);
|
Console.WriteLine("\t{0}: {1} ({2})", mod.Key, mod.Value.Mod.Title, mod.Value.Mod.Version);
|
||||||
|
|
||||||
InitializeMod(Settings.Game.Mod, args);
|
InitializeMod(Settings.Game.Mod, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsModInstalled(string modId)
|
public static bool IsModInstalled(string modId)
|
||||||
{
|
{
|
||||||
return ModMetadata.AllMods[modId].RequiresMods.All(IsModInstalled);
|
return Mods.ContainsKey(modId) && Mods[modId].RequiresMods.All(IsModInstalled);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsModInstalled(KeyValuePair<string, string> mod)
|
public static bool IsModInstalled(KeyValuePair<string, string> mod)
|
||||||
{
|
{
|
||||||
return ModMetadata.AllMods.ContainsKey(mod.Key)
|
return Mods.ContainsKey(mod.Key)
|
||||||
&& ModMetadata.AllMods[mod.Key].Version == mod.Value
|
&& Mods[mod.Key].Mod.Version == mod.Value
|
||||||
&& IsModInstalled(mod.Key);
|
&& IsModInstalled(mod.Key);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -347,7 +351,7 @@ namespace OpenRA
|
|||||||
ModData = null;
|
ModData = null;
|
||||||
|
|
||||||
// Fall back to default if the mod doesn't exist or has missing prerequisites.
|
// Fall back to default if the mod doesn't exist or has missing prerequisites.
|
||||||
if (!ModMetadata.AllMods.ContainsKey(mod) || !IsModInstalled(mod))
|
if (!IsModInstalled(mod))
|
||||||
mod = new GameSettings().Mod;
|
mod = new GameSettings().Mod;
|
||||||
|
|
||||||
Console.WriteLine("Loading mod: {0}", mod);
|
Console.WriteLine("Loading mod: {0}", mod);
|
||||||
@@ -355,7 +359,7 @@ namespace OpenRA
|
|||||||
|
|
||||||
Sound.StopVideo();
|
Sound.StopVideo();
|
||||||
|
|
||||||
ModData = new ModData(mod, true);
|
ModData = new ModData(Mods[mod], Mods, true);
|
||||||
|
|
||||||
using (new PerfTimer("LoadMaps"))
|
using (new PerfTimer("LoadMaps"))
|
||||||
ModData.MapCache.LoadMaps();
|
ModData.MapCache.LoadMaps();
|
||||||
@@ -468,7 +472,7 @@ namespace OpenRA
|
|||||||
ThreadPool.QueueUserWorkItem(_ =>
|
ThreadPool.QueueUserWorkItem(_ =>
|
||||||
{
|
{
|
||||||
var mod = ModData.Manifest.Mod;
|
var mod = ModData.Manifest.Mod;
|
||||||
var directory = Platform.ResolvePath("^", "Screenshots", mod.Id, mod.Version);
|
var directory = Platform.ResolvePath("^", "Screenshots", ModData.Manifest.Id, mod.Version);
|
||||||
Directory.CreateDirectory(directory);
|
Directory.CreateDirectory(directory);
|
||||||
|
|
||||||
var filename = TimestampedFilename();
|
var filename = TimestampedFilename();
|
||||||
|
|||||||
@@ -16,10 +16,12 @@ namespace OpenRA
|
|||||||
public class Utility
|
public class Utility
|
||||||
{
|
{
|
||||||
public readonly ModData ModData;
|
public readonly ModData ModData;
|
||||||
|
public readonly InstalledMods Mods;
|
||||||
|
|
||||||
public Utility(ModData modData)
|
public Utility(ModData modData, InstalledMods mods)
|
||||||
{
|
{
|
||||||
ModData = modData;
|
ModData = modData;
|
||||||
|
Mods = mods;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
117
OpenRA.Game/InstalledMods.cs
Normal file
117
OpenRA.Game/InstalledMods.cs
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
#region Copyright & License Information
|
||||||
|
/*
|
||||||
|
* Copyright 2007-2016 The OpenRA Developers (see AUTHORS)
|
||||||
|
* This file is part of OpenRA, which is free software. It is made
|
||||||
|
* available to you under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation, either version 3 of
|
||||||
|
* the License, or (at your option) any later version. For more
|
||||||
|
* information, see COPYING.
|
||||||
|
*/
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using OpenRA.FileSystem;
|
||||||
|
using OpenRA.Primitives;
|
||||||
|
|
||||||
|
namespace OpenRA
|
||||||
|
{
|
||||||
|
public class InstalledMods : IReadOnlyDictionary<string, Manifest>
|
||||||
|
{
|
||||||
|
readonly Dictionary<string, Manifest> mods;
|
||||||
|
|
||||||
|
public InstalledMods()
|
||||||
|
{
|
||||||
|
mods = GetInstalledMods();
|
||||||
|
}
|
||||||
|
|
||||||
|
static IEnumerable<Pair<string, string>> GetCandidateMods()
|
||||||
|
{
|
||||||
|
// Get mods that are in the game folder.
|
||||||
|
var basePath = Platform.ResolvePath(Path.Combine(".", "mods"));
|
||||||
|
var mods = Directory.GetDirectories(basePath)
|
||||||
|
.Select(x => Pair.New(x.Substring(basePath.Length + 1), x))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
foreach (var m in Directory.GetFiles(basePath, "*.oramod"))
|
||||||
|
mods.Add(Pair.New(Path.GetFileNameWithoutExtension(m), m));
|
||||||
|
|
||||||
|
// Get mods that are in the support folder.
|
||||||
|
var supportPath = Platform.ResolvePath(Path.Combine("^", "mods"));
|
||||||
|
if (!Directory.Exists(supportPath))
|
||||||
|
return mods;
|
||||||
|
|
||||||
|
foreach (var pair in Directory.GetDirectories(supportPath).ToDictionary(x => x.Substring(supportPath.Length + 1)))
|
||||||
|
mods.Add(Pair.New(pair.Key, pair.Value));
|
||||||
|
|
||||||
|
foreach (var m in Directory.GetFiles(supportPath, "*.oramod"))
|
||||||
|
mods.Add(Pair.New(Path.GetFileNameWithoutExtension(m), m));
|
||||||
|
|
||||||
|
return mods;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Manifest LoadMod(string id, string path)
|
||||||
|
{
|
||||||
|
IReadOnlyPackage package = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (Directory.Exists(path))
|
||||||
|
package = new Folder(path);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var fileStream = File.OpenRead(path))
|
||||||
|
package = new ZipFile(fileStream, path);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
throw new InvalidDataException(path + " is not a valid mod package");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!package.Contains("mod.yaml"))
|
||||||
|
throw new InvalidDataException(path + " is not a valid mod package");
|
||||||
|
|
||||||
|
// Mods in the support directory and oramod packages (which are listed later
|
||||||
|
// in the CandidateMods list) override mods in the main install.
|
||||||
|
return new Manifest(id, package);
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
if (package != null)
|
||||||
|
package.Dispose();
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Dictionary<string, Manifest> GetInstalledMods()
|
||||||
|
{
|
||||||
|
var ret = new Dictionary<string, Manifest>();
|
||||||
|
foreach (var pair in GetCandidateMods())
|
||||||
|
{
|
||||||
|
var mod = LoadMod(pair.First, pair.Second);
|
||||||
|
|
||||||
|
// Mods in the support directory and oramod packages (which are listed later
|
||||||
|
// in the CandidateMods list) override mods in the main install.
|
||||||
|
if (mod != null)
|
||||||
|
ret[pair.First] = mod;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Manifest this[string key] { get { return mods[key]; } }
|
||||||
|
public int Count { get { return mods.Count; } }
|
||||||
|
public ICollection<string> Keys { get { return mods.Keys; } }
|
||||||
|
public ICollection<Manifest> Values { get { return mods.Values; } }
|
||||||
|
public bool ContainsKey(string key) { return mods.ContainsKey(key); }
|
||||||
|
public IEnumerator<KeyValuePair<string, Manifest>> GetEnumerator() { return mods.GetEnumerator(); }
|
||||||
|
public bool TryGetValue(string key, out Manifest value) { return mods.TryGetValue(key, out value); }
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() { return mods.GetEnumerator(); }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -34,6 +34,8 @@ namespace OpenRA
|
|||||||
/// <summary> Describes what is to be loaded in order to run a mod. </summary>
|
/// <summary> Describes what is to be loaded in order to run a mod. </summary>
|
||||||
public class Manifest
|
public class Manifest
|
||||||
{
|
{
|
||||||
|
public readonly string Id;
|
||||||
|
public readonly IReadOnlyPackage Package;
|
||||||
public readonly ModMetadata Mod;
|
public readonly ModMetadata Mod;
|
||||||
public readonly string[]
|
public readonly string[]
|
||||||
Rules, ServerTraits,
|
Rules, ServerTraits,
|
||||||
@@ -60,14 +62,15 @@ namespace OpenRA
|
|||||||
readonly TypeDictionary modules = new TypeDictionary();
|
readonly TypeDictionary modules = new TypeDictionary();
|
||||||
readonly Dictionary<string, MiniYaml> yaml;
|
readonly Dictionary<string, MiniYaml> yaml;
|
||||||
|
|
||||||
public Manifest(string modId)
|
bool customDataLoaded;
|
||||||
{
|
|
||||||
var package = ModMetadata.AllMods[modId].Package;
|
|
||||||
|
|
||||||
|
public Manifest(string modId, IReadOnlyPackage package)
|
||||||
|
{
|
||||||
|
Id = modId;
|
||||||
|
Package = package;
|
||||||
yaml = new MiniYaml(null, MiniYaml.FromStream(package.GetStream("mod.yaml"), "mod.yaml")).ToDictionary();
|
yaml = new MiniYaml(null, MiniYaml.FromStream(package.GetStream("mod.yaml"), "mod.yaml")).ToDictionary();
|
||||||
|
|
||||||
Mod = FieldLoader.Load<ModMetadata>(yaml["Metadata"]);
|
Mod = FieldLoader.Load<ModMetadata>(yaml["Metadata"]);
|
||||||
Mod.Id = modId;
|
|
||||||
|
|
||||||
// TODO: Use fieldloader
|
// TODO: Use fieldloader
|
||||||
MapFolders = YamlDictionary(yaml, "MapFolders");
|
MapFolders = YamlDictionary(yaml, "MapFolders");
|
||||||
@@ -106,7 +109,7 @@ namespace OpenRA
|
|||||||
RequiresMods = yaml["RequiresMods"].ToDictionary(my => my.Value);
|
RequiresMods = yaml["RequiresMods"].ToDictionary(my => my.Value);
|
||||||
|
|
||||||
// Allow inherited mods to import parent maps.
|
// Allow inherited mods to import parent maps.
|
||||||
var compat = new List<string> { Mod.Id };
|
var compat = new List<string> { Id };
|
||||||
|
|
||||||
if (yaml.ContainsKey("SupportsMapsFrom"))
|
if (yaml.ContainsKey("SupportsMapsFrom"))
|
||||||
compat.AddRange(yaml["SupportsMapsFrom"].Value.Split(',').Select(c => c.Trim()));
|
compat.AddRange(yaml["SupportsMapsFrom"].Value.Split(',').Select(c => c.Trim()));
|
||||||
@@ -147,6 +150,8 @@ namespace OpenRA
|
|||||||
|
|
||||||
modules.Add(module);
|
modules.Add(module);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
customDataLoaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static string[] YamlList(Dictionary<string, MiniYaml> yaml, string key, bool parsePaths = false)
|
static string[] YamlList(Dictionary<string, MiniYaml> yaml, string key, bool parsePaths = false)
|
||||||
@@ -171,8 +176,12 @@ namespace OpenRA
|
|||||||
return modules.Contains<T>();
|
return modules.Contains<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>Load a cached IGlobalModData instance.</summary>
|
||||||
public T Get<T>() where T : IGlobalModData
|
public T Get<T>() where T : IGlobalModData
|
||||||
{
|
{
|
||||||
|
if (!customDataLoaded)
|
||||||
|
throw new InvalidOperationException("Attempted to call Manifest.Get() before loading custom data!");
|
||||||
|
|
||||||
var module = modules.GetOrDefault<T>();
|
var module = modules.GetOrDefault<T>();
|
||||||
|
|
||||||
// Lazily create the default values if not explicitly defined.
|
// Lazily create the default values if not explicitly defined.
|
||||||
@@ -184,5 +193,36 @@ namespace OpenRA
|
|||||||
|
|
||||||
return module;
|
return module;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Load an uncached IGlobalModData instance directly from the manifest yaml.
|
||||||
|
/// This should only be used by external mods that want to query data from this mod.
|
||||||
|
/// </summary>
|
||||||
|
public T Get<T>(ObjectCreator oc) where T : IGlobalModData
|
||||||
|
{
|
||||||
|
MiniYaml data;
|
||||||
|
var t = typeof(T);
|
||||||
|
if (!yaml.TryGetValue(t.Name, out data))
|
||||||
|
{
|
||||||
|
// Lazily create the default values if not explicitly defined.
|
||||||
|
return (T)oc.CreateBasic(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
IGlobalModData module;
|
||||||
|
var ctor = t.GetConstructor(new[] { typeof(MiniYaml) });
|
||||||
|
if (ctor != null)
|
||||||
|
{
|
||||||
|
// Class has opted-in to DIY initialization
|
||||||
|
module = (IGlobalModData)ctor.Invoke(new object[] { data.Value });
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Automatically load the child nodes using FieldLoader
|
||||||
|
module = oc.CreateObject<IGlobalModData>(t.Name);
|
||||||
|
FieldLoader.Load(module, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (T)module;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ namespace OpenRA
|
|||||||
public ILoadScreen LoadScreen { get; private set; }
|
public ILoadScreen LoadScreen { get; private set; }
|
||||||
public VoxelLoader VoxelLoader { get; private set; }
|
public VoxelLoader VoxelLoader { get; private set; }
|
||||||
public CursorProvider CursorProvider { get; private set; }
|
public CursorProvider CursorProvider { get; private set; }
|
||||||
public FS ModFiles = new FS();
|
public FS ModFiles;
|
||||||
public IReadOnlyFileSystem DefaultFileSystem { get { return ModFiles; } }
|
public IReadOnlyFileSystem DefaultFileSystem { get { return ModFiles; } }
|
||||||
|
|
||||||
readonly Lazy<Ruleset> defaultRules;
|
readonly Lazy<Ruleset> defaultRules;
|
||||||
@@ -45,10 +45,14 @@ namespace OpenRA
|
|||||||
readonly Lazy<IReadOnlyDictionary<string, SequenceProvider>> defaultSequences;
|
readonly Lazy<IReadOnlyDictionary<string, SequenceProvider>> defaultSequences;
|
||||||
public IReadOnlyDictionary<string, SequenceProvider> DefaultSequences { get { return defaultSequences.Value; } }
|
public IReadOnlyDictionary<string, SequenceProvider> DefaultSequences { get { return defaultSequences.Value; } }
|
||||||
|
|
||||||
public ModData(string mod, bool useLoadScreen = false)
|
public ModData(Manifest mod, InstalledMods mods, bool useLoadScreen = false)
|
||||||
{
|
{
|
||||||
Languages = new string[0];
|
Languages = new string[0];
|
||||||
Manifest = new Manifest(mod);
|
|
||||||
|
ModFiles = new FS(mods);
|
||||||
|
|
||||||
|
// Take a local copy of the manifest
|
||||||
|
Manifest = new Manifest(mod.Id, mod.Package);
|
||||||
ModFiles.LoadFromManifest(Manifest);
|
ModFiles.LoadFromManifest(Manifest);
|
||||||
|
|
||||||
ObjectCreator = new ObjectCreator(Manifest, ModFiles);
|
ObjectCreator = new ObjectCreator(Manifest, ModFiles);
|
||||||
|
|||||||
@@ -9,118 +9,14 @@
|
|||||||
*/
|
*/
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using OpenRA.FileSystem;
|
|
||||||
using OpenRA.Primitives;
|
|
||||||
|
|
||||||
namespace OpenRA
|
namespace OpenRA
|
||||||
{
|
{
|
||||||
public class ModMetadata
|
public class ModMetadata
|
||||||
{
|
{
|
||||||
public static readonly Dictionary<string, ModMetadata> AllMods = ValidateMods();
|
|
||||||
|
|
||||||
public string Id;
|
|
||||||
public string Title;
|
public string Title;
|
||||||
public string Description;
|
public string Description;
|
||||||
public string Version;
|
public string Version;
|
||||||
public string Author;
|
public string Author;
|
||||||
public bool Hidden;
|
public bool Hidden;
|
||||||
|
|
||||||
public Dictionary<string, string> RequiresMods;
|
|
||||||
public ModContent ModContent;
|
|
||||||
public IReadOnlyPackage Package;
|
|
||||||
|
|
||||||
static Dictionary<string, ModMetadata> ValidateMods()
|
|
||||||
{
|
|
||||||
var ret = new Dictionary<string, ModMetadata>();
|
|
||||||
foreach (var pair in GetCandidateMods())
|
|
||||||
{
|
|
||||||
IReadOnlyPackage package = null;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (Directory.Exists(pair.Second))
|
|
||||||
package = new Folder(pair.Second);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (var fileStream = File.OpenRead(pair.Second))
|
|
||||||
package = new ZipFile(fileStream, pair.Second);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
throw new InvalidDataException(pair.Second + " is not a valid mod package");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!package.Contains("mod.yaml"))
|
|
||||||
{
|
|
||||||
package.Dispose();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var yaml = new MiniYaml(null, MiniYaml.FromStream(package.GetStream("mod.yaml"), "mod.yaml"));
|
|
||||||
var nd = yaml.ToDictionary();
|
|
||||||
if (!nd.ContainsKey("Metadata"))
|
|
||||||
{
|
|
||||||
package.Dispose();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var metadata = FieldLoader.Load<ModMetadata>(nd["Metadata"]);
|
|
||||||
metadata.Id = pair.First;
|
|
||||||
metadata.Package = package;
|
|
||||||
|
|
||||||
if (nd.ContainsKey("RequiresMods"))
|
|
||||||
metadata.RequiresMods = nd["RequiresMods"].ToDictionary(my => my.Value);
|
|
||||||
else
|
|
||||||
metadata.RequiresMods = new Dictionary<string, string>();
|
|
||||||
|
|
||||||
if (nd.ContainsKey("ModContent"))
|
|
||||||
metadata.ModContent = FieldLoader.Load<ModContent>(nd["ModContent"]);
|
|
||||||
|
|
||||||
// Mods in the support directory and oramod packages (which are listed later
|
|
||||||
// in the CandidateMods list) override mods in the main install.
|
|
||||||
ret[pair.First] = metadata;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
if (package != null)
|
|
||||||
package.Dispose();
|
|
||||||
Console.WriteLine("An exception occurred when trying to load ModMetadata for `{0}`:".F(pair.First));
|
|
||||||
Console.WriteLine(ex.Message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static IEnumerable<Pair<string, string>> GetCandidateMods()
|
|
||||||
{
|
|
||||||
// Get mods that are in the game folder.
|
|
||||||
var basePath = Platform.ResolvePath(Path.Combine(".", "mods"));
|
|
||||||
var mods = Directory.GetDirectories(basePath)
|
|
||||||
.Select(x => Pair.New(x.Substring(basePath.Length + 1), x))
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
foreach (var m in Directory.GetFiles(basePath, "*.oramod"))
|
|
||||||
mods.Add(Pair.New(Path.GetFileNameWithoutExtension(m), m));
|
|
||||||
|
|
||||||
// Get mods that are in the support folder.
|
|
||||||
var supportPath = Platform.ResolvePath(Path.Combine("^", "mods"));
|
|
||||||
if (!Directory.Exists(supportPath))
|
|
||||||
return mods;
|
|
||||||
|
|
||||||
foreach (var pair in Directory.GetDirectories(supportPath).ToDictionary(x => x.Substring(supportPath.Length + 1)))
|
|
||||||
mods.Add(Pair.New(pair.Key, pair.Value));
|
|
||||||
|
|
||||||
foreach (var m in Directory.GetFiles(supportPath, "*.oramod"))
|
|
||||||
mods.Add(Pair.New(Path.GetFileNameWithoutExtension(m), m));
|
|
||||||
|
|
||||||
return mods;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,14 +38,14 @@ namespace OpenRA.Network
|
|||||||
{
|
{
|
||||||
FieldLoader.Load(this, yaml);
|
FieldLoader.Load(this, yaml);
|
||||||
|
|
||||||
ModMetadata mod;
|
Manifest mod;
|
||||||
var modVersion = Mods.Split('@');
|
var modVersion = Mods.Split('@');
|
||||||
if (modVersion.Length == 2 && ModMetadata.AllMods.TryGetValue(modVersion[0], out mod))
|
if (modVersion.Length == 2 && Game.Mods.TryGetValue(modVersion[0], out mod))
|
||||||
{
|
{
|
||||||
ModId = modVersion[0];
|
ModId = modVersion[0];
|
||||||
ModVersion = modVersion[1];
|
ModVersion = modVersion[1];
|
||||||
ModLabel = "{0} ({1})".F(mod.Title, modVersion[1]);
|
ModLabel = "{0} ({1})".F(mod.Mod.Title, modVersion[1]);
|
||||||
IsCompatible = Game.Settings.Debug.IgnoreVersionMismatch || ModVersion == mod.Version;
|
IsCompatible = Game.Settings.Debug.IgnoreVersionMismatch || ModVersion == mod.Mod.Version;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
ModLabel = "Unknown mod: {0}".F(Mods);
|
ModLabel = "Unknown mod: {0}".F(Mods);
|
||||||
|
|||||||
@@ -44,8 +44,8 @@ namespace OpenRA.Network
|
|||||||
void StartSavingReplay(byte[] initialContent)
|
void StartSavingReplay(byte[] initialContent)
|
||||||
{
|
{
|
||||||
var filename = chooseFilename();
|
var filename = chooseFilename();
|
||||||
var mod = Game.ModData.Manifest.Mod;
|
var mod = Game.ModData.Manifest;
|
||||||
var dir = Platform.ResolvePath("^", "Replays", mod.Id, mod.Version);
|
var dir = Platform.ResolvePath("^", "Replays", mod.Id, mod.Mod.Version);
|
||||||
|
|
||||||
if (!Directory.Exists(dir))
|
if (!Directory.Exists(dir))
|
||||||
Directory.CreateDirectory(dir);
|
Directory.CreateDirectory(dir);
|
||||||
|
|||||||
@@ -132,13 +132,13 @@ namespace OpenRA.Network
|
|||||||
case "HandshakeRequest":
|
case "HandshakeRequest":
|
||||||
{
|
{
|
||||||
// Switch to the server's mod if we need and are able to
|
// Switch to the server's mod if we need and are able to
|
||||||
var mod = Game.ModData.Manifest.Mod;
|
var mod = Game.ModData.Manifest;
|
||||||
var request = HandshakeRequest.Deserialize(order.TargetString);
|
var request = HandshakeRequest.Deserialize(order.TargetString);
|
||||||
|
|
||||||
ModMetadata serverMod;
|
Manifest serverMod;
|
||||||
if (request.Mod != mod.Id &&
|
if (request.Mod != mod.Id &&
|
||||||
ModMetadata.AllMods.TryGetValue(request.Mod, out serverMod) &&
|
Game.Mods.TryGetValue(request.Mod, out serverMod) &&
|
||||||
serverMod.Version == request.Version)
|
serverMod.Mod.Version == request.Version)
|
||||||
{
|
{
|
||||||
var replay = orderManager.Connection as ReplayConnection;
|
var replay = orderManager.Connection as ReplayConnection;
|
||||||
var launchCommand = replay != null ?
|
var launchCommand = replay != null ?
|
||||||
@@ -170,7 +170,7 @@ namespace OpenRA.Network
|
|||||||
{
|
{
|
||||||
Client = info,
|
Client = info,
|
||||||
Mod = mod.Id,
|
Mod = mod.Id,
|
||||||
Version = mod.Version,
|
Version = mod.Mod.Version,
|
||||||
Password = orderManager.Password
|
Password = orderManager.Password
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -245,6 +245,7 @@
|
|||||||
<Compile Include="FileSystem\ZipFolder.cs" />
|
<Compile Include="FileSystem\ZipFolder.cs" />
|
||||||
<Compile Include="Primitives\float3.cs" />
|
<Compile Include="Primitives\float3.cs" />
|
||||||
<Compile Include="ModContent.cs" />
|
<Compile Include="ModContent.cs" />
|
||||||
|
<Compile Include="InstalledMods.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="FileSystem\D2kSoundResources.cs" />
|
<Compile Include="FileSystem\D2kSoundResources.cs" />
|
||||||
|
|||||||
@@ -158,7 +158,7 @@ namespace OpenRA.Server
|
|||||||
foreach (var t in serverTraits.WithInterface<INotifyServerStart>())
|
foreach (var t in serverTraits.WithInterface<INotifyServerStart>())
|
||||||
t.ServerStarted(this);
|
t.ServerStarted(this);
|
||||||
|
|
||||||
Log.Write("server", "Initial mod: {0}", ModData.Manifest.Mod.Id);
|
Log.Write("server", "Initial mod: {0}", ModData.Manifest.Id);
|
||||||
Log.Write("server", "Initial map: {0}", LobbyInfo.GlobalSettings.Map);
|
Log.Write("server", "Initial map: {0}", LobbyInfo.GlobalSettings.Map);
|
||||||
|
|
||||||
var timeout = serverTraits.WithInterface<ITick>().Min(t => t.TickTimeout);
|
var timeout = serverTraits.WithInterface<ITick>().Min(t => t.TickTimeout);
|
||||||
@@ -262,7 +262,7 @@ namespace OpenRA.Server
|
|||||||
// Dispatch a handshake order
|
// Dispatch a handshake order
|
||||||
var request = new HandshakeRequest
|
var request = new HandshakeRequest
|
||||||
{
|
{
|
||||||
Mod = ModData.Manifest.Mod.Id,
|
Mod = ModData.Manifest.Id,
|
||||||
Version = ModData.Manifest.Mod.Version,
|
Version = ModData.Manifest.Mod.Version,
|
||||||
Map = LobbyInfo.GlobalSettings.Map
|
Map = LobbyInfo.GlobalSettings.Map
|
||||||
};
|
};
|
||||||
@@ -327,7 +327,7 @@ namespace OpenRA.Server
|
|||||||
else
|
else
|
||||||
client.Color = HSLColor.FromRGB(255, 255, 255);
|
client.Color = HSLColor.FromRGB(255, 255, 255);
|
||||||
|
|
||||||
if (ModData.Manifest.Mod.Id != handshake.Mod)
|
if (ModData.Manifest.Id != handshake.Mod)
|
||||||
{
|
{
|
||||||
Log.Write("server", "Rejected connection from {0}; mods do not match.",
|
Log.Write("server", "Rejected connection from {0}; mods do not match.",
|
||||||
newConn.Socket.RemoteEndPoint);
|
newConn.Socket.RemoteEndPoint);
|
||||||
|
|||||||
@@ -176,7 +176,7 @@ namespace OpenRA
|
|||||||
|
|
||||||
gameInfo = new GameInformation
|
gameInfo = new GameInformation
|
||||||
{
|
{
|
||||||
Mod = Game.ModData.Manifest.Mod.Id,
|
Mod = Game.ModData.Manifest.Id,
|
||||||
Version = Game.ModData.Manifest.Mod.Version,
|
Version = Game.ModData.Manifest.Mod.Version,
|
||||||
|
|
||||||
MapUid = Map.Uid,
|
MapUid = Map.Uid,
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ namespace OpenRA.Mods.Common.LoadScreens
|
|||||||
if (replayMeta != null)
|
if (replayMeta != null)
|
||||||
{
|
{
|
||||||
var mod = replayMeta.GameInfo.Mod;
|
var mod = replayMeta.GameInfo.Mod;
|
||||||
if (mod != null && mod != Game.ModData.Manifest.Mod.Id && ModMetadata.AllMods.ContainsKey(mod))
|
if (mod != null && mod != Game.ModData.Manifest.Id && Game.Mods.ContainsKey(mod))
|
||||||
Game.InitializeMod(mod, args);
|
Game.InitializeMod(mod, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ namespace OpenRA.Mods.Common.Server
|
|||||||
lastPing = Game.RunTime;
|
lastPing = Game.RunTime;
|
||||||
isBusy = true;
|
isBusy = true;
|
||||||
|
|
||||||
var mod = server.ModData.Manifest.Mod;
|
var mod = server.ModData.Manifest;
|
||||||
|
|
||||||
// important to grab these on the main server thread, not in the worker we're about to spawn -- they may be modified
|
// important to grab these on the main server thread, not in the worker we're about to spawn -- they may be modified
|
||||||
// by the main thread as clients join and leave.
|
// by the main thread as clients join and leave.
|
||||||
@@ -79,7 +79,7 @@ namespace OpenRA.Mods.Common.Server
|
|||||||
(int)server.State,
|
(int)server.State,
|
||||||
numPlayers,
|
numPlayers,
|
||||||
numBots,
|
numBots,
|
||||||
"{0}@{1}".F(mod.Id, mod.Version),
|
"{0}@{1}".F(mod.Id, mod.Mod.Version),
|
||||||
server.LobbyInfo.GlobalSettings.Map,
|
server.LobbyInfo.GlobalSettings.Map,
|
||||||
numSlots,
|
numSlots,
|
||||||
numSpectators,
|
numSpectators,
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
|||||||
Author = "Westwood Studios",
|
Author = "Westwood Studios",
|
||||||
};
|
};
|
||||||
|
|
||||||
Map.RequiresMod = ModData.Manifest.Mod.Id;
|
Map.RequiresMod = ModData.Manifest.Id;
|
||||||
|
|
||||||
SetBounds(Map, mapSection);
|
SetBounds(Map, mapSection);
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
|
||||||
using OpenRA.FileSystem;
|
using OpenRA.FileSystem;
|
||||||
|
|
||||||
namespace OpenRA.Mods.Common.UtilityCommands
|
namespace OpenRA.Mods.Common.UtilityCommands
|
||||||
@@ -31,7 +30,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
|||||||
var filename = Path.GetFileName(args[1]);
|
var filename = Path.GetFileName(args[1]);
|
||||||
var path = Path.GetDirectoryName(args[1]);
|
var path = Path.GetDirectoryName(args[1]);
|
||||||
|
|
||||||
var fs = new OpenRA.FileSystem.FileSystem();
|
var fs = new FileSystem.FileSystem(utility.Mods);
|
||||||
fs.Mount(path, "parent");
|
fs.Mount(path, "parent");
|
||||||
var package = new InstallShieldPackage(fs, "parent|" + filename);
|
var package = new InstallShieldPackage(fs, "parent|" + filename);
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
|||||||
var filename = Path.GetFileName(args[1]);
|
var filename = Path.GetFileName(args[1]);
|
||||||
var path = Path.GetDirectoryName(args[1]);
|
var path = Path.GetDirectoryName(args[1]);
|
||||||
|
|
||||||
var fs = new OpenRA.FileSystem.FileSystem();
|
var fs = new FileSystem.FileSystem(utility.Mods);
|
||||||
|
|
||||||
// Needed to access the global mix database
|
// Needed to access the global mix database
|
||||||
fs.LoadFromManifest(utility.ModData.Manifest);
|
fs.LoadFromManifest(utility.ModData.Manifest);
|
||||||
|
|||||||
@@ -39,14 +39,14 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
|||||||
remap[i] = i;
|
remap[i] = i;
|
||||||
|
|
||||||
var srcMod = args[1].Split(':')[0];
|
var srcMod = args[1].Split(':')[0];
|
||||||
var srcModData = new ModData(srcMod);
|
var srcModData = new ModData(utility.Mods[srcMod], utility.Mods);
|
||||||
Game.ModData = srcModData;
|
Game.ModData = srcModData;
|
||||||
|
|
||||||
var srcPaletteInfo = srcModData.DefaultRules.Actors["player"].TraitInfo<PlayerColorPaletteInfo>();
|
var srcPaletteInfo = srcModData.DefaultRules.Actors["player"].TraitInfo<PlayerColorPaletteInfo>();
|
||||||
var srcRemapIndex = srcPaletteInfo.RemapIndex;
|
var srcRemapIndex = srcPaletteInfo.RemapIndex;
|
||||||
|
|
||||||
var destMod = args[2].Split(':')[0];
|
var destMod = args[2].Split(':')[0];
|
||||||
var destModData = new ModData(destMod);
|
var destModData = new ModData(utility.Mods[destMod], utility.Mods);
|
||||||
Game.ModData = destModData;
|
Game.ModData = destModData;
|
||||||
var destPaletteInfo = destModData.DefaultRules.Actors["player"].TraitInfo<PlayerColorPaletteInfo>();
|
var destPaletteInfo = destModData.DefaultRules.Actors["player"].TraitInfo<PlayerColorPaletteInfo>();
|
||||||
var destRemapIndex = destPaletteInfo.RemapIndex;
|
var destRemapIndex = destPaletteInfo.RemapIndex;
|
||||||
|
|||||||
@@ -346,7 +346,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
|||||||
{
|
{
|
||||||
foreach (var node in nodes)
|
foreach (var node in nodes)
|
||||||
{
|
{
|
||||||
if (engineVersion < 20160730 && modData.Manifest.Mod.Id == "d2k" && depth == 2)
|
if (engineVersion < 20160730 && modData.Manifest.Id == "d2k" && depth == 2)
|
||||||
{
|
{
|
||||||
if (node.Key == "Start")
|
if (node.Key == "Start")
|
||||||
node.Value.Value = RemapD2k106Sequence(FieldLoader.GetValue<int>("", node.Value.Value)).ToString();
|
node.Value.Value = RemapD2k106Sequence(FieldLoader.GetValue<int>("", node.Value.Value)).ToString();
|
||||||
@@ -416,7 +416,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
|||||||
foreach (var node in nodes)
|
foreach (var node in nodes)
|
||||||
{
|
{
|
||||||
// Fix RA building footprints to not use _ when it's not necessary
|
// Fix RA building footprints to not use _ when it's not necessary
|
||||||
if (engineVersion < 20160619 && modData.Manifest.Mod.Id == "ra" && depth == 1)
|
if (engineVersion < 20160619 && modData.Manifest.Id == "ra" && depth == 1)
|
||||||
{
|
{
|
||||||
var buildings = new List<string>() { "tsla", "gap", "agun", "apwr", "fapw" };
|
var buildings = new List<string>() { "tsla", "gap", "agun", "apwr", "fapw" };
|
||||||
if (buildings.Contains(parent.Value.Value) && node.Key == "Location")
|
if (buildings.Contains(parent.Value.Value) && node.Key == "Location")
|
||||||
@@ -424,7 +424,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fix TD building footprints to not use _ when it's not necessary
|
// Fix TD building footprints to not use _ when it's not necessary
|
||||||
if (engineVersion < 20160619 && modData.Manifest.Mod.Id == "cnc" && depth == 1)
|
if (engineVersion < 20160619 && modData.Manifest.Id == "cnc" && depth == 1)
|
||||||
{
|
{
|
||||||
var buildings = new List<string>() { "atwr", "obli", "tmpl", "weap", "hand" };
|
var buildings = new List<string>() { "atwr", "obli", "tmpl", "weap", "hand" };
|
||||||
if (buildings.Contains(parent.Value.Value) && node.Key == "Location")
|
if (buildings.Contains(parent.Value.Value) && node.Key == "Location")
|
||||||
|
|||||||
@@ -165,7 +165,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
if (playerDefinitions != null)
|
if (playerDefinitions != null)
|
||||||
map.PlayerDefinitions = playerDefinitions;
|
map.PlayerDefinitions = playerDefinitions;
|
||||||
|
|
||||||
map.RequiresMod = modData.Manifest.Mod.Id;
|
map.RequiresMod = modData.Manifest.Id;
|
||||||
|
|
||||||
var combinedPath = Platform.ResolvePath(Path.Combine(selectedDirectory.Folder.Name, filename.Text + fileTypes[fileType].Extension));
|
var combinedPath = Platform.ResolvePath(Path.Combine(selectedDirectory.Folder.Name, filename.Text + fileTypes[fileType].Extension));
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
{
|
{
|
||||||
var panel = widget.Get("INSTALL_MOD_PANEL");
|
var panel = widget.Get("INSTALL_MOD_PANEL");
|
||||||
|
|
||||||
var mods = ModMetadata.AllMods[modId].RequiresMods.Where(m => !Game.IsModInstalled(m)).Select(m => "{0} ({1})".F(m.Key, m.Value));
|
var mods = Game.Mods[modId].RequiresMods.Where(m => !Game.IsModInstalled(m)).Select(m => "{0} ({1})".F(m.Key, m.Value));
|
||||||
var text = string.Join(", ", mods);
|
var text = string.Join(", ", mods);
|
||||||
panel.Get<LabelWidget>("MOD_LIST").Text = text;
|
panel.Get<LabelWidget>("MOD_LIST").Text = text;
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using OpenRA.Widgets;
|
using OpenRA.Widgets;
|
||||||
|
|
||||||
@@ -24,11 +23,12 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
bool discAvailable;
|
bool discAvailable;
|
||||||
|
|
||||||
[ObjectCreator.UseCtor]
|
[ObjectCreator.UseCtor]
|
||||||
public ModContentLogic(Widget widget, string modId, Action onCancel)
|
public ModContentLogic(Widget widget, Manifest mod, ModContent content, Action onCancel)
|
||||||
{
|
{
|
||||||
|
this.content = content;
|
||||||
|
|
||||||
var panel = widget.Get("CONTENT_PANEL");
|
var panel = widget.Get("CONTENT_PANEL");
|
||||||
|
|
||||||
content = ModMetadata.AllMods[modId].ModContent;
|
|
||||||
scrollPanel = panel.Get<ScrollPanelWidget>("PACKAGES");
|
scrollPanel = panel.Get<ScrollPanelWidget>("PACKAGES");
|
||||||
template = scrollPanel.Get<ContainerWidget>("PACKAGE_TEMPLATE");
|
template = scrollPanel.Get<ContainerWidget>("PACKAGE_TEMPLATE");
|
||||||
|
|
||||||
|
|||||||
@@ -17,13 +17,10 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
public class ModContentPromptLogic : ChromeLogic
|
public class ModContentPromptLogic : ChromeLogic
|
||||||
{
|
{
|
||||||
[ObjectCreator.UseCtor]
|
[ObjectCreator.UseCtor]
|
||||||
public ModContentPromptLogic(Widget widget, string modId, Action continueLoading)
|
public ModContentPromptLogic(Widget widget, Manifest mod, ModContent content, Action continueLoading)
|
||||||
{
|
{
|
||||||
var panel = widget.Get("CONTENT_PROMPT_PANEL");
|
var panel = widget.Get("CONTENT_PROMPT_PANEL");
|
||||||
|
|
||||||
var mod = ModMetadata.AllMods[modId];
|
|
||||||
var content = ModMetadata.AllMods[modId].ModContent;
|
|
||||||
|
|
||||||
var headerTemplate = panel.Get<LabelWidget>("HEADER_TEMPLATE");
|
var headerTemplate = panel.Get<LabelWidget>("HEADER_TEMPLATE");
|
||||||
var headerLines = !string.IsNullOrEmpty(content.InstallPromptMessage) ? content.InstallPromptMessage.Replace("\\n", "\n").Split('\n') : new string[0];
|
var headerLines = !string.IsNullOrEmpty(content.InstallPromptMessage) ? content.InstallPromptMessage.Replace("\\n", "\n").Split('\n') : new string[0];
|
||||||
var headerHeight = 0;
|
var headerHeight = 0;
|
||||||
@@ -46,7 +43,8 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
{
|
{
|
||||||
Ui.OpenWindow("CONTENT_PANEL", new WidgetArgs
|
Ui.OpenWindow("CONTENT_PANEL", new WidgetArgs
|
||||||
{
|
{
|
||||||
{ "modId", modId },
|
{ "mod", mod },
|
||||||
|
{ "content", content },
|
||||||
{ "onCancel", Ui.CloseWindow }
|
{ "onCancel", Ui.CloseWindow }
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
// so we can't do this inside the input handler.
|
// so we can't do this inside the input handler.
|
||||||
Game.RunAfterTick(() =>
|
Game.RunAfterTick(() =>
|
||||||
{
|
{
|
||||||
Game.Settings.Game.PreviousMod = modData.Manifest.Mod.Id;
|
Game.Settings.Game.PreviousMod = modData.Manifest.Id;
|
||||||
Game.InitializeMod("modchooser", null);
|
Game.InitializeMod("modchooser", null);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -283,8 +283,8 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
{
|
{
|
||||||
// Send the mod and engine version to support version-filtered news (update prompts)
|
// Send the mod and engine version to support version-filtered news (update prompts)
|
||||||
var newsURL = Game.Settings.Game.NewsUrl + "?version={0}&mod={1}&modversion={2}".F(
|
var newsURL = Game.Settings.Game.NewsUrl + "?version={0}&mod={1}&modversion={2}".F(
|
||||||
Uri.EscapeUriString(ModMetadata.AllMods["modchooser"].Version),
|
Uri.EscapeUriString(Game.Mods["modchooser"].Mod.Version),
|
||||||
Uri.EscapeUriString(Game.ModData.Manifest.Mod.Id),
|
Uri.EscapeUriString(Game.ModData.Manifest.Id),
|
||||||
Uri.EscapeUriString(Game.ModData.Manifest.Mod.Version));
|
Uri.EscapeUriString(Game.ModData.Manifest.Mod.Version));
|
||||||
|
|
||||||
// Append system profile data if the player has opted in
|
// Append system profile data if the player has opted in
|
||||||
|
|||||||
@@ -24,32 +24,39 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
{
|
{
|
||||||
readonly Widget modList;
|
readonly Widget modList;
|
||||||
readonly ButtonWidget modTemplate;
|
readonly ButtonWidget modTemplate;
|
||||||
readonly ModMetadata[] allMods;
|
readonly Manifest[] allMods;
|
||||||
readonly Dictionary<string, Sprite> previews = new Dictionary<string, Sprite>();
|
readonly Dictionary<string, Sprite> previews = new Dictionary<string, Sprite>();
|
||||||
readonly Dictionary<string, Sprite> logos = new Dictionary<string, Sprite>();
|
readonly Dictionary<string, Sprite> logos = new Dictionary<string, Sprite>();
|
||||||
|
readonly Cache<Manifest, ModContent> content = new Cache<Manifest, ModContent>(LoadModContent);
|
||||||
|
|
||||||
readonly Widget modChooserPanel;
|
readonly Widget modChooserPanel;
|
||||||
readonly ButtonWidget loadButton;
|
readonly ButtonWidget loadButton;
|
||||||
readonly SheetBuilder sheetBuilder;
|
readonly SheetBuilder sheetBuilder;
|
||||||
ModMetadata selectedMod;
|
Manifest selectedMod;
|
||||||
string selectedAuthor;
|
string selectedAuthor;
|
||||||
string selectedDescription;
|
string selectedDescription;
|
||||||
int modOffset = 0;
|
int modOffset = 0;
|
||||||
|
|
||||||
|
static ModContent LoadModContent(Manifest mod)
|
||||||
|
{
|
||||||
|
return mod.Get<ModContent>(Game.ModData.ObjectCreator);
|
||||||
|
}
|
||||||
|
|
||||||
[ObjectCreator.UseCtor]
|
[ObjectCreator.UseCtor]
|
||||||
public ModBrowserLogic(Widget widget, ModData modData)
|
public ModBrowserLogic(Widget widget, ModData modData)
|
||||||
{
|
{
|
||||||
modChooserPanel = widget;
|
modChooserPanel = widget;
|
||||||
loadButton = modChooserPanel.Get<ButtonWidget>("LOAD_BUTTON");
|
loadButton = modChooserPanel.Get<ButtonWidget>("LOAD_BUTTON");
|
||||||
loadButton.OnClick = () => LoadMod(selectedMod);
|
loadButton.OnClick = () => LoadMod(selectedMod);
|
||||||
loadButton.IsDisabled = () => selectedMod.Id == modData.Manifest.Mod.Id;
|
loadButton.IsDisabled = () => selectedMod.Id == modData.Manifest.Id;
|
||||||
|
|
||||||
var contentButton = modChooserPanel.Get<ButtonWidget>("CONFIGURE_BUTTON");
|
var contentButton = modChooserPanel.Get<ButtonWidget>("CONFIGURE_BUTTON");
|
||||||
contentButton.IsDisabled = () => selectedMod.ModContent == null;
|
|
||||||
contentButton.OnClick = () =>
|
contentButton.OnClick = () =>
|
||||||
{
|
{
|
||||||
var widgetArgs = new WidgetArgs
|
var widgetArgs = new WidgetArgs
|
||||||
{
|
{
|
||||||
{ "modId", selectedMod.Id },
|
{ "mod", selectedMod },
|
||||||
|
{ "content", content[selectedMod] },
|
||||||
{ "onCancel", () => { } }
|
{ "onCancel", () => { } }
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -62,9 +69,9 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
modTemplate = modList.Get<ButtonWidget>("MOD_TEMPLATE");
|
modTemplate = modList.Get<ButtonWidget>("MOD_TEMPLATE");
|
||||||
|
|
||||||
modChooserPanel.Get<LabelWidget>("MOD_DESC").GetText = () => selectedDescription;
|
modChooserPanel.Get<LabelWidget>("MOD_DESC").GetText = () => selectedDescription;
|
||||||
modChooserPanel.Get<LabelWidget>("MOD_TITLE").GetText = () => selectedMod.Title;
|
modChooserPanel.Get<LabelWidget>("MOD_TITLE").GetText = () => selectedMod.Mod.Title;
|
||||||
modChooserPanel.Get<LabelWidget>("MOD_AUTHOR").GetText = () => selectedAuthor;
|
modChooserPanel.Get<LabelWidget>("MOD_AUTHOR").GetText = () => selectedAuthor;
|
||||||
modChooserPanel.Get<LabelWidget>("MOD_VERSION").GetText = () => selectedMod.Version;
|
modChooserPanel.Get<LabelWidget>("MOD_VERSION").GetText = () => selectedMod.Mod.Version;
|
||||||
|
|
||||||
var prevMod = modChooserPanel.Get<ButtonWidget>("PREV_MOD");
|
var prevMod = modChooserPanel.Get<ButtonWidget>("PREV_MOD");
|
||||||
prevMod.OnClick = () => { modOffset -= 1; RebuildModList(); };
|
prevMod.OnClick = () => { modOffset -= 1; RebuildModList(); };
|
||||||
@@ -82,8 +89,8 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
};
|
};
|
||||||
|
|
||||||
sheetBuilder = new SheetBuilder(SheetType.BGRA);
|
sheetBuilder = new SheetBuilder(SheetType.BGRA);
|
||||||
allMods = ModMetadata.AllMods.Values.Where(m => !m.Hidden)
|
allMods = Game.Mods.Values.Where(m => !m.Mod.Hidden)
|
||||||
.OrderBy(m => m.Title)
|
.OrderBy(m => m.Mod.Title)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
// Load preview images, and eat any errors
|
// Load preview images, and eat any errors
|
||||||
@@ -91,7 +98,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using (var stream = ModMetadata.AllMods[mod.Id].Package.GetStream("preview.png"))
|
using (var stream = mod.Package.GetStream("preview.png"))
|
||||||
using (var preview = new Bitmap(stream))
|
using (var preview = new Bitmap(stream))
|
||||||
if (preview.Width == 296 && preview.Height == 196)
|
if (preview.Width == 296 && preview.Height == 196)
|
||||||
previews.Add(mod.Id, sheetBuilder.Add(preview));
|
previews.Add(mod.Id, sheetBuilder.Add(preview));
|
||||||
@@ -100,7 +107,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using (var stream = ModMetadata.AllMods[mod.Id].Package.GetStream("logo.png"))
|
using (var stream = mod.Package.GetStream("logo.png"))
|
||||||
using (var logo = new Bitmap(stream))
|
using (var logo = new Bitmap(stream))
|
||||||
if (logo.Width == 96 && logo.Height == 96)
|
if (logo.Width == 96 && logo.Height == 96)
|
||||||
logos.Add(mod.Id, sheetBuilder.Add(logo));
|
logos.Add(mod.Id, sheetBuilder.Add(logo));
|
||||||
@@ -108,9 +115,9 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
catch (Exception) { }
|
catch (Exception) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
ModMetadata initialMod;
|
Manifest initialMod;
|
||||||
ModMetadata.AllMods.TryGetValue(Game.Settings.Game.PreviousMod, out initialMod);
|
Game.Mods.TryGetValue(Game.Settings.Game.PreviousMod, out initialMod);
|
||||||
SelectMod(initialMod != null && initialMod.Id != "modchooser" ? initialMod : ModMetadata.AllMods["ra"]);
|
SelectMod(initialMod != null && initialMod.Id != "modchooser" ? initialMod : Game.Mods["ra"]);
|
||||||
|
|
||||||
RebuildModList();
|
RebuildModList();
|
||||||
}
|
}
|
||||||
@@ -146,7 +153,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
SelectMod(mod);
|
SelectMod(mod);
|
||||||
};
|
};
|
||||||
|
|
||||||
item.TooltipText = mod.Title;
|
item.TooltipText = mod.Mod.Title;
|
||||||
|
|
||||||
if (j < 9)
|
if (j < 9)
|
||||||
item.Key = new Hotkey((Keycode)((int)Keycode.NUMBER_1 + j), Modifiers.None);
|
item.Key = new Hotkey((Keycode)((int)Keycode.NUMBER_1 + j), Modifiers.None);
|
||||||
@@ -160,23 +167,25 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SelectMod(ModMetadata mod)
|
void SelectMod(Manifest mod)
|
||||||
{
|
{
|
||||||
selectedMod = mod;
|
selectedMod = mod;
|
||||||
selectedAuthor = "By " + (mod.Author ?? "unknown author");
|
selectedAuthor = "By " + (mod.Mod.Author ?? "unknown author");
|
||||||
selectedDescription = (mod.Description ?? "").Replace("\\n", "\n");
|
selectedDescription = (mod.Mod.Description ?? "").Replace("\\n", "\n");
|
||||||
var selectedIndex = Array.IndexOf(allMods, mod);
|
var selectedIndex = Array.IndexOf(allMods, mod);
|
||||||
if (selectedIndex - modOffset > 4)
|
if (selectedIndex - modOffset > 4)
|
||||||
modOffset = selectedIndex - 4;
|
modOffset = selectedIndex - 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoadMod(ModMetadata mod)
|
void LoadMod(Manifest mod)
|
||||||
{
|
{
|
||||||
if (!Game.IsModInstalled(mod.Id))
|
var modId = mod.Id;
|
||||||
|
if (!Game.IsModInstalled(modId))
|
||||||
{
|
{
|
||||||
var widgetArgs = new WidgetArgs
|
var widgetArgs = new WidgetArgs
|
||||||
{
|
{
|
||||||
{ "modId", mod.Id }
|
{ "mod", selectedMod },
|
||||||
|
{ "content", content[selectedMod] },
|
||||||
};
|
};
|
||||||
|
|
||||||
Ui.OpenWindow("INSTALL_MOD_PANEL", widgetArgs);
|
Ui.OpenWindow("INSTALL_MOD_PANEL", widgetArgs);
|
||||||
@@ -188,8 +197,9 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
var widgetArgs = new WidgetArgs
|
var widgetArgs = new WidgetArgs
|
||||||
{
|
{
|
||||||
{ "continueLoading", () =>
|
{ "continueLoading", () =>
|
||||||
Game.RunAfterTick(() => Game.InitializeMod(mod.Id, new Arguments())) },
|
Game.RunAfterTick(() => Game.InitializeMod(modId, new Arguments())) },
|
||||||
{ "modId", mod.Id }
|
{ "mod", selectedMod },
|
||||||
|
{ "content", content[selectedMod] },
|
||||||
};
|
};
|
||||||
|
|
||||||
Ui.OpenWindow("CONTENT_PROMPT_PANEL", widgetArgs);
|
Ui.OpenWindow("CONTENT_PROMPT_PANEL", widgetArgs);
|
||||||
@@ -201,13 +211,13 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
{
|
{
|
||||||
Ui.CloseWindow();
|
Ui.CloseWindow();
|
||||||
sheetBuilder.Dispose();
|
sheetBuilder.Dispose();
|
||||||
Game.InitializeMod(mod.Id, null);
|
Game.InitializeMod(modId, null);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool IsModInstalled(ModMetadata mod)
|
bool IsModInstalled(Manifest mod)
|
||||||
{
|
{
|
||||||
return mod.ModContent.Packages
|
return content[mod].Packages
|
||||||
.Where(p => p.Value.Required)
|
.Where(p => p.Value.Required)
|
||||||
.All(p => p.Value.TestFiles.All(f => File.Exists(Platform.ResolvePath(f))));
|
.All(p => p.Value.TestFiles.All(f => File.Exists(Platform.ResolvePath(f))));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -316,8 +316,8 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
};
|
};
|
||||||
|
|
||||||
var queryURL = Game.Settings.Server.MasterServer + "games?version={0}&mod={1}&modversion={2}".F(
|
var queryURL = Game.Settings.Server.MasterServer + "games?version={0}&mod={1}&modversion={2}".F(
|
||||||
Uri.EscapeUriString(ModMetadata.AllMods["modchooser"].Version),
|
Uri.EscapeUriString(Game.Mods["modchooser"].Mod.Version),
|
||||||
Uri.EscapeUriString(Game.ModData.Manifest.Mod.Id),
|
Uri.EscapeUriString(Game.ModData.Manifest.Id),
|
||||||
Uri.EscapeUriString(Game.ModData.Manifest.Mod.Version));
|
Uri.EscapeUriString(Game.ModData.Manifest.Mod.Version));
|
||||||
|
|
||||||
currentQuery = new Download(queryURL, _ => { }, onComplete);
|
currentQuery = new Download(queryURL, _ => { }, onComplete);
|
||||||
@@ -330,7 +330,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// Games for the current mod+version are sorted first
|
// Games for the current mod+version are sorted first
|
||||||
if (testEntry.ModId == modData.Manifest.Mod.Id)
|
if (testEntry.ModId == modData.Manifest.Id)
|
||||||
return 2;
|
return 2;
|
||||||
|
|
||||||
// Followed by games for different mods that are joinable
|
// Followed by games for different mods that are joinable
|
||||||
|
|||||||
@@ -59,8 +59,8 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
replayList = panel.Get<ScrollPanelWidget>("REPLAY_LIST");
|
replayList = panel.Get<ScrollPanelWidget>("REPLAY_LIST");
|
||||||
var template = panel.Get<ScrollItemWidget>("REPLAY_TEMPLATE");
|
var template = panel.Get<ScrollItemWidget>("REPLAY_TEMPLATE");
|
||||||
|
|
||||||
var mod = modData.Manifest.Mod;
|
var mod = modData.Manifest;
|
||||||
var dir = Platform.ResolvePath("^", "Replays", mod.Id, mod.Version);
|
var dir = Platform.ResolvePath("^", "Replays", mod.Id, mod.Mod.Version);
|
||||||
|
|
||||||
if (Directory.Exists(dir))
|
if (Directory.Exists(dir))
|
||||||
ThreadPool.QueueUserWorkItem(_ => LoadReplays(dir, template));
|
ThreadPool.QueueUserWorkItem(_ => LoadReplays(dir, template));
|
||||||
|
|||||||
@@ -34,10 +34,10 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
if (mod == null)
|
if (mod == null)
|
||||||
return IncompatibleReplayDialog("unknown mod", mod, onCancel);
|
return IncompatibleReplayDialog("unknown mod", mod, onCancel);
|
||||||
|
|
||||||
var allMods = ModMetadata.AllMods;
|
if (!Game.Mods.ContainsKey(mod))
|
||||||
if (!allMods.ContainsKey(mod))
|
|
||||||
return IncompatibleReplayDialog("unavailable mod", mod, onCancel);
|
return IncompatibleReplayDialog("unavailable mod", mod, onCancel);
|
||||||
else if (allMods[mod].Version != version)
|
|
||||||
|
if (Game.Mods[mod].Mod.Version != version)
|
||||||
return IncompatibleReplayDialog("incompatible version", version, onCancel);
|
return IncompatibleReplayDialog("incompatible version", version, onCancel);
|
||||||
|
|
||||||
if (replayMeta.GameInfo.MapPreview.Status != MapStatus.Available)
|
if (replayMeta.GameInfo.MapPreview.Status != MapStatus.Available)
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ namespace OpenRA.Mods.D2k.UtilityCommands
|
|||||||
Game.ModData = utility.ModData;
|
Game.ModData = utility.ModData;
|
||||||
|
|
||||||
var rules = Ruleset.LoadDefaultsForTileSet(utility.ModData, "ARRAKIS");
|
var rules = Ruleset.LoadDefaultsForTileSet(utility.ModData, "ARRAKIS");
|
||||||
var map = D2kMapImporter.Import(args[1], utility.ModData.Manifest.Mod.Id, args[2], rules);
|
var map = D2kMapImporter.Import(args[1], utility.ModData.Manifest.Id, args[2], rules);
|
||||||
|
|
||||||
if (map == null)
|
if (map == null)
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -168,7 +168,7 @@ namespace OpenRA.Mods.TS.UtilityCommands
|
|||||||
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 = utility.ModData.Manifest.Mod.Id
|
RequiresMod = utility.ModData.Manifest.Id
|
||||||
};
|
};
|
||||||
|
|
||||||
var fullSize = new int2(iniSize[2], iniSize[3]);
|
var fullSize = new int2(iniSize[2], iniSize[3]);
|
||||||
|
|||||||
@@ -30,9 +30,11 @@ namespace OpenRA.Server
|
|||||||
Game.InitializeSettings(new Arguments(args));
|
Game.InitializeSettings(new Arguments(args));
|
||||||
var settings = Game.Settings.Server;
|
var settings = Game.Settings.Server;
|
||||||
|
|
||||||
// HACK: The engine code *still* assumes that Game.ModData is set
|
|
||||||
var mod = Game.Settings.Game.Mod;
|
var mod = Game.Settings.Game.Mod;
|
||||||
var modData = Game.ModData = new ModData(mod, false);
|
var mods = new InstalledMods();
|
||||||
|
|
||||||
|
// HACK: The engine code *still* assumes that Game.ModData is set
|
||||||
|
var modData = Game.ModData = new ModData(mods[mod], mods);
|
||||||
modData.MapCache.LoadMaps();
|
modData.MapCache.LoadMaps();
|
||||||
|
|
||||||
settings.Map = modData.MapCache.ChooseInitialMap(settings.Map, new MersenneTwister());
|
settings.Map = modData.MapCache.ChooseInitialMap(settings.Map, new MersenneTwister());
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ using System.Runtime.Serialization;
|
|||||||
|
|
||||||
namespace OpenRA
|
namespace OpenRA
|
||||||
{
|
{
|
||||||
|
using UtilityActions = Dictionary<string, KeyValuePair<Action<Utility, string[]>, Func<string[], bool>>>;
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class NoSuchCommandException : Exception
|
public class NoSuchCommandException : Exception
|
||||||
{
|
{
|
||||||
@@ -37,27 +39,29 @@ namespace OpenRA
|
|||||||
{
|
{
|
||||||
static void Main(string[] args)
|
static void Main(string[] args)
|
||||||
{
|
{
|
||||||
if (args.Length == 0)
|
|
||||||
{
|
|
||||||
PrintUsage(null);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Log.AddChannel("perf", null);
|
Log.AddChannel("perf", null);
|
||||||
Log.AddChannel("debug", null);
|
Log.AddChannel("debug", null);
|
||||||
|
|
||||||
var modName = args[0];
|
Game.InitializeSettings(Arguments.Empty);
|
||||||
if (!ModMetadata.AllMods.Keys.Contains(modName))
|
var mods = new InstalledMods();
|
||||||
|
|
||||||
|
if (args.Length == 0)
|
||||||
{
|
{
|
||||||
PrintUsage(null);
|
PrintUsage(mods, null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Game.InitializeSettings(Arguments.Empty);
|
var modName = args[0];
|
||||||
var modData = new ModData(modName);
|
if (!mods.Keys.Contains(modName))
|
||||||
var utility = new Utility(modData);
|
{
|
||||||
|
PrintUsage(mods, null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var modData = new ModData(mods[modName], mods);
|
||||||
|
var utility = new Utility(modData, mods);
|
||||||
args = args.Skip(1).ToArray();
|
args = args.Skip(1).ToArray();
|
||||||
var actions = new Dictionary<string, KeyValuePair<Action<Utility, string[]>, Func<string[], bool>>>();
|
var actions = new UtilityActions();
|
||||||
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);
|
||||||
@@ -67,7 +71,7 @@ namespace OpenRA
|
|||||||
|
|
||||||
if (args.Length == 0)
|
if (args.Length == 0)
|
||||||
{
|
{
|
||||||
PrintUsage(actions);
|
PrintUsage(mods, actions);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,10 +110,10 @@ namespace OpenRA
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PrintUsage(IDictionary<string, KeyValuePair<Action<Utility, string[]>, Func<string[], bool>>> actions)
|
static void PrintUsage(InstalledMods mods, UtilityActions 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(", ", mods.Keys));
|
||||||
Console.WriteLine();
|
Console.WriteLine();
|
||||||
|
|
||||||
if (actions == null)
|
if (actions == null)
|
||||||
|
|||||||
Reference in New Issue
Block a user