LCOV - code coverage report
Current view: top level - source/ps/scripting - JSInterface_Mod.cpp (source / functions) Hit Total Coverage
Test: 0 A.D. test coverage report Lines: 10 85 11.8 %
Date: 2023-01-19 00:18:29 Functions: 3 17 17.6 %

          Line data    Source code
       1             : /* Copyright (C) 2021 Wildfire Games.
       2             :  * This file is part of 0 A.D.
       3             :  *
       4             :  * 0 A.D. is free software: you can redistribute it and/or modify
       5             :  * it under the terms of the GNU General Public License as published by
       6             :  * the Free Software Foundation, either version 2 of the License, or
       7             :  * (at your option) any later version.
       8             :  *
       9             :  * 0 A.D. is distributed in the hope that it will be useful,
      10             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12             :  * GNU General Public License for more details.
      13             :  *
      14             :  * You should have received a copy of the GNU General Public License
      15             :  * along with 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
      16             :  */
      17             : 
      18             : #include "precompiled.h"
      19             : 
      20             : #include "JSInterface_Mod.h"
      21             : 
      22             : #include "ps/Mod.h"
      23             : #include "ps/Pyrogenesis.h"
      24             : #include "scriptinterface/FunctionWrapper.h"
      25             : #include "scriptinterface/JSON.h"
      26             : #include "scriptinterface/ScriptConversions.h"
      27             : 
      28             : extern void RestartEngine();
      29             : 
      30             : // To avoid copying data needlessly in GetEngineInfo, implement a ToJSVal for pointer types.
      31             : using ModDataCPtr = const Mod::ModData*;
      32             : 
      33             : template<>
      34           0 : void Script::ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue ret, const ModDataCPtr& data)
      35             : {
      36           0 :     ret.set(Script::CreateObject(rq));
      37           0 :     Script::SetProperty(rq, ret, "mod", data->m_Pathname);
      38           0 :     Script::SetProperty(rq, ret, "name", data->m_Name);
      39           0 :     Script::SetProperty(rq, ret, "version", data->m_Version);
      40           0 :     Script::SetProperty(rq, ret, "ignoreInCompatibilityChecks", data->m_IgnoreInCompatibilityChecks);
      41           0 : }
      42             : 
      43             : // Required by JSVAL_VECTOR, but can't be implemented.
      44             : template<>
      45           0 : bool Script::FromJSVal(const ScriptRequest &, const JS::HandleValue, ModDataCPtr&)
      46             : {
      47           0 :     LOGERROR("Not implemented");
      48           0 :     return false;
      49             : }
      50             : 
      51           0 : JSVAL_VECTOR(const Mod::ModData*);
      52             : 
      53             : // Implement FromJSVal as a non-pointer type.
      54             : template<>
      55           0 : void Script::ToJSVal(const ScriptRequest& rq, JS::MutableHandleValue ret, const Mod::ModData& data)
      56             : {
      57           0 :     ret.set(Script::CreateObject(rq));
      58           0 :     Script::SetProperty(rq, ret, "mod", data.m_Pathname);
      59           0 :     Script::SetProperty(rq, ret, "name", data.m_Name);
      60           0 :     Script::SetProperty(rq, ret, "version", data.m_Version);
      61           0 :     Script::SetProperty(rq, ret, "ignoreInCompatibilityChecks", data.m_IgnoreInCompatibilityChecks);
      62           0 : }
      63             : 
      64             : template<>
      65           0 : bool Script::FromJSVal(const ScriptRequest& rq, const JS::HandleValue val, Mod::ModData& data)
      66             : {
      67             :     // To avoid errors & for convenience, some retro-compatibility when reading
      68             :     // TODO: remove this once we hit A26.
      69           0 :     JS::RootedObject obj(rq.cx, val.toObjectOrNull());
      70           0 :     bool isArray = false;
      71           0 :     if (JS::IsArray(rq.cx, obj, &isArray) && isArray)
      72             :     {
      73           0 :         if (!Script::GetPropertyInt(rq, val, 0, data.m_Pathname))
      74           0 :             return false;
      75           0 :         if (!Script::GetPropertyInt(rq, val, 1, data.m_Version))
      76           0 :             return false;
      77             :         // Set a sane default for this.
      78           0 :         data.m_Name = data.m_Pathname;
      79           0 :         return true;
      80             :     }
      81             : 
      82             :     // This property is not set in mod.json files, so don't fail if it's not there.
      83           0 :     if (Script::HasProperty(rq, val, "mod") && !Script::GetProperty(rq, val, "mod", data.m_Pathname))
      84           0 :         return false;
      85             : 
      86           0 :     if (!Script::GetProperty(rq, val, "version", data.m_Version))
      87           0 :         return false;
      88           0 :     if (!Script::GetProperty(rq, val, "name", data.m_Name))
      89           0 :         return false;
      90             : 
      91             :     // Optional - this makes the mod 'GUI-only'.
      92           0 :     if (Script::HasProperty(rq, val, "ignoreInCompatibilityChecks"))
      93             :     {
      94           0 :         if (!Script::GetProperty(rq, val, "ignoreInCompatibilityChecks", data.m_IgnoreInCompatibilityChecks))
      95           0 :             return false;
      96             :     }
      97             :     else
      98           0 :         data.m_IgnoreInCompatibilityChecks = false;
      99             : 
     100           0 :     return true;
     101             : }
     102             : 
     103           0 : JSVAL_VECTOR(Mod::ModData);
     104             : 
     105             : namespace JSI_Mod
     106             : {
     107           0 : Mod* ModGetter(const ScriptRequest&, JS::CallArgs&)
     108             : {
     109           0 :     return &g_Mods;
     110             : }
     111             : 
     112           0 : JS::Value GetEngineInfo(const ScriptInterface& scriptInterface)
     113             : {
     114           0 :     ScriptRequest rq(scriptInterface);
     115             : 
     116           0 :     JS::RootedValue mods(rq.cx);
     117           0 :     Script::ToJSVal(rq, &mods, g_Mods.GetEnabledModsData());
     118           0 :     JS::RootedValue metainfo(rq.cx);
     119             : 
     120           0 :     Script::CreateObject(
     121             :          rq,
     122             :          &metainfo,
     123             :          "engine_version", engine_version,
     124             :          "mods", mods);
     125             : 
     126           0 :     Script::FreezeObject(rq, metainfo, true);
     127             : 
     128           0 :     return metainfo;
     129             : }
     130             : 
     131           0 : JS::Value GetAvailableMods(const ScriptRequest& rq)
     132             : {
     133           0 :     JS::RootedValue ret(rq.cx, Script::CreateObject(rq));
     134           0 :     for (const Mod::ModData& data : g_Mods.GetAvailableMods())
     135             :     {
     136           0 :         JS::RootedValue json(rq.cx);
     137           0 :         if (!Script::ParseJSON(rq, data.m_Text, &json))
     138             :         {
     139           0 :             ScriptException::Raise(rq, "Error parsing mod.json of '%s'", data.m_Pathname.c_str());
     140           0 :             continue;
     141             :         }
     142           0 :         Script::SetProperty(rq, ret, data.m_Pathname.c_str(), json);
     143             :     }
     144           0 :     return ret.get();
     145             : }
     146             : 
     147           0 : bool AreModsPlayCompatible(const std::vector<Mod::ModData>& a, const std::vector<Mod::ModData>& b)
     148             : {
     149           0 :     std::vector<const Mod::ModData*> modsA, modsB;
     150           0 :     modsA.reserve(a.size());
     151           0 :     for (const Mod::ModData& mod : a)
     152           0 :         modsA.push_back(&mod);
     153           0 :     modsB.reserve(b.size());
     154           0 :     for (const Mod::ModData& mod : b)
     155           0 :         modsB.push_back(&mod);
     156           0 :     return Mod::AreModsPlayCompatible(modsA, modsB);
     157             : }
     158             : 
     159           0 : bool SetModsAndRestartEngine(const std::vector<CStr>& mods)
     160             : {
     161           0 :     if (!g_Mods.EnableMods(mods, false))
     162           0 :         return false;
     163             : 
     164           0 :     RestartEngine();
     165           0 :     return true;
     166             : }
     167             : 
     168           0 : bool HasIncompatibleMods()
     169             : {
     170           0 :     return g_Mods.GetIncompatibleMods().size() > 0;
     171             : }
     172             : 
     173          12 : void RegisterScriptFunctions(const ScriptRequest& rq)
     174             : {
     175          12 :     ScriptFunction::Register<GetEngineInfo>(rq, "GetEngineInfo");
     176          12 :     ScriptFunction::Register<GetAvailableMods>(rq, "GetAvailableMods");
     177          12 :     ScriptFunction::Register<&Mod::GetEnabledMods, ModGetter>(rq, "GetEnabledMods");
     178          12 :     ScriptFunction::Register<AreModsPlayCompatible>(rq, "AreModsPlayCompatible");
     179          12 :     ScriptFunction::Register<HasIncompatibleMods> (rq, "HasIncompatibleMods");
     180          12 :     ScriptFunction::Register<&Mod::GetIncompatibleMods, ModGetter>(rq, "GetIncompatibleMods");
     181          12 :     ScriptFunction::Register<&SetModsAndRestartEngine>(rq, "SetModsAndRestartEngine");
     182          12 : }
     183           3 : }

Generated by: LCOV version 1.13