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:
Paul Chote
2016-08-05 17:07:04 +01:00
parent 45a596953e
commit 3df9efb95d
33 changed files with 301 additions and 219 deletions

View File

@@ -79,7 +79,7 @@ namespace OpenRA.Mods.Common.LoadScreens
if (replayMeta != null)
{
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);
}

View File

@@ -52,7 +52,7 @@ namespace OpenRA.Mods.Common.Server
lastPing = Game.RunTime;
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
// by the main thread as clients join and leave.
@@ -79,7 +79,7 @@ namespace OpenRA.Mods.Common.Server
(int)server.State,
numPlayers,
numBots,
"{0}@{1}".F(mod.Id, mod.Version),
"{0}@{1}".F(mod.Id, mod.Mod.Version),
server.LobbyInfo.GlobalSettings.Map,
numSlots,
numSpectators,

View File

@@ -74,7 +74,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
Author = "Westwood Studios",
};
Map.RequiresMod = ModData.Manifest.Mod.Id;
Map.RequiresMod = ModData.Manifest.Id;
SetBounds(Map, mapSection);

View File

@@ -11,7 +11,6 @@
using System;
using System.IO;
using System.Linq;
using OpenRA.FileSystem;
namespace OpenRA.Mods.Common.UtilityCommands
@@ -31,7 +30,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
var filename = Path.GetFileName(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");
var package = new InstallShieldPackage(fs, "parent|" + filename);

View File

@@ -31,7 +31,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
var filename = Path.GetFileName(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
fs.LoadFromManifest(utility.ModData.Manifest);

View File

@@ -39,14 +39,14 @@ namespace OpenRA.Mods.Common.UtilityCommands
remap[i] = i;
var srcMod = args[1].Split(':')[0];
var srcModData = new ModData(srcMod);
var srcModData = new ModData(utility.Mods[srcMod], utility.Mods);
Game.ModData = srcModData;
var srcPaletteInfo = srcModData.DefaultRules.Actors["player"].TraitInfo<PlayerColorPaletteInfo>();
var srcRemapIndex = srcPaletteInfo.RemapIndex;
var destMod = args[2].Split(':')[0];
var destModData = new ModData(destMod);
var destModData = new ModData(utility.Mods[destMod], utility.Mods);
Game.ModData = destModData;
var destPaletteInfo = destModData.DefaultRules.Actors["player"].TraitInfo<PlayerColorPaletteInfo>();
var destRemapIndex = destPaletteInfo.RemapIndex;

View File

@@ -346,7 +346,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
{
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")
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)
{
// 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" };
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
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" };
if (buildings.Contains(parent.Value.Value) && node.Key == "Location")

View File

@@ -165,7 +165,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
if (playerDefinitions != null)
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));

View File

@@ -21,7 +21,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
{
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);
panel.Get<LabelWidget>("MOD_LIST").Text = text;

View File

@@ -10,7 +10,6 @@
#endregion
using System;
using System.IO;
using System.Linq;
using OpenRA.Widgets;
@@ -24,11 +23,12 @@ namespace OpenRA.Mods.Common.Widgets.Logic
bool discAvailable;
[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");
content = ModMetadata.AllMods[modId].ModContent;
scrollPanel = panel.Get<ScrollPanelWidget>("PACKAGES");
template = scrollPanel.Get<ContainerWidget>("PACKAGE_TEMPLATE");

View File

@@ -17,13 +17,10 @@ namespace OpenRA.Mods.Common.Widgets.Logic
public class ModContentPromptLogic : ChromeLogic
{
[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 mod = ModMetadata.AllMods[modId];
var content = ModMetadata.AllMods[modId].ModContent;
var headerTemplate = panel.Get<LabelWidget>("HEADER_TEMPLATE");
var headerLines = !string.IsNullOrEmpty(content.InstallPromptMessage) ? content.InstallPromptMessage.Replace("\\n", "\n").Split('\n') : new string[0];
var headerHeight = 0;
@@ -46,7 +43,8 @@ namespace OpenRA.Mods.Common.Widgets.Logic
{
Ui.OpenWindow("CONTENT_PANEL", new WidgetArgs
{
{ "modId", modId },
{ "mod", mod },
{ "content", content },
{ "onCancel", Ui.CloseWindow }
});
};

View File

@@ -90,7 +90,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
// so we can't do this inside the input handler.
Game.RunAfterTick(() =>
{
Game.Settings.Game.PreviousMod = modData.Manifest.Mod.Id;
Game.Settings.Game.PreviousMod = modData.Manifest.Id;
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)
var newsURL = Game.Settings.Game.NewsUrl + "?version={0}&mod={1}&modversion={2}".F(
Uri.EscapeUriString(ModMetadata.AllMods["modchooser"].Version),
Uri.EscapeUriString(Game.ModData.Manifest.Mod.Id),
Uri.EscapeUriString(Game.Mods["modchooser"].Mod.Version),
Uri.EscapeUriString(Game.ModData.Manifest.Id),
Uri.EscapeUriString(Game.ModData.Manifest.Mod.Version));
// Append system profile data if the player has opted in

View File

@@ -24,32 +24,39 @@ namespace OpenRA.Mods.Common.Widgets.Logic
{
readonly Widget modList;
readonly ButtonWidget modTemplate;
readonly ModMetadata[] allMods;
readonly Manifest[] allMods;
readonly Dictionary<string, Sprite> previews = 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 ButtonWidget loadButton;
readonly SheetBuilder sheetBuilder;
ModMetadata selectedMod;
Manifest selectedMod;
string selectedAuthor;
string selectedDescription;
int modOffset = 0;
static ModContent LoadModContent(Manifest mod)
{
return mod.Get<ModContent>(Game.ModData.ObjectCreator);
}
[ObjectCreator.UseCtor]
public ModBrowserLogic(Widget widget, ModData modData)
{
modChooserPanel = widget;
loadButton = modChooserPanel.Get<ButtonWidget>("LOAD_BUTTON");
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");
contentButton.IsDisabled = () => selectedMod.ModContent == null;
contentButton.OnClick = () =>
{
var widgetArgs = new WidgetArgs
{
{ "modId", selectedMod.Id },
{ "mod", selectedMod },
{ "content", content[selectedMod] },
{ "onCancel", () => { } }
};
@@ -62,9 +69,9 @@ namespace OpenRA.Mods.Common.Widgets.Logic
modTemplate = modList.Get<ButtonWidget>("MOD_TEMPLATE");
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_VERSION").GetText = () => selectedMod.Version;
modChooserPanel.Get<LabelWidget>("MOD_VERSION").GetText = () => selectedMod.Mod.Version;
var prevMod = modChooserPanel.Get<ButtonWidget>("PREV_MOD");
prevMod.OnClick = () => { modOffset -= 1; RebuildModList(); };
@@ -82,8 +89,8 @@ namespace OpenRA.Mods.Common.Widgets.Logic
};
sheetBuilder = new SheetBuilder(SheetType.BGRA);
allMods = ModMetadata.AllMods.Values.Where(m => !m.Hidden)
.OrderBy(m => m.Title)
allMods = Game.Mods.Values.Where(m => !m.Mod.Hidden)
.OrderBy(m => m.Mod.Title)
.ToArray();
// Load preview images, and eat any errors
@@ -91,7 +98,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
{
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))
if (preview.Width == 296 && preview.Height == 196)
previews.Add(mod.Id, sheetBuilder.Add(preview));
@@ -100,7 +107,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
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))
if (logo.Width == 96 && logo.Height == 96)
logos.Add(mod.Id, sheetBuilder.Add(logo));
@@ -108,9 +115,9 @@ namespace OpenRA.Mods.Common.Widgets.Logic
catch (Exception) { }
}
ModMetadata initialMod;
ModMetadata.AllMods.TryGetValue(Game.Settings.Game.PreviousMod, out initialMod);
SelectMod(initialMod != null && initialMod.Id != "modchooser" ? initialMod : ModMetadata.AllMods["ra"]);
Manifest initialMod;
Game.Mods.TryGetValue(Game.Settings.Game.PreviousMod, out initialMod);
SelectMod(initialMod != null && initialMod.Id != "modchooser" ? initialMod : Game.Mods["ra"]);
RebuildModList();
}
@@ -146,7 +153,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
SelectMod(mod);
};
item.TooltipText = mod.Title;
item.TooltipText = mod.Mod.Title;
if (j < 9)
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;
selectedAuthor = "By " + (mod.Author ?? "unknown author");
selectedDescription = (mod.Description ?? "").Replace("\\n", "\n");
selectedAuthor = "By " + (mod.Mod.Author ?? "unknown author");
selectedDescription = (mod.Mod.Description ?? "").Replace("\\n", "\n");
var selectedIndex = Array.IndexOf(allMods, mod);
if (selectedIndex - modOffset > 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
{
{ "modId", mod.Id }
{ "mod", selectedMod },
{ "content", content[selectedMod] },
};
Ui.OpenWindow("INSTALL_MOD_PANEL", widgetArgs);
@@ -188,8 +197,9 @@ namespace OpenRA.Mods.Common.Widgets.Logic
var widgetArgs = new WidgetArgs
{
{ "continueLoading", () =>
Game.RunAfterTick(() => Game.InitializeMod(mod.Id, new Arguments())) },
{ "modId", mod.Id }
Game.RunAfterTick(() => Game.InitializeMod(modId, new Arguments())) },
{ "mod", selectedMod },
{ "content", content[selectedMod] },
};
Ui.OpenWindow("CONTENT_PROMPT_PANEL", widgetArgs);
@@ -201,13 +211,13 @@ namespace OpenRA.Mods.Common.Widgets.Logic
{
Ui.CloseWindow();
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)
.All(p => p.Value.TestFiles.All(f => File.Exists(Platform.ResolvePath(f))));
}

