Ticket #4027: 4027_mod_installation.patch

File 4027_mod_installation.patch, 7.1 KB (added by Vladislav Belov, 7 years ago)

Added the basic checks, windows mod.json, additional directory

  • source/main.cpp

     
    4949#include "ps/Globals.h"
    5050#include "ps/Hotkey.h"
    5151#include "ps/Loader.h"
     52#include "ps/ModInstaller.h"
    5253#include "ps/Profile.h"
    5354#include "ps/Profiler2.h"
    5455#include "ps/Pyrogenesis.h"
     
    443444            return;
    444445        }
    445446    }
     447   
     448    const bool isModInstallation = args.Has("install-mod");
     449    const OsPath modPath(isModInstallation ? args.Get("install-mod") : "");
    446450
     451    if (isModInstallation)
     452    {
     453        if (!FileExists(modPath))
     454        {
     455            debug_printf("ERROR: The mod file '%s' does not exist!\n", modPath.string8().c_str());
     456            return;
     457        }
     458        if (DirectoryExists(modPath))
     459        {
     460            debug_printf("ERROR: The mod file '%s' is a directory!\n", modPath.string8().c_str());
     461            return;
     462        }
     463        if (modPath.Basename().empty())
     464        {
     465            debug_printf("ERROR: The name of the mod file '%s' is empty!\n", modPath.string8().c_str());
     466            return;
     467        }
     468    }
     469
    447470    // We need to initialize SpiderMonkey and libxml2 in the main thread before
    448471    // any thread uses them. So initialize them here before we might run Atlas.
    449472    ScriptEngine scriptEngine;
     
    483506        CXeromyces::Terminate();
    484507        return;
    485508    }
     509   
     510    if (isModInstallation)
     511    {
     512        Paths paths(args);
     513       
     514        CModInstaller installer(paths.UserData() / "mods", paths.Cache());
    486515
     516        // Creates a directory with the name extracted from a `mod.json`
     517        installer.Install(modPath);
     518
     519        CXeromyces::Terminate();
     520        return;
     521    }
     522
    487523    // run in archive-building mode if requested
    488524    if (args.Has("archivebuild"))
    489525    {
  • source/ps/ModInstaller.cpp

     
     1/* Copyright (C) 2016 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 "ModInstaller.h"
     21
     22#include "lib/file/vfs/vfs_util.h"
     23#include "ps/Filesystem.h"
     24#include "ps/XML/Xeromyces.h"
     25
     26#include <boost/filesystem/operations.hpp>
     27#include <fstream>
     28
     29CModInstaller::CModInstaller(const OsPath& modsdir, const OsPath& tempdir) :
     30    m_ModsDir(modsdir), m_TempDir(tempdir / "_modscache"), m_CacheDir("cache/")
     31{
     32    m_VFS = CreateVfs(16 * MiB);
     33
     34    CreateDirectories(m_TempDir, 0700);
     35
     36    const int runtimeSize = 8 * MiB;
     37    const int heapGrowthBytesGCTrigger = 1 * MiB;
     38    m_ScriptRuntime = ScriptInterface::CreateRuntime(std::shared_ptr<ScriptRuntime>(), runtimeSize, heapGrowthBytesGCTrigger);
     39}
     40
     41CModInstaller::~CModInstaller()
     42{
     43    m_VFS.reset();
     44
     45    m_ScriptRuntime.reset();
     46
     47    DeleteDirectory(m_TempDir);
     48}
     49
     50void CModInstaller::Install(const OsPath& mod)
     51{
     52#define BOOST_WARN_IF_FAIL(expression) try { (expression); } catch (boost::filesystem::filesystem_error& ex) { debug_printf("%s", ex.what()); }
     53
     54    const OsPath modTemp = m_TempDir / mod.Basename() / mod.Filename().ChangeExtension(L".zip");
     55    CreateDirectories(modTemp.Parent(), 0700);
     56
     57    BOOST_WARN_IF_FAIL(boost::filesystem::copy_file(mod.string8(), modTemp.string8(), boost::filesystem::copy_option::overwrite_if_exists));
     58   
     59    // Load the mod to VFS
     60    if (m_VFS->Mount(m_CacheDir, m_TempDir / "") != INFO::OK)
     61        return;
     62    CVFSFile modinfo;
     63    PSRETURN modinfo_status = modinfo.Load(m_VFS, m_CacheDir / modTemp.Basename() / "mod.json", false);
     64    m_VFS->Clear();
     65    if (modinfo_status != PSRETURN_OK)
     66        return;
     67
     68    // Extract the name of the mod
     69    ScriptInterface scriptInterface("Engine", "ModInstaller", m_ScriptRuntime);
     70    JSContext* cx = scriptInterface.GetContext();
     71    JS::RootedValue json_val(cx);
     72    if (!scriptInterface.ParseJSON(modinfo.GetAsString(), &json_val))
     73        return;
     74    JS::RootedObject json_obj(cx, json_val.toObjectOrNull());
     75    JS::RootedValue name_val(cx);
     76    if (!JS_GetProperty(cx, json_obj, "name", &name_val))
     77        return;
     78    std::string modName;
     79    ScriptInterface::FromJSVal(cx, name_val, modName);
     80    if (modName.empty())
     81        return;
     82
     83    const OsPath modDir = m_ModsDir / modName;
     84    const OsPath modPath = modDir / (modName + ".zip");
     85   
     86    // Create a directory with the next structure:
     87    //   mod-name/
     88    //   +mod-name.zip
     89    CreateDirectories(modDir, 0700);
     90    BOOST_WARN_IF_FAIL(boost::filesystem::rename(modTemp.string8(), modPath.string8()));
     91    DeleteDirectory(modTemp.Parent());
     92
     93#ifdef OS_WIN
     94    std::ofstream mod_json((modDir / "mod.json").string8());
     95    if (mod_json.good())
     96    {
     97        mod_json << modinfo.GetAsString();
     98        mod_json.close();
     99    }
     100#endif
     101   
     102    // Remove the original file
     103    BOOST_WARN_IF_FAIL(boost::filesystem::remove(mod.string8()));
     104#undef BOOST_WARN_IF_FAIL
     105}
  • source/ps/ModInstaller.h

     
     1/* Copyright (C) 2016 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#ifndef INCLUDED_MODINSTALLER
     19#define INCLUDED_MODINSTALLER
     20
     21#include "lib/file/vfs/vfs.h"
     22#include "scriptinterface/ScriptInterface.h"
     23
     24/**
     25 * Install a mod into the mods directory.
     26 */
     27class CModInstaller
     28{
     29public:
     30    /**
     31     * Initialise the mod installer for processing the given mod.
     32     *
     33     * @param modsdir path to the data directory, containing mods
     34     * @param tempdir path to a writable directory for temporary files
     35     */
     36    CModInstaller(const OsPath& modsdir, const OsPath& tempdir);
     37
     38    ~CModInstaller();
     39
     40    /**
     41     * Do all the processing and unpacking.
     42     * @param mod path of .pyromod file of mod
     43     */
     44    void Install(const OsPath& mod);
     45
     46private:
     47
     48    PIVFS m_VFS;
     49    OsPath m_ModsDir;
     50    OsPath m_TempDir;
     51    VfsPath m_CacheDir;
     52
     53    std::shared_ptr<ScriptRuntime> m_ScriptRuntime;
     54};
     55
     56#endif // INCLUDED_MODINSTALLER