Index: source/ps/GameSetup/GameSetup.h =================================================================== --- source/ps/GameSetup/GameSetup.h +++ source/ps/GameSetup/GameSetup.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Wildfire Games. +/* Copyright (C) 2018 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -79,6 +79,11 @@ 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. + * Make sure to call CacheEnabledModVersions after every call to this. + */ extern void MountMods(const Paths& paths, const std::vector& mods); /** * Returns true if successful, false if mods changed and restart_engine was called. Index: source/ps/GameSetup/GameSetup.cpp =================================================================== --- source/ps/GameSetup/GameSetup.cpp +++ source/ps/GameSetup/GameSetup.cpp @@ -80,6 +80,7 @@ #include "scriptinterface/ScriptInterface.h" #include "scriptinterface/ScriptStats.h" #include "scriptinterface/ScriptConversions.h" +#include "scriptinterface/ScriptRuntime.h" #include "simulation2/Simulation2.h" #include "lobby/IXmppClient.h" #include "soundmanager/scripting/JSInterface_Sound.h" @@ -922,6 +923,8 @@ const int heapGrowthBytesGCTrigger = 20 * 1024 * 1024; g_ScriptRuntime = ScriptInterface::CreateRuntime(shared_ptr(), runtimeSize, heapGrowthBytesGCTrigger); + Mod::CacheEnabledModVersions(g_ScriptRuntime); + // Special command-line mode to dump the entity schemas instead of running the game. // (This must be done after loading VFS etc, but should be done before wasting time // on anything else.) Index: source/ps/Mod.h =================================================================== --- source/ps/Mod.h +++ source/ps/Mod.h @@ -30,6 +30,14 @@ JS::Value GetAvailableMods(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 + * JS pages can request the version numbers too often easily. + * Make sure this is called after each MountMods call. + */ + void CacheEnabledModVersions(shared_ptr scriptRuntime); + + /** * 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 @@ -31,6 +31,8 @@ std::vector g_modsLoaded; +std::vector> g_LoadedModVersions; + CmdLineArgs g_args; JS::Value Mod::GetAvailableMods(const ScriptInterface& scriptInterface) @@ -101,29 +103,38 @@ return JS::ObjectValue(*obj); } -JS::Value Mod::GetLoadedModsWithVersions(const ScriptInterface& scriptInterface) +void Mod::CacheEnabledModVersions(shared_ptr scriptRuntime) { + ScriptInterface scriptInterface("Engine", "CacheEnabledModVersions", scriptRuntime); JSContext* cx = scriptInterface.GetContext(); JSAutoRequest rq(cx); JS::RootedValue availableMods(cx, GetAvailableMods(scriptInterface)); - JS::RootedValue ret(cx, JS::ObjectValue(*JS_NewArrayObject(cx, 0))); + g_LoadedModVersions.clear(); - // Index of the created array - size_t j = 0; - for (size_t i = 0; i < g_modsLoaded.size(); ++i) + for (const CStr& mod : g_modsLoaded) { // Ignore user and mod mod as they are irrelevant for compatibility checks - if (g_modsLoaded[i] == "mod" || g_modsLoaded[i] == "user") + if (mod == "mod" || mod == "user") continue; + CStr version; JS::RootedValue modData(cx); - if (scriptInterface.GetProperty(availableMods, g_modsLoaded[i].c_str(), &modData)) + if (scriptInterface.GetProperty(availableMods, mod.c_str(), &modData)) scriptInterface.GetProperty(modData, "version", version); - scriptInterface.SetPropertyInt(ret, j++, std::vector{g_modsLoaded[i], version}); + + g_LoadedModVersions.push_back({mod, version}); } - return ret; +} + +JS::Value Mod::GetLoadedModsWithVersions(const ScriptInterface& scriptInterface) +{ + JSContext* cx = scriptInterface.GetContext(); + JSAutoRequest rq(cx); + JS::RootedValue returnValue(cx); + scriptInterface.ToJSVal(cx, &returnValue, g_LoadedModVersions); + return returnValue; } JS::Value Mod::GetEngineInfo(const ScriptInterface& scriptInterface) Index: source/ps/Replay.cpp =================================================================== --- source/ps/Replay.cpp +++ source/ps/Replay.cpp @@ -179,6 +179,8 @@ const int heapGrowthBytesGCTrigger = 20 * 1024 * 1024; g_ScriptRuntime = ScriptInterface::CreateRuntime(shared_ptr(), runtimeSize, heapGrowthBytesGCTrigger); + Mod::CacheEnabledModVersions(g_ScriptRuntime); + g_Game = new CGame(true, false); if (serializationtest) g_Game->GetSimulation2()->EnableSerializationTest();