Merge pull request #9463 from penev92/modDependencies
Add support for inter-mod dependencies
This commit is contained in:
3
Makefile
3
Makefile
@@ -320,7 +320,8 @@ all-dependencies: cli-dependencies windows-dependencies osx-dependencies
|
|||||||
version: mods/ra/mod.yaml mods/cnc/mod.yaml mods/d2k/mod.yaml mods/ts/mod.yaml mods/modchooser/mod.yaml mods/all/mod.yaml
|
version: mods/ra/mod.yaml mods/cnc/mod.yaml mods/d2k/mod.yaml mods/ts/mod.yaml mods/modchooser/mod.yaml mods/all/mod.yaml
|
||||||
@for i in $? ; do \
|
@for i in $? ; do \
|
||||||
awk '{sub("Version:.*$$","Version: $(VERSION)"); print $0}' $${i} > $${i}.tmp && \
|
awk '{sub("Version:.*$$","Version: $(VERSION)"); print $0}' $${i} > $${i}.tmp && \
|
||||||
mv -f $${i}.tmp $${i} ; \
|
awk '{sub("\tmodchooser:.*$$","\tmodchooser: $(VERSION)"); print $0}' $${i}.tmp > $${i} && \
|
||||||
|
rm $${i}.tmp ; \
|
||||||
done
|
done
|
||||||
|
|
||||||
docs: utility mods version
|
docs: utility mods version
|
||||||
|
|||||||
@@ -253,6 +253,13 @@ namespace OpenRA
|
|||||||
RunAfterDelay(Settings.Server.NatDiscoveryTimeout, UPnP.StoppingNatDiscovery);
|
RunAfterDelay(Settings.Server.NatDiscoveryTimeout, UPnP.StoppingNatDiscovery);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool IsModInstalled(string modId)
|
||||||
|
{
|
||||||
|
return Manifest.AllMods[modId].RequiresMods.All(mod => ModMetadata.AllMods.ContainsKey(mod.Key)
|
||||||
|
&& ModMetadata.AllMods[mod.Key].Version == mod.Value
|
||||||
|
&& IsModInstalled(mod.Key));
|
||||||
|
}
|
||||||
|
|
||||||
public static void InitializeMod(string mod, Arguments args)
|
public static void InitializeMod(string mod, Arguments args)
|
||||||
{
|
{
|
||||||
// Clear static state if we have switched mods
|
// Clear static state if we have switched mods
|
||||||
@@ -276,8 +283,8 @@ namespace OpenRA
|
|||||||
ModData.Dispose();
|
ModData.Dispose();
|
||||||
ModData = null;
|
ModData = null;
|
||||||
|
|
||||||
// Fall back to default if the mod doesn't exist
|
// Fall back to default if the mod doesn't exist or has missing prerequisites.
|
||||||
if (!ModMetadata.AllMods.ContainsKey(mod))
|
if (!ModMetadata.AllMods.ContainsKey(mod) || !IsModInstalled(mod))
|
||||||
mod = new GameSettings().Mod;
|
mod = new GameSettings().Mod;
|
||||||
|
|
||||||
Console.WriteLine("Loading mod: {0}", mod);
|
Console.WriteLine("Loading mod: {0}", mod);
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ namespace OpenRA
|
|||||||
// Describes what is to be loaded in order to run a mod
|
// Describes what is to be loaded in order to run a mod
|
||||||
public class Manifest
|
public class Manifest
|
||||||
{
|
{
|
||||||
|
public static readonly Dictionary<string, Manifest> AllMods = LoadMods();
|
||||||
|
|
||||||
public readonly ModMetadata Mod;
|
public readonly ModMetadata Mod;
|
||||||
public readonly string[]
|
public readonly string[]
|
||||||
Folders, Rules, ServerTraits,
|
Folders, Rules, ServerTraits,
|
||||||
@@ -44,6 +46,7 @@ namespace OpenRA
|
|||||||
public readonly MiniYaml LoadScreen;
|
public readonly MiniYaml LoadScreen;
|
||||||
public readonly MiniYaml LobbyDefaults;
|
public readonly MiniYaml LobbyDefaults;
|
||||||
|
|
||||||
|
public readonly Dictionary<string, string> RequiresMods;
|
||||||
public readonly Dictionary<string, Pair<string, int>> Fonts;
|
public readonly Dictionary<string, Pair<string, int>> Fonts;
|
||||||
|
|
||||||
public readonly string[] SpriteFormats = { };
|
public readonly string[] SpriteFormats = { };
|
||||||
@@ -51,7 +54,7 @@ namespace OpenRA
|
|||||||
readonly string[] reservedModuleNames = { "Metadata", "Folders", "MapFolders", "Packages", "Rules",
|
readonly string[] reservedModuleNames = { "Metadata", "Folders", "MapFolders", "Packages", "Rules",
|
||||||
"Sequences", "VoxelSequences", "Cursors", "Chrome", "Assemblies", "ChromeLayout", "Weapons",
|
"Sequences", "VoxelSequences", "Cursors", "Chrome", "Assemblies", "ChromeLayout", "Weapons",
|
||||||
"Voices", "Notifications", "Music", "Translations", "TileSets", "ChromeMetrics", "Missions",
|
"Voices", "Notifications", "Music", "Translations", "TileSets", "ChromeMetrics", "Missions",
|
||||||
"ServerTraits", "LoadScreen", "LobbyDefaults", "Fonts", "SupportsMapsFrom", "SpriteFormats" };
|
"ServerTraits", "LoadScreen", "LobbyDefaults", "Fonts", "SupportsMapsFrom", "SpriteFormats", "RequiresMods" };
|
||||||
|
|
||||||
readonly TypeDictionary modules = new TypeDictionary();
|
readonly TypeDictionary modules = new TypeDictionary();
|
||||||
readonly Dictionary<string, MiniYaml> yaml;
|
readonly Dictionary<string, MiniYaml> yaml;
|
||||||
@@ -98,6 +101,8 @@ namespace OpenRA
|
|||||||
return Pair.New(nd["Font"].Value, Exts.ParseIntegerInvariant(nd["Size"].Value));
|
return Pair.New(nd["Font"].Value, Exts.ParseIntegerInvariant(nd["Size"].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>();
|
var compat = new List<string>();
|
||||||
compat.Add(mod);
|
compat.Add(mod);
|
||||||
@@ -174,5 +179,29 @@ namespace OpenRA
|
|||||||
|
|
||||||
return module;
|
return module;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Dictionary<string, Manifest> LoadMods()
|
||||||
|
{
|
||||||
|
var basePath = Platform.ResolvePath(".", "mods");
|
||||||
|
var mods = Directory.GetDirectories(basePath)
|
||||||
|
.Select(x => x.Substring(basePath.Length + 1));
|
||||||
|
|
||||||
|
var ret = new Dictionary<string, Manifest>();
|
||||||
|
foreach (var mod in mods)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var manifest = new Manifest(mod);
|
||||||
|
ret.Add(mod, manifest);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Write("debug", "An exception occured while trying to load mod {0}:", mod);
|
||||||
|
Log.Write("debug", ex.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -596,6 +596,7 @@
|
|||||||
<Compile Include="Widgets\Logic\Ingame\WorldTooltipLogic.cs" />
|
<Compile Include="Widgets\Logic\Ingame\WorldTooltipLogic.cs" />
|
||||||
<Compile Include="Widgets\Logic\Installation\InstallFromCDLogic.cs" />
|
<Compile Include="Widgets\Logic\Installation\InstallFromCDLogic.cs" />
|
||||||
<Compile Include="Widgets\Logic\Installation\DownloadPackagesLogic.cs" />
|
<Compile Include="Widgets\Logic\Installation\DownloadPackagesLogic.cs" />
|
||||||
|
<Compile Include="Widgets\Logic\Installation\InstallModLogic.cs" />
|
||||||
<Compile Include="Widgets\Logic\Installation\InstallLogic.cs" />
|
<Compile Include="Widgets\Logic\Installation\InstallLogic.cs" />
|
||||||
<Compile Include="Widgets\Logic\Installation\InstallMusicLogic.cs" />
|
<Compile Include="Widgets\Logic\Installation\InstallMusicLogic.cs" />
|
||||||
<Compile Include="Widgets\Logic\Lobby\ClientTooltipLogic.cs" />
|
<Compile Include="Widgets\Logic\Lobby\ClientTooltipLogic.cs" />
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
#region Copyright & License Information
|
||||||
|
/*
|
||||||
|
* Copyright 2007-2015 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. For more information,
|
||||||
|
* see COPYING.
|
||||||
|
*/
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System.Linq;
|
||||||
|
using OpenRA.Widgets;
|
||||||
|
|
||||||
|
namespace OpenRA.Mods.Common.Widgets.Logic
|
||||||
|
{
|
||||||
|
public class InstallModLogic : ChromeLogic
|
||||||
|
{
|
||||||
|
[ObjectCreator.UseCtor]
|
||||||
|
public InstallModLogic(Widget widget, string modId)
|
||||||
|
{
|
||||||
|
var panel = widget.Get("INSTALL_MOD_PANEL");
|
||||||
|
|
||||||
|
var mods = Manifest.AllMods[modId].RequiresMods.Select(x => "{0} ({1})".F(x.Key, x.Value));
|
||||||
|
var text = string.Join(", ", mods);
|
||||||
|
panel.Get<LabelWidget>("MOD_LIST").Text = text;
|
||||||
|
|
||||||
|
panel.Get<ButtonWidget>("BACK_BUTTON").OnClick = Ui.CloseWindow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,6 +27,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
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<ModMetadata, bool> modInstallStatus;
|
readonly Cache<ModMetadata, bool> modInstallStatus;
|
||||||
|
readonly Cache<string, bool> modPrerequisitesFulfilled;
|
||||||
readonly Widget modChooserPanel;
|
readonly Widget modChooserPanel;
|
||||||
readonly ButtonWidget loadButton;
|
readonly ButtonWidget loadButton;
|
||||||
readonly SheetBuilder sheetBuilder;
|
readonly SheetBuilder sheetBuilder;
|
||||||
@@ -38,6 +39,9 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
[ObjectCreator.UseCtor]
|
[ObjectCreator.UseCtor]
|
||||||
public ModBrowserLogic(Widget widget)
|
public ModBrowserLogic(Widget widget)
|
||||||
{
|
{
|
||||||
|
modInstallStatus = new Cache<ModMetadata, bool>(IsModInstalled);
|
||||||
|
modPrerequisitesFulfilled = new Cache<string, bool>(Game.IsModInstalled);
|
||||||
|
|
||||||
modChooserPanel = widget;
|
modChooserPanel = widget;
|
||||||
loadButton = modChooserPanel.Get<ButtonWidget>("LOAD_BUTTON");
|
loadButton = modChooserPanel.Get<ButtonWidget>("LOAD_BUTTON");
|
||||||
loadButton.OnClick = () => LoadMod(selectedMod);
|
loadButton.OnClick = () => LoadMod(selectedMod);
|
||||||
@@ -93,8 +97,6 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
catch (Exception) { }
|
catch (Exception) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
modInstallStatus = new Cache<ModMetadata, bool>(IsModInstalled);
|
|
||||||
|
|
||||||
ModMetadata initialMod;
|
ModMetadata initialMod;
|
||||||
ModMetadata.AllMods.TryGetValue(Game.Settings.Game.PreviousMod, out initialMod);
|
ModMetadata.AllMods.TryGetValue(Game.Settings.Game.PreviousMod, out initialMod);
|
||||||
SelectMod(initialMod != null && initialMod.Id != "modchooser" ? initialMod : ModMetadata.AllMods["ra"]);
|
SelectMod(initialMod != null && initialMod.Id != "modchooser" ? initialMod : ModMetadata.AllMods["ra"]);
|
||||||
@@ -156,11 +158,23 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
if (selectedIndex - modOffset > 4)
|
if (selectedIndex - modOffset > 4)
|
||||||
modOffset = selectedIndex - 4;
|
modOffset = selectedIndex - 4;
|
||||||
|
|
||||||
loadButton.Text = modInstallStatus[mod] ? "Load Mod" : "Install Assets";
|
loadButton.Text = !modPrerequisitesFulfilled[mod.Id] ? "Install mod" :
|
||||||
|
modInstallStatus[mod] ? "Load Mod" : "Install Assets";
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoadMod(ModMetadata mod)
|
void LoadMod(ModMetadata mod)
|
||||||
{
|
{
|
||||||
|
if (!modPrerequisitesFulfilled[mod.Id])
|
||||||
|
{
|
||||||
|
var widgetArgs = new WidgetArgs
|
||||||
|
{
|
||||||
|
{ "modId", mod.Id }
|
||||||
|
};
|
||||||
|
|
||||||
|
Ui.OpenWindow("INSTALL_MOD_PANEL", widgetArgs);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!modInstallStatus[mod])
|
if (!modInstallStatus[mod])
|
||||||
{
|
{
|
||||||
var widgetArgs = new WidgetArgs
|
var widgetArgs = new WidgetArgs
|
||||||
|
|||||||
2
make.ps1
2
make.ps1
@@ -113,6 +113,8 @@ elseif ($command -eq "version")
|
|||||||
{
|
{
|
||||||
$replacement = (gc $mod) -Replace "Version:.*", ("Version: {0}" -f $version)
|
$replacement = (gc $mod) -Replace "Version:.*", ("Version: {0}" -f $version)
|
||||||
sc $mod $replacement
|
sc $mod $replacement
|
||||||
|
$replacement = (gc $mod) -Replace "modchooser:.*", ("modchooser: {0}" -f $version)
|
||||||
|
sc $mod $replacement
|
||||||
}
|
}
|
||||||
echo ("Version strings set to '{0}'." -f $version)
|
echo ("Version strings set to '{0}'." -f $version)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,9 @@ Metadata:
|
|||||||
Version: {DEV_VERSION}
|
Version: {DEV_VERSION}
|
||||||
Author: the OpenRA Developers
|
Author: the OpenRA Developers
|
||||||
|
|
||||||
|
RequiresMods:
|
||||||
|
modchooser: {DEV_VERSION}
|
||||||
|
|
||||||
Folders:
|
Folders:
|
||||||
.
|
.
|
||||||
./mods/cnc
|
./mods/cnc
|
||||||
|
|||||||
@@ -4,6 +4,9 @@ Metadata:
|
|||||||
Version: {DEV_VERSION}
|
Version: {DEV_VERSION}
|
||||||
Author: the OpenRA Developers
|
Author: the OpenRA Developers
|
||||||
|
|
||||||
|
RequiresMods:
|
||||||
|
modchooser: {DEV_VERSION}
|
||||||
|
|
||||||
Folders:
|
Folders:
|
||||||
.
|
.
|
||||||
./mods/d2k
|
./mods/d2k
|
||||||
|
|||||||
@@ -260,3 +260,50 @@ Container@INSTALL_MUSIC_PANEL:
|
|||||||
Text: Back
|
Text: Back
|
||||||
Font: Bold
|
Font: Bold
|
||||||
Key: escape
|
Key: escape
|
||||||
|
Container@INSTALL_MOD_PANEL:
|
||||||
|
Logic: InstallModLogic
|
||||||
|
X: (WINDOW_RIGHT - WIDTH)/2
|
||||||
|
Y: (WINDOW_BOTTOM - HEIGHT)/2
|
||||||
|
Width: 500
|
||||||
|
Height: 177
|
||||||
|
Children:
|
||||||
|
Background:
|
||||||
|
Width: PARENT_RIGHT
|
||||||
|
Height: PARENT_BOTTOM
|
||||||
|
Background: panel-bg
|
||||||
|
Background@RULE:
|
||||||
|
X: 30
|
||||||
|
Y: 50
|
||||||
|
Width: 440
|
||||||
|
Height: 150
|
||||||
|
Background: panel-rule
|
||||||
|
Label@TITLE:
|
||||||
|
X: 0
|
||||||
|
Y: 12
|
||||||
|
Width: PARENT_RIGHT
|
||||||
|
Height: 25
|
||||||
|
Text: Missing dependencies
|
||||||
|
Align: Center
|
||||||
|
Font: MediumBold
|
||||||
|
Label@DESC:
|
||||||
|
X: 0
|
||||||
|
Y: 65
|
||||||
|
Width: PARENT_RIGHT
|
||||||
|
Height: 25
|
||||||
|
Align: Center
|
||||||
|
Text: Please fully install the following mods then try again:
|
||||||
|
Label@MOD_LIST:
|
||||||
|
X: 0
|
||||||
|
Y: 85
|
||||||
|
Width: PARENT_RIGHT
|
||||||
|
Height: 25
|
||||||
|
Align: Center
|
||||||
|
Button@BACK_BUTTON:
|
||||||
|
X: PARENT_RIGHT - 130
|
||||||
|
Y: PARENT_BOTTOM - 52
|
||||||
|
Background: button-highlighted
|
||||||
|
Width: 110
|
||||||
|
Height: 32
|
||||||
|
Text: Back
|
||||||
|
Font: Bold
|
||||||
|
Key: escape
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ Metadata:
|
|||||||
Author: The OpenRA Developers
|
Author: The OpenRA Developers
|
||||||
Hidden: true
|
Hidden: true
|
||||||
|
|
||||||
|
RequiresMods:
|
||||||
|
|
||||||
Folders:
|
Folders:
|
||||||
.
|
.
|
||||||
./mods/modchooser
|
./mods/modchooser
|
||||||
|
|||||||
@@ -4,6 +4,9 @@ Metadata:
|
|||||||
Version: {DEV_VERSION}
|
Version: {DEV_VERSION}
|
||||||
Author: the OpenRA Developers
|
Author: the OpenRA Developers
|
||||||
|
|
||||||
|
RequiresMods:
|
||||||
|
modchooser: {DEV_VERSION}
|
||||||
|
|
||||||
Folders:
|
Folders:
|
||||||
.
|
.
|
||||||
./mods/ra
|
./mods/ra
|
||||||
|
|||||||
@@ -4,6 +4,9 @@ Metadata:
|
|||||||
Version: {DEV_VERSION}
|
Version: {DEV_VERSION}
|
||||||
Author: the OpenRA Developers
|
Author: the OpenRA Developers
|
||||||
|
|
||||||
|
RequiresMods:
|
||||||
|
modchooser: {DEV_VERSION}
|
||||||
|
|
||||||
Folders:
|
Folders:
|
||||||
.
|
.
|
||||||
# Tiberian Sun
|
# Tiberian Sun
|
||||||
|
|||||||
Reference in New Issue
Block a user