Add a mod installer, fixes #4027.
pyrogenesis can now take a zip file (rename it to .pyromod for direct
file association following 943a61e4ea
) and install it. It then starts
the mod selector.
Patch by vladislavbelov, with contributions from Imarok, elexis and
myself.
Differential Revision: https://code.wildfiregames.com/D1142
This was SVN commit r21726.
This commit is contained in:
parent
3eaaddf3ef
commit
404e1a9a4a
@ -48,17 +48,33 @@ var g_Mods = {};
|
||||
var g_ModsEnabled = [];
|
||||
var g_ModsDisabled = [];
|
||||
|
||||
/**
|
||||
* Name of the mods installed by the ModInstaller.
|
||||
*/
|
||||
var g_InstalledMods;
|
||||
|
||||
var g_ColorNoModSelected = "255 255 100";
|
||||
var g_ColorDependenciesMet = "100 255 100";
|
||||
var g_ColorDependenciesNotMet = "255 100 100";
|
||||
|
||||
function init(data)
|
||||
function init(data, hotloadData)
|
||||
{
|
||||
g_InstalledMods = data && data.installedMods || hotloadData && hotloadData.installedMods || [];
|
||||
initMods();
|
||||
initGUIButtons(data);
|
||||
}
|
||||
|
||||
function initMods()
|
||||
{
|
||||
loadMods();
|
||||
loadEnabledMods();
|
||||
validateMods();
|
||||
initGUIFilters();
|
||||
initGUIButtons(data);
|
||||
}
|
||||
|
||||
function getHotloadData()
|
||||
{
|
||||
return { "installedMods": g_InstalledMods };
|
||||
}
|
||||
|
||||
function loadMods()
|
||||
@ -129,7 +145,7 @@ function displayModList(listObjectName, folders)
|
||||
|
||||
folders = folders.filter(filterMod);
|
||||
|
||||
listObject.list_name = folders.map(folder => g_Mods[folder].name);
|
||||
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 || "");
|
||||
|
@ -51,6 +51,9 @@ Configuration:
|
||||
-xres=N set screen X resolution to 'N'
|
||||
-yres=N set screen Y resolution to 'N'
|
||||
|
||||
Installing mods:
|
||||
PATHS install mods located at PATHS. For instance: "./pyrogenesis mod1.pyromod mod2.zip"
|
||||
|
||||
Advanced / diagnostic:
|
||||
-version print the version of the engine and exit
|
||||
-dumpSchema creates a file entity.rng in the working directory, containing
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2016 Wildfire Games.
|
||||
/* Copyright (C) 2018 Wildfire Games.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
@ -191,3 +191,25 @@ Status DeleteDirectory(const OsPath& path)
|
||||
|
||||
return INFO::OK;
|
||||
}
|
||||
|
||||
|
||||
Status CopyFile(const OsPath& path, const OsPath& newPath, bool override_if_exists/* = false*/)
|
||||
{
|
||||
if(path.empty())
|
||||
return INFO::OK;
|
||||
|
||||
try
|
||||
{
|
||||
if(override_if_exists)
|
||||
fs::copy_file(path.string8(), newPath.string8(), boost::filesystem::copy_option::overwrite_if_exists);
|
||||
else
|
||||
fs::copy_file(path.string8(), newPath.string8());
|
||||
}
|
||||
catch(fs::filesystem_error& err)
|
||||
{
|
||||
debug_printf("CopyFile: failed to copy %s to %s.\n%s\n", path.string8().c_str(), path.string8().c_str(), err.what());
|
||||
return ERR::EXCEPTION;
|
||||
}
|
||||
|
||||
return INFO::OK;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2016 Wildfire Games.
|
||||
/* Copyright (C) 2018 Wildfire Games.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
@ -85,4 +85,6 @@ LIB_API Status CreateDirectories(const OsPath& path, mode_t mode, bool breakpoin
|
||||
|
||||
LIB_API Status DeleteDirectory(const OsPath& dirPath);
|
||||
|
||||
LIB_API Status CopyFile(const OsPath& path, const OsPath& newPath, bool override_if_exists = false);
|
||||
|
||||
#endif // #ifndef INCLUDED_FILE_SYSTEM
|
||||
|
@ -51,6 +51,7 @@ that of Atlas depending on commandline parameters.
|
||||
#include "ps/Globals.h"
|
||||
#include "ps/Hotkey.h"
|
||||
#include "ps/Loader.h"
|
||||
#include "ps/ModInstaller.h"
|
||||
#include "ps/Profile.h"
|
||||
#include "ps/Profiler2.h"
|
||||
#include "ps/Pyrogenesis.h"
|
||||
@ -495,6 +496,28 @@ static void RunGameOrAtlas(int argc, const char* argv[])
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<OsPath> modsToInstall;
|
||||
for (const CStr& arg : args.GetArgsWithoutName())
|
||||
{
|
||||
const OsPath modPath(arg);
|
||||
if (!CModInstaller::IsDefaultModExtension(modPath.Extension()))
|
||||
{
|
||||
debug_printf("Skipping file '%s' which does not have a mod file extension.\n", modPath.string8().c_str());
|
||||
continue;
|
||||
}
|
||||
if (!FileExists(modPath))
|
||||
{
|
||||
debug_printf("ERROR: The mod file '%s' does not exist!\n", modPath.string8().c_str());
|
||||
continue;
|
||||
}
|
||||
if (DirectoryExists(modPath))
|
||||
{
|
||||
debug_printf("ERROR: The mod file '%s' is a directory!\n", modPath.string8().c_str());
|
||||
continue;
|
||||
}
|
||||
modsToInstall.emplace_back(std::move(modPath));
|
||||
}
|
||||
|
||||
// We need to initialize SpiderMonkey and libxml2 in the main thread before
|
||||
// any thread uses them. So initialize them here before we might run Atlas.
|
||||
ScriptEngine scriptEngine;
|
||||
@ -577,6 +600,19 @@ static void RunGameOrAtlas(int argc, const char* argv[])
|
||||
continue;
|
||||
}
|
||||
|
||||
std::vector<CStr> installedMods;
|
||||
if (!modsToInstall.empty())
|
||||
{
|
||||
Paths paths(args);
|
||||
CModInstaller installer(paths.UserData() / "mods", paths.Cache());
|
||||
|
||||
// Install the mods without deleting the pyromod files
|
||||
for (const OsPath& modPath : modsToInstall)
|
||||
installer.Install(modPath, g_ScriptRuntime, false);
|
||||
|
||||
installedMods = installer.GetInstalledMods();
|
||||
}
|
||||
|
||||
if (isNonVisual)
|
||||
{
|
||||
InitNonVisual(args);
|
||||
@ -585,12 +621,15 @@ static void RunGameOrAtlas(int argc, const char* argv[])
|
||||
}
|
||||
else
|
||||
{
|
||||
InitGraphics(args, 0);
|
||||
InitGraphics(args, 0, installedMods);
|
||||
MainControllerInit();
|
||||
while (!quit)
|
||||
Frame();
|
||||
}
|
||||
|
||||
// Do not install mods again in case of restart (typically from the mod selector)
|
||||
modsToInstall.clear();
|
||||
|
||||
Shutdown(0);
|
||||
MainControllerShutdown();
|
||||
flags &= ~INIT_MODS;
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2015 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
|
||||
@ -20,6 +20,26 @@
|
||||
|
||||
#include "lib/sysdep/sysdep.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
// Simple matcher for elements of the arguments container.
|
||||
class IsKeyEqualTo
|
||||
{
|
||||
public:
|
||||
IsKeyEqualTo(const CStr& value) : m_Value(value) {}
|
||||
|
||||
bool operator()(const std::pair<CStr, CStr>& p) const
|
||||
{
|
||||
return p.first == m_Value;
|
||||
}
|
||||
|
||||
private:
|
||||
const CStr m_Value;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
CmdLineArgs::CmdLineArgs(int argc, const char* argv[])
|
||||
{
|
||||
if (argc >= 1)
|
||||
@ -35,7 +55,10 @@ CmdLineArgs::CmdLineArgs(int argc, const char* argv[])
|
||||
{
|
||||
// Only accept arguments that start with '-'
|
||||
if (argv[i][0] != '-')
|
||||
{
|
||||
m_ArgsWithoutName.emplace_back(argv[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Allow -arg and --arg
|
||||
char offset = argv[i][1] == '-' ? 2 : 1;
|
||||
@ -55,34 +78,26 @@ CmdLineArgs::CmdLineArgs(int argc, const char* argv[])
|
||||
}
|
||||
}
|
||||
|
||||
bool CmdLineArgs::Has(const char* name) const
|
||||
bool CmdLineArgs::Has(const CStr& name) const
|
||||
{
|
||||
return m_Args.end() != find_if(m_Args.begin(), m_Args.end(),
|
||||
[&name](const std::pair<CStr, CStr>& a) { return a.first == name; });
|
||||
return std::any_of(m_Args.begin(), m_Args.end(), IsKeyEqualTo(name));
|
||||
}
|
||||
|
||||
CStr CmdLineArgs::Get(const char* name) const
|
||||
CStr CmdLineArgs::Get(const CStr& name) const
|
||||
{
|
||||
ArgsT::const_iterator it = find_if(m_Args.begin(), m_Args.end(),
|
||||
[&name](const std::pair<CStr, CStr>& a) { return a.first == name; });
|
||||
if (it != m_Args.end())
|
||||
return it->second;
|
||||
else
|
||||
return "";
|
||||
ArgsT::const_iterator it = std::find_if(m_Args.begin(), m_Args.end(), IsKeyEqualTo(name));
|
||||
return it != m_Args.end() ? it->second : "";
|
||||
}
|
||||
|
||||
std::vector<CStr> CmdLineArgs::GetMultiple(const char* name) const
|
||||
std::vector<CStr> CmdLineArgs::GetMultiple(const CStr& name) const
|
||||
{
|
||||
std::vector<CStr> values;
|
||||
ArgsT::const_iterator it = m_Args.begin();
|
||||
while (1)
|
||||
while ((it = std::find_if(it, m_Args.end(), IsKeyEqualTo(name))) != m_Args.end())
|
||||
{
|
||||
it = find_if(it, m_Args.end(),
|
||||
[&name](const std::pair<CStr, CStr>& a) { return a.first == name; });
|
||||
if (it == m_Args.end())
|
||||
break;
|
||||
values.push_back(it->second);
|
||||
++it; // start searching from the next one in the next iteration
|
||||
// Start searching from the next one in the next iteration
|
||||
++it;
|
||||
}
|
||||
return values;
|
||||
}
|
||||
@ -91,3 +106,8 @@ OsPath CmdLineArgs::GetArg0() const
|
||||
{
|
||||
return m_Arg0;
|
||||
}
|
||||
|
||||
std::vector<CStr> CmdLineArgs::GetArgsWithoutName() const
|
||||
{
|
||||
return m_ArgsWithoutName;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2009 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
|
||||
@ -40,20 +40,20 @@ public:
|
||||
* Test whether the given name was specified, as either <tt>-name</tt> or
|
||||
* <tt>-name=value</tt>
|
||||
*/
|
||||
bool Has(const char* name) const;
|
||||
bool Has(const CStr& name) const;
|
||||
|
||||
/**
|
||||
* Get the value of the named parameter. If it was not specified, returns
|
||||
* the empty string. If it was specified multiple times, returns the value
|
||||
* from the first occurrence.
|
||||
*/
|
||||
CStr Get(const char* name) const;
|
||||
CStr Get(const CStr& name) const;
|
||||
|
||||
/**
|
||||
* Get all the values given to the named parameter. Returns values in the
|
||||
* same order as they were given in argv.
|
||||
*/
|
||||
std::vector<CStr> GetMultiple(const char* name) const;
|
||||
std::vector<CStr> GetMultiple(const CStr& name) const;
|
||||
|
||||
/**
|
||||
* Get the value of argv[0], which is typically meant to be the name/path of
|
||||
@ -61,10 +61,16 @@ public:
|
||||
*/
|
||||
OsPath GetArg0() const;
|
||||
|
||||
/**
|
||||
* Returns all arguments that don't have a name (string started with '-').
|
||||
*/
|
||||
std::vector<CStr> GetArgsWithoutName() const;
|
||||
|
||||
private:
|
||||
typedef std::vector<std::pair<CStr, CStr> > ArgsT;
|
||||
ArgsT m_Args;
|
||||
OsPath m_Arg0;
|
||||
std::vector<CStr> m_ArgsWithoutName;
|
||||
};
|
||||
|
||||
#endif // INCLUDED_CMDLINEARGS
|
||||
|
@ -973,7 +973,7 @@ bool Init(const CmdLineArgs& args, int flags)
|
||||
return true;
|
||||
}
|
||||
|
||||
void InitGraphics(const CmdLineArgs& args, int flags)
|
||||
void InitGraphics(const CmdLineArgs& args, int flags, const std::vector<CStr>& installedMods)
|
||||
{
|
||||
const bool setup_vmode = (flags & INIT_HAVE_VMODE) == 0;
|
||||
|
||||
@ -1077,8 +1077,10 @@ void InitGraphics(const CmdLineArgs& args, int flags)
|
||||
{
|
||||
scriptInterface->Eval("({})", &data);
|
||||
scriptInterface->SetProperty(data, "isStartup", true);
|
||||
if (!installedMods.empty())
|
||||
scriptInterface->SetProperty(data, "installedMods", installedMods);
|
||||
}
|
||||
InitPs(setup_gui, L"page_pregame.xml", g_GUI->GetScriptInterface().get(), data);
|
||||
InitPs(setup_gui, installedMods.empty() ? L"page_pregame.xml" : L"page_modmod.xml", g_GUI->GetScriptInterface().get(), data);
|
||||
}
|
||||
}
|
||||
catch (PSERROR_Game_World_MapLoadFailed& e)
|
||||
|
@ -85,7 +85,8 @@ extern void MountMods(const Paths& paths, const std::vector<CStr>& mods);
|
||||
* In the latter case the caller should call Shutdown() with SHUTDOWN_FROM_CONFIG.
|
||||
*/
|
||||
extern bool Init(const CmdLineArgs& args, int flags);
|
||||
extern void InitGraphics(const CmdLineArgs& args, int flags);
|
||||
extern void InitGraphics(const CmdLineArgs& args, int flags,
|
||||
const std::vector<CStr>& installedMods = std::vector<CStr>());
|
||||
extern void InitNonVisual(const CmdLineArgs& args);
|
||||
extern void Shutdown(int flags);
|
||||
extern void CancelLoad(const CStrW& message);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2011 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
|
||||
@ -34,8 +34,9 @@ public:
|
||||
|
||||
void test_get()
|
||||
{
|
||||
const char* argv[] = { "program", "-test1=", "-test2=x", "-test3=-y=y-", "-=z" };
|
||||
const char* argv[] = { "program", "-test1=", "--test2=x", "-test3=-y=y-", "-=z" };
|
||||
CmdLineArgs c(ARRAY_SIZE(argv), argv);
|
||||
TS_ASSERT(!c.Has("program"));
|
||||
TS_ASSERT_STR_EQUALS(c.Get("test0"), "");
|
||||
TS_ASSERT_STR_EQUALS(c.Get("test1"), "");
|
||||
TS_ASSERT_STR_EQUALS(c.Get("test2"), "x");
|
||||
@ -45,7 +46,7 @@ public:
|
||||
|
||||
void test_multiple()
|
||||
{
|
||||
const char* argv[] = { "program", "-test1=one", "-test1=two", "-test2=none", "-test1=three" };
|
||||
const char* argv[] = { "program", "-test1=one", "--test1=two", "-test2=none", "-test1=three" };
|
||||
CmdLineArgs c(ARRAY_SIZE(argv), argv);
|
||||
|
||||
TS_ASSERT_STR_EQUALS(c.Get("test1"), "one");
|
||||
@ -65,7 +66,9 @@ public:
|
||||
|
||||
void test_get_invalid()
|
||||
{
|
||||
const char* argv[] = { "-test1", "-test2", "test3", " -test4" };
|
||||
const char* argv[] = {
|
||||
"-test1", "--test2", "test3-", " -test4", "--", "-=="
|
||||
};
|
||||
CmdLineArgs c(ARRAY_SIZE(argv), argv);
|
||||
|
||||
TS_ASSERT(!c.Has("test1"));
|
||||
@ -91,4 +94,14 @@ public:
|
||||
TS_ASSERT_WSTR_EQUALS(c3.GetArg0().string(), L"ab/cd/ef/gh/../ij");
|
||||
#endif
|
||||
}
|
||||
|
||||
void test_get_without_names()
|
||||
{
|
||||
const char* argv[] = { "program", "test0", "-test1", "test2", "test3", "--test4=test5" };
|
||||
CmdLineArgs c(ARRAY_SIZE(argv), argv);
|
||||
TS_ASSERT(c.Has("test1"));
|
||||
TS_ASSERT_STR_EQUALS(c.Get("test4"), "test5");
|
||||
CStr expected_args[] = { "test0", "test2", "test3" };
|
||||
TS_ASSERT_VECTOR_EQUALS_ARRAY(c.GetArgsWithoutName(), expected_args);
|
||||
}
|
||||
};
|
||||
|
111
source/ps/ModInstaller.cpp
Normal file
111
source/ps/ModInstaller.cpp
Normal file
@ -0,0 +1,111 @@
|
||||
/* 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
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "ModInstaller.h"
|
||||
|
||||
#include "lib/file/vfs/vfs_util.h"
|
||||
#include "ps/Filesystem.h"
|
||||
#include "ps/XML/Xeromyces.h"
|
||||
|
||||
#include <fstream>
|
||||
|
||||
CModInstaller::CModInstaller(const OsPath& modsdir, const OsPath& tempdir) :
|
||||
m_ModsDir(modsdir), m_TempDir(tempdir / "_modscache"), m_CacheDir("cache/")
|
||||
{
|
||||
m_VFS = CreateVfs();
|
||||
CreateDirectories(m_TempDir, 0700);
|
||||
}
|
||||
|
||||
CModInstaller::~CModInstaller()
|
||||
{
|
||||
m_VFS.reset();
|
||||
DeleteDirectory(m_TempDir);
|
||||
}
|
||||
|
||||
CModInstaller::ModInstallationResult CModInstaller::Install(
|
||||
const OsPath& mod,
|
||||
const std::shared_ptr<ScriptRuntime>& scriptRuntime,
|
||||
bool deleteAfterInstall)
|
||||
{
|
||||
const OsPath modTemp = m_TempDir / mod.Basename() / mod.Filename().ChangeExtension(L".zip");
|
||||
CreateDirectories(modTemp.Parent(), 0700);
|
||||
|
||||
CopyFile(mod, modTemp, true);
|
||||
|
||||
// Load the mod to VFS
|
||||
if (m_VFS->Mount(m_CacheDir, m_TempDir / "") != INFO::OK)
|
||||
return FAIL_ON_VFS_MOUNT;
|
||||
CVFSFile modinfo;
|
||||
PSRETURN modinfo_status = modinfo.Load(m_VFS, m_CacheDir / modTemp.Basename() / "mod.json", false);
|
||||
m_VFS->Clear();
|
||||
if (modinfo_status != PSRETURN_OK)
|
||||
return FAIL_ON_MOD_LOAD;
|
||||
|
||||
// Extract the name of the mod
|
||||
ScriptInterface scriptInterface("Engine", "ModInstaller", scriptRuntime);
|
||||
JSContext* cx = scriptInterface.GetContext();
|
||||
JS::RootedValue json_val(cx);
|
||||
if (!scriptInterface.ParseJSON(modinfo.GetAsString(), &json_val))
|
||||
return FAIL_ON_PARSE_JSON;
|
||||
JS::RootedObject json_obj(cx, json_val.toObjectOrNull());
|
||||
JS::RootedValue name_val(cx);
|
||||
if (!JS_GetProperty(cx, json_obj, "name", &name_val))
|
||||
return FAIL_ON_EXTRACT_NAME;
|
||||
CStr modName;
|
||||
ScriptInterface::FromJSVal(cx, name_val, modName);
|
||||
if (modName.empty())
|
||||
return FAIL_ON_EXTRACT_NAME;
|
||||
|
||||
const OsPath modDir = m_ModsDir / modName;
|
||||
const OsPath modPath = modDir / (modName + ".zip");
|
||||
|
||||
// Create a directory with the following structure:
|
||||
// mod-name/
|
||||
// mod-name.zip
|
||||
CreateDirectories(modDir, 0700);
|
||||
if (wrename(modTemp, modPath) != 0)
|
||||
return FAIL_ON_MOD_MOVE;
|
||||
DeleteDirectory(modTemp.Parent());
|
||||
|
||||
#ifdef OS_WIN
|
||||
// On Windows, write the contents of mod.json to a separate file next to the archive:
|
||||
// mod-name/
|
||||
// mod-name.zip
|
||||
// mod.json
|
||||
std::ofstream mod_json((modDir / "mod.json").string8());
|
||||
if (mod_json.good())
|
||||
{
|
||||
mod_json << modinfo.GetAsString();
|
||||
mod_json.close();
|
||||
}
|
||||
#endif // OS_WIN
|
||||
|
||||
// Remove the original file if requested
|
||||
if (deleteAfterInstall)
|
||||
wunlink(mod);
|
||||
|
||||
m_InstalledMods.emplace_back(modName);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
const std::vector<CStr>& CModInstaller::GetInstalledMods() const
|
||||
{
|
||||
return m_InstalledMods;
|
||||
}
|
82
source/ps/ModInstaller.h
Normal file
82
source/ps/ModInstaller.h
Normal file
@ -0,0 +1,82 @@
|
||||
/* 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
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_MODINSTALLER
|
||||
#define INCLUDED_MODINSTALLER
|
||||
|
||||
#include "lib/file/vfs/vfs.h"
|
||||
#include "scriptinterface/ScriptInterface.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* Install a mod into the mods directory.
|
||||
*/
|
||||
class CModInstaller
|
||||
{
|
||||
public:
|
||||
enum ModInstallationResult
|
||||
{
|
||||
SUCCESS,
|
||||
FAIL_ON_VFS_MOUNT,
|
||||
FAIL_ON_MOD_LOAD,
|
||||
FAIL_ON_PARSE_JSON,
|
||||
FAIL_ON_EXTRACT_NAME,
|
||||
FAIL_ON_MOD_MOVE
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialise the mod installer for processing the given mod.
|
||||
*
|
||||
* @param modsdir path to the data directory that contains mods
|
||||
* @param tempdir path to a writable directory for temporary files
|
||||
*/
|
||||
CModInstaller(const OsPath& modsdir, const OsPath& tempdir);
|
||||
|
||||
~CModInstaller();
|
||||
|
||||
/**
|
||||
* Process and unpack the mod.
|
||||
* @param mod path of .pyromod/.zip file
|
||||
*/
|
||||
ModInstallationResult Install(
|
||||
const OsPath& mod,
|
||||
const std::shared_ptr<ScriptRuntime>& scriptRuntime,
|
||||
bool deleteAfterInstall);
|
||||
|
||||
/**
|
||||
* @return a list of all mods installed so far by this CModInstaller.
|
||||
*/
|
||||
const std::vector<CStr>& GetInstalledMods() const;
|
||||
|
||||
/**
|
||||
* @return whether the path has a mod-like extension.
|
||||
*/
|
||||
static bool IsDefaultModExtension(const Path& ext)
|
||||
{
|
||||
return ext == ".pyromod" || ext == ".zip";
|
||||
}
|
||||
|
||||
private:
|
||||
PIVFS m_VFS;
|
||||
OsPath m_ModsDir;
|
||||
OsPath m_TempDir;
|
||||
VfsPath m_CacheDir;
|
||||
std::vector<CStr> m_InstalledMods;
|
||||
};
|
||||
|
||||
#endif // INCLUDED_MODINSTALLER
|
@ -87,7 +87,7 @@ MESSAGEHANDLER(InitGraphics)
|
||||
|
||||
ogl_Init();
|
||||
|
||||
InitGraphics(g_AtlasGameLoop->args, g_InitFlags);
|
||||
InitGraphics(g_AtlasGameLoop->args, g_InitFlags, {});
|
||||
|
||||
#if OS_WIN
|
||||
// HACK (to stop things looking very ugly when scrolling) - should
|
||||
|
Loading…
Reference in New Issue
Block a user