Index: binaries/data/mods/mod/gui/modmod/modmod.js
===================================================================
--- binaries/data/mods/mod/gui/modmod/modmod.js
+++ binaries/data/mods/mod/gui/modmod/modmod.js
@@ -89,7 +89,7 @@
function loadEnabledMods()
{
- g_ModsEnabled = Engine.ConfigDB_GetValue("user", "mod.enabledmods").split(/\s+/).filter(folder => !!g_Mods[folder]);
+ g_ModsEnabled = Engine.GetEnabledMods().filter(folder => !!g_Mods[folder]);
g_ModsDisabled = Object.keys(g_Mods).filter(folder => g_ModsEnabled.indexOf(folder) == -1);
g_ModsEnabledFiltered = g_ModsEnabled;
g_ModsDisabledFiltered = g_ModsDisabled;
@@ -114,6 +114,8 @@
let cancelButton = !data || data.cancelbutton;
Engine.GetGUIObjectByName("cancelButton").hidden = !cancelButton;
Engine.GetGUIObjectByName("quitButton").hidden = cancelButton;
+ Engine.GetGUIObjectByName("startModsButton").hidden = !cancelButton;
+ Engine.GetGUIObjectByName("startButton").hidden = cancelButton;
Engine.GetGUIObjectByName("toggleModButton").caption = translateWithContext("mod activation", "Enable");
}
@@ -127,8 +129,13 @@
function startMods()
{
sortEnabledMods();
- Engine.SetMods(["mod"].concat(g_ModsEnabled));
- Engine.RestartEngine();
+ if (!g_ModsEnabled.length)
+ {
+ Engine.GetGUIObjectByName("message").caption = coloredText(translate('Enable at least one mod'), g_ColorDependenciesNotMet);
+ return;
+ }
+ if (!Engine.SetModsAndRestartEngine(["mod"].concat(g_ModsEnabled)))
+ Engine.GetGUIObjectByName("message").caption = coloredText(translate('Dependencies not met'), g_ColorDependenciesNotMet);
}
function displayModLists()
Index: binaries/data/mods/mod/gui/modmod/modmod.xml
===================================================================
--- binaries/data/mods/mod/gui/modmod/modmod.xml
+++ binaries/data/mods/mod/gui/modmod/modmod.xml
@@ -202,5 +202,10 @@
Start Mods
startMods();
+
+
Index: source/main.cpp
===================================================================
--- source/main.cpp
+++ source/main.cpp
@@ -49,6 +49,7 @@
#include "ps/Globals.h"
#include "ps/Hotkey.h"
#include "ps/Loader.h"
+#include "ps/Mod.h"
#include "ps/ModInstaller.h"
#include "ps/Profile.h"
#include "ps/Profiler2.h"
@@ -594,7 +595,7 @@
Paths paths(args);
g_VFS = CreateVfs();
g_VFS->Mount(L"cache/", paths.Cache(), VFS_MOUNT_ARCHIVABLE);
- MountMods(paths, GetMods(args, INIT_MODS));
+ MountMods(paths, Mod::GetModsFromArguments(args, INIT_MODS));
{
CReplayPlayer replay;
Index: source/ps/GameSetup/GameSetup.h
===================================================================
--- source/ps/GameSetup/GameSetup.h
+++ source/ps/GameSetup/GameSetup.h
@@ -82,7 +82,6 @@
class CmdLineArgs;
class Paths;
-extern const std::vector& GetMods(const CmdLineArgs& args, int flags);
/**
* Mounts all files of the given mods in the global VFS.
Index: source/ps/GameSetup/GameSetup.cpp
===================================================================
--- source/ps/GameSetup/GameSetup.cpp
+++ source/ps/GameSetup/GameSetup.cpp
@@ -370,36 +370,6 @@
return ERI_NOT_IMPLEMENTED;
}
-const std::vector& GetMods(const CmdLineArgs& args, int flags)
-{
- const bool init_mods = (flags & INIT_MODS) == INIT_MODS;
- const bool add_user = !InDevelopmentCopy() && !args.Has("noUserMod");
- const bool add_public = (flags & INIT_MODS_PUBLIC) == INIT_MODS_PUBLIC;
-
- if (!init_mods)
- {
- // Add the user mod if it should be present
- if (add_user && (g_modsLoaded.empty() || g_modsLoaded.back() != "user"))
- g_modsLoaded.push_back("user");
-
- return g_modsLoaded;
- }
-
- g_modsLoaded = args.GetMultiple("mod");
-
- if (add_public)
- g_modsLoaded.insert(g_modsLoaded.begin(), "public");
-
- g_modsLoaded.insert(g_modsLoaded.begin(), "mod");
-
- // Add the user mod if not explicitly disabled or we have a dev copy so
- // that saved files end up in version control and not in the user mod.
- if (add_user)
- g_modsLoaded.push_back("user");
-
- return g_modsLoaded;
-}
-
void MountMods(const Paths& paths, const std::vector& mods)
{
OsPath modPath = paths.RData()/"mods";
@@ -458,7 +428,7 @@
// Engine localization files.
g_VFS->Mount(L"l10n/", paths.RData()/"l10n"/"");
- MountMods(paths, GetMods(args, flags));
+ MountMods(paths, Mod::GetModsFromArguments(args, flags));
// We mount these dirs last as otherwise writing could result in files being placed in a mod's dir.
g_VFS->Mount(L"screenshots/", paths.UserData()/"screenshots"/"");
@@ -869,6 +839,28 @@
*/
bool AutostartVisualReplay(const std::string& replayFile);
+bool EnableModsOrFail(const CmdLineArgs& args, int flags, const std::vector& mods)
+{
+ const bool isNonVisual = args.Has("autostart-nonvisual");
+ if (!Mod::CheckAndEnableMods(g_ScriptContext, mods))
+ {
+ // Here we refuse to start as there is no gui anyway
+ if (isNonVisual)
+ {
+ LOGERROR("Mods defined in config file are not compatible.");
+ return false;
+ }
+ // When mods are incompatible, we enforce default ones so user is able
+ // to start the game without wall of error strings
+ Mod::SetDefaultMods(g_ScriptContext, args, flags);
+ // Abort init and restart
+ RestartEngine();
+ return false;
+ }
+
+ return true;
+}
+
bool Init(const CmdLineArgs& args, int flags)
{
h_mgr_init();
@@ -929,22 +921,30 @@
// else check if there are mods that should be loaded specified
// in the config and load those (by aborting init and restarting
// the engine).
- if (!args.Has("mod") && (flags & INIT_MODS) == INIT_MODS)
+
+ if (!args.Has("mod"))
{
- CStr modstring;
- CFG_GET_VAL("mod.enabledmods", modstring);
- if (!modstring.empty())
- {
- std::vector mods;
- boost::split(mods, modstring, boost::is_any_of(" "), boost::token_compress_on);
- std::swap(g_modsLoaded, mods);
+ if ((flags & INIT_MODS) == INIT_MODS)
+ {
+ CStr modstring;
+ CFG_GET_VAL("mod.enabledmods", modstring);
+ if (!modstring.empty())
+ {
+ std::vector mods;
+ boost::split(mods, modstring, boost::is_any_of(" "), boost::token_compress_on);
+ if (!EnableModsOrFail(args, flags, mods))
+ return false;
- // Abort init and restart
- RestartEngine();
- return false;
+ RestartEngine();
+ return false;
+ }
}
}
-
+ else
+ {
+ if (!EnableModsOrFail(args, flags, g_modsLoaded))
+ return false;
+ }
new L10n;
// Optionally start profiler HTTP output automatically
Index: source/ps/Mod.h
===================================================================
--- source/ps/Mod.h
+++ source/ps/Mod.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2018 Wildfire Games.
+/* Copyright (C) 2021 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -30,7 +30,7 @@
namespace Mod
{
JS::Value GetAvailableMods(const ScriptInterface& scriptInterface);
-
+ std::vector GetEnabledMods(const ScriptInterface& scriptInterface);
/**
* This reads the version numbers from the launched mods.
* It caches the result, since the reading of zip files is slow and
@@ -39,6 +39,12 @@
*/
void CacheEnabledModVersions(const shared_ptr& scriptContext);
+ const std::vector& GetModsFromArguments(const CmdLineArgs& args, int flags);
+ bool CheckAndEnableMods(const shared_ptr& scriptContext, const std::vector& mods);
+ bool CheckAndEnableMods(const ScriptInterface& scriptInterface, const std::vector& mods);
+ bool CompareVersionStrings(const CStr& version, const CStr& op, const CStr& target);
+ void SetDefaultMods(const shared_ptr& scriptContext, const CmdLineArgs& args, int flags);
+
/**
* Get the loaded mods and their version.
* "user" mod and "mod" mod are ignored as they are irrelevant for compatibility checks.
Index: source/ps/Mod.cpp
===================================================================
--- source/ps/Mod.cpp
+++ source/ps/Mod.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 2020 Wildfire Games.
+/* Copyright (C) 2021 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@@ -19,8 +19,6 @@
#include "ps/Mod.h"
-#include
-
#include "lib/file/file_system.h"
#include "lib/file/vfs/vfs.h"
#include "lib/utf8.h"
@@ -30,6 +28,11 @@
#include "ps/Pyrogenesis.h"
#include "scriptinterface/ScriptInterface.h"
+#include
+#include