Index: binaries/data/mods/mod/gui/incompatible_mods/incompatible_mods.js
===================================================================
--- /dev/null
+++ binaries/data/mods/mod/gui/incompatible_mods/incompatible_mods.js
@@ -0,0 +1,11 @@
+var g_IncompatibleModsFile = "gui/incompatible_mods/incompatible_mods.txt";
+
+function init(data)
+{
+ Engine.GetGUIObjectByName("mainText").caption = Engine.TranslateLines(Engine.ReadFile(g_IncompatibleModsFile));
+}
+
+function closePage()
+{
+ Engine.PopGuiPage();
+}
Index: binaries/data/mods/mod/gui/incompatible_mods/incompatible_mods.txt
===================================================================
--- /dev/null
+++ binaries/data/mods/mod/gui/incompatible_mods/incompatible_mods.txt
@@ -0,0 +1,4 @@
+[font="sans-bold-20"] You tried to start game with incompatible or missing mods!
+[font="sans-16"]
+Solve the compatibility and start game again.
+You might want to save configuration before starting, when you see this page again.
Index: binaries/data/mods/mod/gui/incompatible_mods/incompatible_mods.xml
===================================================================
--- /dev/null
+++ binaries/data/mods/mod/gui/incompatible_mods/incompatible_mods.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
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
@@ -56,6 +56,20 @@
*/
var g_InstalledMods;
+/**
+ * Foldernames of mods, which were enabled on engine start, when compatibility check failed.
+ */
+var g_IncompatibleMods;
+
+var g_FakeMod = {
+ "name": traslate("This mod does not exist"),
+ "version": "",
+ "label": "",
+ "url": "",
+ "description": "",
+ "dependencies": []
+};
+
var g_ColorNoModSelected = "255 255 100";
var g_ColorDependenciesMet = "100 255 100";
var g_ColorDependenciesNotMet = "255 100 100";
@@ -63,9 +77,13 @@
function init(data, hotloadData)
{
g_InstalledMods = data && data.installedMods || hotloadData && hotloadData.installedMods || [];
+ g_IncompatibleMods = Engine.GetIncompatibleMods();
+ deepfreeze(g_IncompatibleMods);
initMods();
initGUIButtons(data);
+ if (g_IncompatibleMods.length)
+ Engine.PushGuiPage("page_incompatible_mods.xml", {});
}
function initMods()
@@ -87,9 +105,20 @@
deepfreeze(g_Mods);
}
+/**
+ * Return fake mod for mods which do not exist
+*/
+function getMod(folder)
+{
+ return !!g_Mods[folder] ? g_Mods[folder] : g_FakeMod;
+}
+
function loadEnabledMods()
{
- g_ModsEnabled = Engine.ConfigDB_GetValue("user", "mod.enabledmods").split(/\s+/).filter(folder => !!g_Mods[folder]);
+ if (g_IncompatibleMods.length)
+ g_ModsEnabled = Engine.GetFailedMods().filter(folder => folder != "mod" && folder != "user");
+ else
+ 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;
@@ -111,9 +140,11 @@
function initGUIButtons(data)
{
// Either get back to the previous page or quit if there is no previous page
- let cancelButton = !data || data.cancelbutton;
- Engine.GetGUIObjectByName("cancelButton").hidden = !cancelButton;
- Engine.GetGUIObjectByName("quitButton").hidden = cancelButton;
+ let hasPreviousPage = !data || data.cancelbutton;
+ Engine.GetGUIObjectByName("cancelButton").hidden = !hasPreviousPage;
+ Engine.GetGUIObjectByName("quitButton").hidden = hasPreviousPage;
+ Engine.GetGUIObjectByName("startModsButton").hidden = !hasPreviousPage;
+ Engine.GetGUIObjectByName("startButton").hidden = hasPreviousPage;
Engine.GetGUIObjectByName("toggleModButton").caption = translateWithContext("mod activation", "Enable");
}
@@ -127,8 +158,8 @@
function startMods()
{
sortEnabledMods();
- Engine.SetMods(["mod"].concat(g_ModsEnabled));
- Engine.RestartEngine();
+ if (!Engine.SetModsAndRestartEngine(["mod"].concat(g_ModsEnabled)))
+ Engine.GetGUIObjectByName("message").caption = coloredText(translate('Dependencies not met'), g_ColorDependenciesNotMet);
}
function displayModLists()
@@ -143,7 +174,7 @@
if (listObjectName == "modsDisabledList")
{
- let sortFolder = folder => String(g_Mods[folder][listObject.selected_column] || folder);
+ let sortFolder = folder => String(getMod(folder)[listObject.selected_column] || folder);
folders.sort((folder1, folder2) =>
listObject.selected_column_order *
sortFolder(folder1).localeCompare(sortFolder(folder2)));
@@ -153,12 +184,12 @@
let selected = listObject.selected !== -1 ? listObject.list_name[listObject.selected] : null;
- listObject.list_name = folders.map(folder => g_Mods[folder].name).map(name => g_InstalledMods.indexOf(name) == -1 ? name : coloredText(name, "green"));
- listObject.list_folder = folders;
- listObject.list_label = folders.map(folder => g_Mods[folder].label);
- listObject.list_url = folders.map(folder => g_Mods[folder].url || "");
- listObject.list_version = folders.map(folder => g_Mods[folder].version);
- listObject.list_dependencies = folders.map(folder => g_Mods[folder].dependencies.join(" "));
+ listObject.list_name = folders.map(folder => colorMod(folder, getMod(folder).name));
+ listObject.list_folder = folders.map(folder => colorMod(folder, folder));
+ listObject.list_label = folders.map(folder => colorMod(folder, getMod(folder).label));
+ listObject.list_url = folders.map(folder => colorMod(folder, getMod(folder).url || ""));
+ listObject.list_version = folders.map(folder => colorMod(folder, getMod(folder).version));
+ listObject.list_dependencies = folders.map(folder => colorMod(folder, getMod(folder).dependencies.join(" ")));
listObject.list = folders;
listObject.selected = selected ? listObject.list_name.indexOf(selected) : -1;
@@ -166,6 +197,21 @@
return folders;
}
+function getModColor(folder)
+{
+ if (g_IncompatibleMods.indexOf(folder) != -1)
+ return "red";
+ if (g_InstalledMods.indexOf(getMod(folder).name) != -1)
+ return "green";
+ return false;
+}
+
+function colorMod(folder, text)
+{
+ let color = getModColor(folder);
+ return color ? coloredText(text, color) : text;
+}
+
function reloadDisabledMods()
{
g_ModsDisabled = Object.keys(g_Mods).filter(folder => g_ModsEnabled.indexOf(folder) == -1);
@@ -310,7 +356,14 @@
{
let guiObject = Engine.GetGUIObjectByName("message");
- for (let dependency of g_Mods[folder].dependencies)
+ if (!g_Mods[folder])
+ {
+ guiObject.caption = coloredText(
+ sprintf(translate('Mod does not extist')),
+ g_ColorDependenciesNotMet);
+ return false;
+ }
+ for (let dependency of getMod(folder).dependencies)
{
if (isDependencyMet(dependency))
continue;
@@ -380,11 +433,11 @@
{
let dependencies = {};
for (let folder of g_ModsEnabled)
- dependencies[folder] = g_Mods[folder].dependencies.map(d => d.split(g_RegExpComparisonOperator)[0]);
+ dependencies[folder] = getMod(folder).dependencies.map(d => d.split(g_RegExpComparisonOperator)[0]);
g_ModsEnabled.sort((folder1, folder2) =>
- dependencies[folder1].indexOf(g_Mods[folder2].name) != -1 ? 1 :
- dependencies[folder2].indexOf(g_Mods[folder1].name) != -1 ? -1 : 0);
+ dependencies[folder1].indexOf(getMod(folder2).name) != -1 ? 1 :
+ dependencies[folder2].indexOf(getMod(folder1).name) != -1 ? -1 : 0);
g_ModsEnabledFiltered = displayModList("modsEnabledList", g_ModsEnabled);
}
@@ -414,8 +467,21 @@
Engine.GetGUIObjectByName("globalModDescription").caption =
listObject.list[listObject.selected] ?
- g_Mods[listObject.list[listObject.selected]].description :
+ getMod(listObject.list[listObject.selected]).description :
'[color="' + g_ColorNoModSelected + '"]' + translate("No mod has been selected.") + '[/color]';
+
+ if (!g_ModsEnabled.length)
+ {
+ if (!Engine.GetGUIObjectByName("startButton").hidden)
+ Engine.GetGUIObjectByName("message").caption = coloredText(translate('Enable at least 0ad mod and save configuration'), g_ColorDependenciesNotMet);
+ else
+ Engine.GetGUIObjectByName("message").caption = coloredText(translate('Enable at least 0ad mod'), g_ColorDependenciesNotMet);
+ }
+ if (!Engine.GetGUIObjectByName("startButton").hidden)
+ Engine.GetGUIObjectByName("startButton").enabled = g_ModsEnabled.length;
+ if (!Engine.GetGUIObjectByName("startModsButton").hidden)
+ Engine.GetGUIObjectByName("startModsButton").enabled = g_ModsEnabled.length;
+
}
/**
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();
+
+
+ Start
+ startMods();
+
Index: binaries/data/mods/mod/gui/page_incompatible_mods.xml
===================================================================
--- /dev/null
+++ binaries/data/mods/mod/gui/page_incompatible_mods.xml
@@ -0,0 +1,9 @@
+
+
+ common/modern/setup.xml
+ common/modern/styles.xml
+ common/modern/sprites.xml
+
+ modmod/styles.xml
+ incompatible_mods/incompatible_mods.xml
+
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;
@@ -694,6 +695,7 @@
// Do not install mods again in case of restart (typically from the mod selector)
modsToInstall.clear();
+ Mod::ClearIncompatibleMods();
Shutdown(0);
MainControllerShutdown();
Index: source/ps/GameSetup/GameSetup.cpp
===================================================================
--- source/ps/GameSetup/GameSetup.cpp
+++ source/ps/GameSetup/GameSetup.cpp
@@ -372,36 +372,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";
@@ -460,7 +430,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"/"");
@@ -871,6 +841,31 @@
*/
bool AutostartVisualReplay(const std::string& replayFile);
+bool EnableModsOrSetDefault(const CmdLineArgs& args, int flags, const std::vector& mods, bool fromConfig)
+{
+ ScriptInterface scriptInterface("Engine", "CheckAndEnableMods", g_ScriptContext);
+ if (Mod::CheckAndEnableMods(scriptInterface, mods))
+ return true;
+ // Here we refuse to start as there is no gui anyway
+ if (args.Has("autostart-nonvisual"))
+ {
+ if (fromConfig)
+ LOGERROR("Mods defined in config file are not compatible.");
+ else
+ LOGERROR("Trying to start with incompatible mods.");
+ return false;
+ }
+ // When mods are incompatible, we enforce default ones so user is able
+ // to start the game without wall of error strings
+ if (!fromConfig)
+ LOGERROR("Trying to start with incompatible mods. Setting default mods.");
+ else
+ LOGERROR("Trying to start with incompatible mods.");
+ Mod::SetDefaultMods(args, flags);
+ RestartEngine();
+ return false;
+}
+
bool Init(const CmdLineArgs& args, int flags)
{
h_mgr_init();
@@ -931,21 +926,27 @@
// 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);
-
- // Abort init and restart
- RestartEngine();
- return false;
+ 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 (!EnableModsOrSetDefault(args, flags, mods, true))
+ return false;
+
+ RestartEngine();
+ return false;
+ }
}
}
+ else if (!EnableModsOrSetDefault(args, flags, g_modsLoaded, false))
+ return false;
new L10n;
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,9 @@
namespace Mod
{
JS::Value GetAvailableMods(const ScriptInterface& scriptInterface);
-
+ const std::vector& GetEnabledMods();
+ const std::vector& GetIncompatibleMods();
+ const std::vector& GetFailedMods();
/**
* This reads the version numbers from the launched mods.
* It caches the result, since the reading of zip files is slow and
@@ -39,6 +41,13 @@
*/
void CacheEnabledModVersions(const shared_ptr& scriptContext);
+ const std::vector& GetModsFromArguments(const CmdLineArgs& args, int flags);
+ bool AreModsCompatible(const ScriptInterface& scriptInterface, const std::vector& mods, const JS::RootedValue& availableMods);
+ bool CheckAndEnableMods(const ScriptInterface& scriptInterface, const std::vector& mods);
+ bool CompareVersionStrings(const CStr& required, const CStr& op, const CStr& version);
+ void SetDefaultMods(const CmdLineArgs& args, int flags);
+ void ClearIncompatibleMods();
+
/**
* 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,7 +28,14 @@
#include "ps/Pyrogenesis.h"
#include "scriptinterface/ScriptInterface.h"
+#include
+#include
+#include
+#include
+
std::vector g_modsLoaded;
+std::vector g_incompatibleMods;
+std::vector g_failedMods;
std::vector> g_LoadedModVersions;
@@ -103,6 +108,21 @@
return JS::ObjectValue(*obj);
}
+const std::vector& Mod::GetEnabledMods()
+{
+ return g_modsLoaded;
+}
+
+const std::vector& Mod::GetIncompatibleMods()
+{
+ return g_incompatibleMods;
+}
+
+const std::vector& Mod::GetFailedMods()
+{
+ return g_failedMods;
+}
+
void Mod::CacheEnabledModVersions(const shared_ptr& scriptContext)
{
ScriptInterface scriptInterface("Engine", "CacheEnabledModVersions", scriptContext);
@@ -127,6 +147,187 @@
}
}
+const std::vector& Mod::GetModsFromArguments(const CmdLineArgs& args, int flags)
+{
+ const bool initMods = (flags & INIT_MODS) == INIT_MODS;
+ const bool addUser = !InDevelopmentCopy() && !args.Has("noUserMod");
+ const bool addPublic = (flags & INIT_MODS_PUBLIC) == INIT_MODS_PUBLIC;
+
+ if (!initMods)
+ {
+ // Add the user mod if it should be present
+ if (addUser && (g_modsLoaded.empty() || g_modsLoaded.back() != "user"))
+ g_modsLoaded.push_back("user");
+
+ return g_modsLoaded;
+ }
+
+ g_modsLoaded = args.GetMultiple("mod");
+
+ if (addPublic)
+ 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 (addUser)
+ g_modsLoaded.push_back("user");
+
+ return g_modsLoaded;
+}
+
+void Mod::SetDefaultMods(const CmdLineArgs& args, int flags)
+{
+ const bool addUser = !InDevelopmentCopy() && !args.Has("noUserMod");
+
+ g_modsLoaded.clear();
+
+ 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 (addUser)
+ g_modsLoaded.push_back("user");
+}
+
+void Mod::ClearIncompatibleMods()
+{
+ g_incompatibleMods.clear();
+ g_failedMods.clear();
+}
+
+bool Mod::CheckAndEnableMods(const ScriptInterface& scriptInterface, const std::vector& mods)
+{
+ ScriptRequest rq(scriptInterface);
+
+ JS::RootedValue availableMods(rq.cx, GetAvailableMods(scriptInterface));
+ if (!AreModsCompatible(scriptInterface, mods, availableMods))
+ {
+ g_failedMods = mods;
+ return false;
+ }
+ g_modsLoaded = mods;
+ return true;
+}
+
+bool Mod::AreModsCompatible(const ScriptInterface& scriptInterface, const std::vector& mods, const JS::RootedValue& availableMods)
+{
+ ScriptRequest rq(scriptInterface);
+ std::unordered_map> modDependencies;
+ std::unordered_map modNameVersions;
+ for (const CStr& mod : mods)
+ {
+ if (mod == "mod" || mod == "user")
+ continue;
+
+ JS::RootedValue modData(rq.cx);
+
+ // Requested mod is not available, fail
+ if (!scriptInterface.HasProperty(availableMods, mod.c_str()))
+ {
+ g_incompatibleMods.push_back(mod);
+ continue;
+ }
+ if (!scriptInterface.GetProperty(availableMods, mod.c_str(), &modData))
+ {
+ g_incompatibleMods.push_back(mod);
+ continue;
+ }
+
+ CStr dependencies;
+ CStr version;
+ CStr name;
+ scriptInterface.GetProperty(modData, "dependencies", dependencies);
+ scriptInterface.GetProperty(modData, "version", version);
+ scriptInterface.GetProperty(modData, "name", name);
+
+ modNameVersions.emplace(name, version);
+ std::vector deps;
+ boost::split(deps, dependencies, boost::is_any_of(","), boost::token_compress_on);
+ modDependencies.emplace(mod, deps);
+ }
+
+ static const std::vector toCheck = { "<=", ">=", "=", "<", ">" };
+ for (const CStr& mod : mods)
+ {
+ if (mod == "mod" || mod == "user")
+ continue;
+
+ const std::unordered_map>::iterator res = modDependencies.find(mod);
+ if (res == modDependencies.end())
+ continue;
+ const std::vector deps = res->second;
+ if (deps.empty())
+ continue;
+
+ for (const CStr& dep : deps)
+ {
+ if (dep.empty())
+ continue;
+ // 0ad<=0.0.24
+ for (const CStr& op : toCheck)
+ {
+ const int pos = dep.Find(op.c_str());
+ if (pos == -1)
+ continue;
+ //0ad
+ const CStr modToCheck = dep.substr(0, pos);
+ //0.0.24
+ const CStr versionToCheck = dep.substr(pos + op.size());
+ const std::unordered_map::iterator it = modNameVersions.find(modToCheck);
+ if (it == modNameVersions.end())
+ {
+ g_incompatibleMods.push_back(mod);
+ continue;
+ }
+ // 0.0.25(0ad) , <=, 0.0.24(required version)
+ if (!CompareVersionStrings(it->second, op, versionToCheck))
+ {
+ g_incompatibleMods.push_back(mod);
+ continue;
+ }
+ }
+ }
+
+ }
+
+ return g_incompatibleMods.empty();
+}
+
+bool Mod::CompareVersionStrings(const CStr& version, const CStr& op, const CStr& required)
+{
+ std::vector versionSplit;
+ std::vector requiredSplit;
+ static const std::string toIgnore = "-,_";
+ boost::split(versionSplit, version, boost::is_any_of(toIgnore), boost::token_compress_on);
+ boost::split(requiredSplit, required, boost::is_any_of(toIgnore), boost::token_compress_on);
+ boost::split(versionSplit, versionSplit[0], boost::is_any_of("."), boost::token_compress_on);
+ boost::split(requiredSplit, requiredSplit[0], boost::is_any_of("."), boost::token_compress_on);
+
+ const bool eq = op.Find("=") != -1;
+ const bool lt = op.Find("<") != -1;
+ const bool gt = op.Find(">") != -1;
+
+ const size_t min = std::min(versionSplit.size(), requiredSplit.size());
+
+ for (size_t i = 0; i < min; ++i)
+ {
+ const int diff = versionSplit[i].ToInt() - requiredSplit[i].ToInt();
+ if (gt && diff > 0 || lt && diff < 0)
+ return true;
+
+ if (gt && diff < 0 || lt && diff > 0 || eq && diff)
+ return false;
+ }
+
+ const size_t versionSize = versionSplit.size();
+ const size_t requiredSize = requiredSplit.size();
+ if (versionSize == requiredSize)
+ return eq;
+ return versionSize < requiredSize ? lt : gt;
+}
+
JS::Value Mod::GetLoadedModsWithVersions(const ScriptInterface& scriptInterface)
{
ScriptRequest rq(scriptInterface);
Index: source/ps/scripting/JSInterface_Mod.cpp
===================================================================
--- source/ps/scripting/JSInterface_Mod.cpp
+++ source/ps/scripting/JSInterface_Mod.cpp
@@ -27,36 +27,23 @@
namespace
{
-JS::Value GetEngineInfo(ScriptInterface::CmptPrivate* pCmptPrivate)
+bool SetModsAndRestartEngine(ScriptInterface::CmptPrivate* pCmptPrivate, const std::vector& mods)
{
- return Mod::GetEngineInfo(*(pCmptPrivate->pScriptInterface));
-}
+ Mod::ClearIncompatibleMods();
+ if (!Mod::CheckAndEnableMods(*(pCmptPrivate->pScriptInterface), mods))
+ return false;
-/**
- * Returns a JS object containing a listing of available mods that
- * have a modname.json file in their modname folder. The returned
- * object looks like { modname1: json1, modname2: json2, ... } where
- * jsonN is the content of the modnameN/modnameN.json file as a JS
- * object.
- *
- * @return JS object with available mods as the keys of the modname.json
- * properties.
- */
-JS::Value GetAvailableMods(ScriptInterface::CmptPrivate* pCmptPrivate)
-{
- return Mod::GetAvailableMods(*(pCmptPrivate->pScriptInterface));
-}
-
-void SetMods(const std::vector& mods)
-{
- g_modsLoaded = mods;
+ RestartEngine();
+ return true;
}
}
void JSI_Mod::RegisterScriptFunctions(const ScriptRequest& rq)
{
- ScriptFunction::Register<&GetEngineInfo>(rq, "GetEngineInfo");
- ScriptFunction::Register<&GetAvailableMods>(rq, "GetAvailableMods");
- ScriptFunction::Register<&RestartEngine>(rq, "RestartEngine");
- ScriptFunction::Register<&SetMods>(rq, "SetMods");
+ ScriptFunction::Register<&Mod::GetEngineInfo>(rq, "GetEngineInfo");
+ ScriptFunction::Register<&Mod::GetAvailableMods>(rq, "GetAvailableMods");
+ ScriptFunction::Register<&Mod::GetEnabledMods>(rq, "GetEnabledMods");
+ ScriptFunction::Register<&Mod::GetIncompatibleMods>(rq, "GetIncompatibleMods");
+ ScriptFunction::Register<&Mod::GetFailedMods>(rq, "GetFailedMods");
+ ScriptFunction::Register<&SetModsAndRestartEngine>(rq, "SetModsAndRestartEngine");
}