View File

@@ -316,8 +316,8 @@ namespace OpenRA.Mods.Common.Widgets.Logic
};
var queryURL = Game.Settings.Server.MasterServer + "games?version={0}&mod={1}&modversion={2}".F(
Uri.EscapeUriString(ModMetadata.AllMods["modchooser"].Version),
Uri.EscapeUriString(Game.ModData.Manifest.Mod.Id),
Uri.EscapeUriString(Game.Mods["modchooser"].Mod.Version),
Uri.EscapeUriString(Game.ModData.Manifest.Id),
Uri.EscapeUriString(Game.ModData.Manifest.Mod.Version));
currentQuery = new Download(queryURL, _ => { }, onComplete);
@@ -330,7 +330,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
return 0;
// Games for the current mod+version are sorted first
if (testEntry.ModId == modData.Manifest.Mod.Id)
if (testEntry.ModId == modData.Manifest.Id)
return 2;
// Followed by games for different mods that are joinable

View File

@@ -59,8 +59,8 @@ namespace OpenRA.Mods.Common.Widgets.Logic
replayList = panel.Get<ScrollPanelWidget>("REPLAY_LIST");
var template = panel.Get<ScrollItemWidget>("REPLAY_TEMPLATE");
var mod = modData.Manifest.Mod;
var dir = Platform.ResolvePath("^", "Replays", mod.Id, mod.Version);
var mod = modData.Manifest;
var dir = Platform.ResolvePath("^", "Replays", mod.Id, mod.Mod.Version);
if (Directory.Exists(dir))
ThreadPool.QueueUserWorkItem(_ => LoadReplays(dir, template));

View File

@@ -34,10 +34,10 @@ namespace OpenRA.Mods.Common.Widgets.Logic
if (mod == null)
return IncompatibleReplayDialog("unknown mod", mod, onCancel);
var allMods = ModMetadata.AllMods;
if (!allMods.ContainsKey(mod))
if (!Game.Mods.ContainsKey(mod))
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);
if (replayMeta.GameInfo.MapPreview.Status != MapStatus.Available)