Fix installers.

This commit is contained in:
Mikaël Capelle
2022-04-25 22:17:34 +02:00
parent 5ec456f880
commit 92a2429d58
6 changed files with 2124 additions and 1543 deletions
+1 -1
View File
@@ -153,7 +153,7 @@ QStringList ProxyPython::pluginList(const QDir& pluginPath) const
QString name = iter.next();
QFileInfo info = iter.fileInfo();
if (info.fileName() == "pyCfg.py") {
if (info.fileName() == "pyCfg.py" || info.fileName() == "installer_wizard") {
result.append(name);
}
+11 -1
View File
@@ -34,6 +34,7 @@
#include <ipluginfilemapper.h>
#include <iplugingame.h>
#include <iplugininstaller.h>
#include <iplugininstallersimple.h>
#include <ipluginlist.h>
#include <ipluginmodpage.h>
#include <ipluginpreview.h>
@@ -55,9 +56,12 @@ PYBIND11_MODULE(mobase, m)
//
mo2::python::add_basic_bindings(m);
mo2::python::add_wrapper_bindings(m);
mo2::python::add_plugins_bindings(m);
// game features must be added before plugins
mo2::python::add_game_feature_bindings(m);
mo2::python::add_plugins_bindings(m);
// widgets
//
py::module_ widgets(
@@ -96,6 +100,12 @@ PYBIND11_MODULE(mobase, m)
std::cout << fmt::format(" plugin {}: {} -> {}\n", i, (void*)qobjects[i],
(void*)plugin);
std::cout << fmt::format(" name: {}\n", plugin->name().toStdString());
std::cout << fmt::format(
" installer?: {}\n",
(void*)qobject_cast<IPluginInstaller*>(qobjects[i]));
std::cout << fmt::format(
" installer simple?: {}\n",
(void*)qobject_cast<IPluginInstallerSimple*>(qobjects[i]));
}
});
+94 -1
View File
@@ -8,12 +8,105 @@
#include "../pybind11_qt/pybind11_qt.h"
#include <moddatachecker.h>
#include <scriptextender.h>
#include "pyfiletree.h"
namespace py = pybind11;
using namespace MOBase;
using namespace pybind11::literals;
namespace mo2::python {
void add_game_feature_bindings(pybind11::module_ m) {}
class PyModDataChecker : public ModDataChecker {
public:
CheckReturn
dataLooksValid(std::shared_ptr<const MOBase::IFileTree> fileTree) const override
{
PYBIND11_OVERRIDE_PURE(CheckReturn, ModDataChecker, dataLooksValid,
fileTree);
}
std::shared_ptr<MOBase::IFileTree>
fix(std::shared_ptr<MOBase::IFileTree> fileTree) const override
{
PYBIND11_OVERRIDE(std::shared_ptr<MOBase::IFileTree>, ModDataChecker, fix,
fileTree);
}
};
class PyScriptExtender : public ScriptExtender {
public:
QString BinaryName() const override
{
PYBIND11_OVERRIDE_PURE(QString, ScriptExtender, BinaryName, );
}
QString PluginPath() const override
{
PYBIND11_OVERRIDE_PURE(QString, ScriptExtender, PluginPath, );
}
QString loaderName() const override
{
PYBIND11_OVERRIDE_PURE(QString, ScriptExtender, loaderName, );
}
QString loaderPath() const override
{
PYBIND11_OVERRIDE_PURE(QString, ScriptExtender, loaderPath, );
}
QString savegameExtension() const override
{
PYBIND11_OVERRIDE_PURE(QString, ScriptExtender, savegameExtension, );
}
bool isInstalled() const override
{
PYBIND11_OVERRIDE_PURE(bool, ScriptExtender, isInstalled, );
}
QString getExtenderVersion() const override
{
PYBIND11_OVERRIDE_PURE(QString, ScriptExtender, getExtenderVersion, );
}
WORD getArch() const override
{
PYBIND11_OVERRIDE_PURE(WORD, ScriptExtender, getArch, );
}
};
void add_game_feature_bindings(pybind11::module_ m)
{
// ModDataChecker
py::class_<ModDataChecker, PyModDataChecker> pyModDataChecker(m,
"ModDataChecker");
py::enum_<ModDataChecker::CheckReturn>(pyModDataChecker, "CheckReturn")
.value("INVALID", ModDataChecker::CheckReturn::INVALID)
.value("FIXABLE", ModDataChecker::CheckReturn::FIXABLE)
.value("VALID", ModDataChecker::CheckReturn::VALID)
.export_values();
pyModDataChecker.def(py::init<>())
.def("dataLooksValid", &ModDataChecker::dataLooksValid, "filetree"_a)
.def("fix", &ModDataChecker::fix, "filetree"_a);
// ScriptExtender
py::class_<ScriptExtender, PyScriptExtender>(m, "ScriptExtender")
.def(py::init<>())
.def("BinaryName", &ScriptExtender::BinaryName)
.def("PluginPath", &ScriptExtender::PluginPath)
.def("loaderName", &ScriptExtender::loaderName)
.def("loaderPath", &ScriptExtender::loaderPath)
.def("savegameExtension", &ScriptExtender::savegameExtension)
.def("isInstalled", &ScriptExtender::isInstalled)
.def("getExtenderVersion", &ScriptExtender::getExtenderVersion)
.def("getArch", &ScriptExtender::getArch);
}
} // namespace mo2::python
+133 -115
View File
@@ -1,17 +1,53 @@
#include "wrappers.h"
#include <tuple>
#include "pyplugins.h"
#include <bsainvalidation.h>
#include <dataarchives.h>
#include <gameplugins.h>
#include <localsavegames.h>
#include <moddatachecker.h>
#include <moddatacontent.h>
#include <savegameinfo.h>
#include <scriptextender.h>
#include <unmanagedmods.h>
namespace py = pybind11;
using namespace pybind11::literals;
using namespace MOBase;
namespace mo2::python {
class GameFeaturesHelper {
using GameFeatures = std::tuple<
// BSAInvalidation, DataArchives, GamePlugins, LocalSavegames,
ModDataChecker,
// ModDataContent, SaveGameInfo,
ScriptExtender
// , UnmanagedMods
>;
template <class F, std::size_t... Is>
static void helper(F&& f, std::index_sequence<Is...>)
{
(f(static_cast<std::tuple_element_t<Is, GameFeatures>*>(nullptr)), ...);
}
public:
// apply the function f on a null-pointer of type Feature* for each game
// feature
template <class F>
static void apply(F&& f)
{
helper(f, std::make_index_sequence<std::tuple_size_v<GameFeatures>>{});
}
};
// this one is kind of big so it has its own function
void add_iplugingame_bindings(pybind11::module_ m)
{
py::enum_<MOBase::IPluginGame::LoadOrderMechanism>(m, "LoadOrderMechanism")
.value("FileTime", MOBase::IPluginGame::LoadOrderMechanism::FileTime)
.value("PluginsTxt", MOBase::IPluginGame::LoadOrderMechanism::PluginsTxt)
@@ -38,125 +74,107 @@ namespace mo2::python {
.value("SAVEGAMES", MOBase::IPluginGame::SAVEGAMES)
.value("PREFER_DEFAULTS", MOBase::IPluginGame::PREFER_DEFAULTS);
// py::class_<IPluginGameWrapper, py::bases<IPlugin>,
// boost::noncopyable>("IPluginGame")
// .def("localizedName", &MOBase::IPlugin::localizedName,
// &IPluginGameWrapper::localizedName_Default) .def("master",
// &MOBase::IPlugin::master, &IPluginGameWrapper::master_Default)
py::class_<IPluginGame, IPlugin, std::unique_ptr<IPluginGame, py::nodelete>>(
m, "IPluginGame")
// .def("detectGame",
// py::pure_virtual(&MOBase::IPluginGame::detectGame))
// .def("gameName",
// py::pure_virtual(&MOBase::IPluginGame::gameName))
// .def("initializeProfile",
// py::pure_virtual(&MOBase::IPluginGame::initializeProfile),
// (py::arg("directory"), "settings")) .def("listSaves",
// py::pure_virtual(&MOBase::IPluginGame::listSaves),
// py::arg("folder")) .def("isInstalled",
// py::pure_virtual(&MOBase::IPluginGame::isInstalled))
// .def("gameIcon",
// py::pure_virtual(&MOBase::IPluginGame::gameIcon))
// .def("gameDirectory",
// py::pure_virtual(&MOBase::IPluginGame::gameDirectory))
// .def("dataDirectory",
// py::pure_virtual(&MOBase::IPluginGame::dataDirectory))
// .def("setGamePath",
// py::pure_virtual(&MOBase::IPluginGame::setGamePath),
// py::arg("path")) .def("documentsDirectory",
// py::pure_virtual(&MOBase::IPluginGame::documentsDirectory))
// .def("savesDirectory",
// py::pure_virtual(&MOBase::IPluginGame::savesDirectory))
// .def("executables",
// py::pure_virtual(&MOBase::IPluginGame::executables))
// .def("executableForcedLoads",
// py::pure_virtual(&MOBase::IPluginGame::executableForcedLoads))
// .def("steamAPPId",
// py::pure_virtual(&MOBase::IPluginGame::steamAPPId))
// .def("primaryPlugins",
// py::pure_virtual(&MOBase::IPluginGame::primaryPlugins))
// .def("gameVariants",
// py::pure_virtual(&MOBase::IPluginGame::gameVariants))
// .def("setGameVariant",
// py::pure_virtual(&MOBase::IPluginGame::setGameVariant),
// py::arg("variant")) .def("binaryName",
// py::pure_virtual(&MOBase::IPluginGame::binaryName))
// .def("gameShortName",
// py::pure_virtual(&MOBase::IPluginGame::gameShortName))
// .def("primarySources",
// py::pure_virtual(&MOBase::IPluginGame::primarySources))
// .def("validShortNames",
// py::pure_virtual(&MOBase::IPluginGame::validShortNames))
// .def("gameNexusName",
// py::pure_virtual(&MOBase::IPluginGame::gameNexusName))
// .def("iniFiles",
// py::pure_virtual(&MOBase::IPluginGame::iniFiles))
// .def("DLCPlugins",
// py::pure_virtual(&MOBase::IPluginGame::DLCPlugins))
// .def("CCPlugins",
// py::pure_virtual(&MOBase::IPluginGame::CCPlugins))
// .def("loadOrderMechanism",
// py::pure_virtual(&MOBase::IPluginGame::loadOrderMechanism))
// .def("sortMechanism",
// py::pure_virtual(&MOBase::IPluginGame::sortMechanism))
// .def("nexusModOrganizerID",
// py::pure_virtual(&MOBase::IPluginGame::nexusModOrganizerID))
// .def("nexusGameID",
// py::pure_virtual(&MOBase::IPluginGame::nexusGameID))
// .def("looksValid",
// py::pure_virtual(&MOBase::IPluginGame::looksValid),
// py::arg("directory")) .def("gameVersion",
// py::pure_virtual(&MOBase::IPluginGame::gameVersion))
// .def("getLauncherName",
// py::pure_virtual(&MOBase::IPluginGame::getLauncherName))
.def("featureList",
[](MOBase::IPluginGame* p) {
// constructing a dict from class name to actual object
py::dict dict;
GameFeaturesHelper::apply(
[p, &dict]<class Feature>(Feature* feature) {
const auto name = py::type::of<Feature>().attr("__name__");
dict[name] = py::cast(p->feature<Feature>(),
py::return_value_policy::reference);
});
return dict;
})
// .def("featureList", +[](MOBase::IPluginGame* p) {
// // Constructing a dict from class name to actual object:
// py::dict dict;
// mp11::mp_for_each<
// // Must user pointers because mp_for_each construct object:
// mp11::mp_transform<std::add_pointer_t, MpGameFeaturesList>
// >([&](auto* pt) {
// using T = std::remove_pointer_t<decltype(pt)>;
// typename py::reference_existing_object::apply<T*>::type
// converter;
.def(
"feature",
[](MOBase::IPluginGame* p, py::object clsObj) {
py::object py_feature = py::none();
// // Retrieve the python class object:
// const py::converter::registration* registration =
// py::converter::registry::query(py::type_id<T>()); py::object
// key
// =
// py::object(py::handle<>(py::borrowed(registration->get_class_object())));
GameFeaturesHelper::apply([p, &clsObj, &py_feature]<class Feature>(
Feature* feature) {
if (py::type::of<Feature>().is(clsObj)) {
py_feature = py::cast(p->feature<Feature>(),
py::return_value_policy::reference);
}
});
return py_feature;
},
"feature_type"_a, py::return_value_policy::reference)
// // Set the object:
// dict[key] = py::handle<>(converter(p->feature<T>()));
// });
// return dict;
// })
// .def("localizedName", &MOBase::IPlugin::localizedName,
// &IPluginGameWrapper::localizedName_Default) .def("master",
// &MOBase::IPlugin::master, &IPluginGameWrapper::master_Default)
// .def("feature", +[](MOBase::IPluginGame* p, py::object clsObj) {
// py::object feature;
// mp11::mp_for_each<
// // Must user pointers because mp_for_each construct object:
// mp11::mp_transform<std::add_pointer_t, MpGameFeaturesList>
// >([&](auto* pt) {
// using T = std::remove_pointer_t<decltype(pt)>;
// typename py::reference_existing_object::apply<T*>::type
// converter;
// // Retrieve the python class object:
// const py::converter::registration* registration =
// py::converter::registry::query(py::type_id<T>());
// if (clsObj.ptr() == (PyObject*)
// registration->get_class_object())
// {
// feature =
// py::object(py::handle<>(converter(p->feature<T>())));
// }
// });
// return feature;
// }, py::arg("feature_type"))
// ;
// .def("detectGame",
// py::pure_virtual(&MOBase::IPluginGame::detectGame))
// .def("gameName",
// py::pure_virtual(&MOBase::IPluginGame::gameName))
// .def("initializeProfile",
// py::pure_virtual(&MOBase::IPluginGame::initializeProfile),
// (py::arg("directory"), "settings")) .def("listSaves",
// py::pure_virtual(&MOBase::IPluginGame::listSaves),
// py::arg("folder")) .def("isInstalled",
// py::pure_virtual(&MOBase::IPluginGame::isInstalled))
// .def("gameIcon",
// py::pure_virtual(&MOBase::IPluginGame::gameIcon))
// .def("gameDirectory",
// py::pure_virtual(&MOBase::IPluginGame::gameDirectory))
.def("dataDirectory", &MOBase::IPluginGame::dataDirectory)
// .def("setGamePath",
// py::pure_virtual(&MOBase::IPluginGame::setGamePath),
// py::arg("path")) .def("documentsDirectory",
// py::pure_virtual(&MOBase::IPluginGame::documentsDirectory))
// .def("savesDirectory",
// py::pure_virtual(&MOBase::IPluginGame::savesDirectory))
// .def("executables",
// py::pure_virtual(&MOBase::IPluginGame::executables))
// .def("executableForcedLoads",
// py::pure_virtual(&MOBase::IPluginGame::executableForcedLoads))
// .def("steamAPPId",
// py::pure_virtual(&MOBase::IPluginGame::steamAPPId))
// .def("primaryPlugins",
// py::pure_virtual(&MOBase::IPluginGame::primaryPlugins))
// .def("gameVariants",
// py::pure_virtual(&MOBase::IPluginGame::gameVariants))
// .def("setGameVariant",
// py::pure_virtual(&MOBase::IPluginGame::setGameVariant),
// py::arg("variant")) .def("binaryName",
// py::pure_virtual(&MOBase::IPluginGame::binaryName))
// .def("gameShortName",
// py::pure_virtual(&MOBase::IPluginGame::gameShortName))
// .def("primarySources",
// py::pure_virtual(&MOBase::IPluginGame::primarySources))
// .def("validShortNames",
// py::pure_virtual(&MOBase::IPluginGame::validShortNames))
// .def("gameNexusName",
// py::pure_virtual(&MOBase::IPluginGame::gameNexusName))
// .def("iniFiles",
// py::pure_virtual(&MOBase::IPluginGame::iniFiles))
// .def("DLCPlugins",
// py::pure_virtual(&MOBase::IPluginGame::DLCPlugins))
// .def("CCPlugins",
// py::pure_virtual(&MOBase::IPluginGame::CCPlugins))
// .def("loadOrderMechanism",
// py::pure_virtual(&MOBase::IPluginGame::loadOrderMechanism))
// .def("sortMechanism",
// py::pure_virtual(&MOBase::IPluginGame::sortMechanism))
// .def("nexusModOrganizerID",
// py::pure_virtual(&MOBase::IPluginGame::nexusModOrganizerID))
// .def("nexusGameID",
// py::pure_virtual(&MOBase::IPluginGame::nexusGameID))
// .def("looksValid",
// py::pure_virtual(&MOBase::IPluginGame::looksValid),
// py::arg("directory")) .def("gameVersion",
// py::pure_virtual(&MOBase::IPluginGame::gameVersion))
// .def("getLauncherName",
// py::pure_virtual(&MOBase::IPluginGame::getLauncherName))
//
;
}
// multiple installers
+4 -2
View File
@@ -262,7 +262,8 @@ namespace mo2::python {
class PyPluginInstallerCustom
: public PyPluginInstallerBase<IPluginInstallerCustom> {
Q_OBJECT
Q_INTERFACES(MOBase::IPlugin MOBase::IPluginInstallerCustom)
Q_INTERFACES(
MOBase::IPlugin MOBase::IPluginInstaller MOBase::IPluginInstallerCustom)
public:
bool isArchiveSupported(const QString& archiveName) const
{
@@ -288,7 +289,8 @@ namespace mo2::python {
class PyPluginInstallerSimple
: public PyPluginInstallerBase<IPluginInstallerSimple> {
Q_OBJECT
Q_INTERFACES(MOBase::IPlugin MOBase::IPluginInstallerSimple)
Q_INTERFACES(
MOBase::IPlugin MOBase::IPluginInstaller MOBase::IPluginInstallerSimple)
public:
using py_install_return_type =
std::variant<IPluginInstaller::EInstallResult, std::shared_ptr<IFileTree>,
+1881 -1423
View File
File diff suppressed because it is too large Load Diff