mirror of
https://github.com/ModOrganizer2/modorganizer-plugin_python.git
synced 2026-07-27 14:03:33 -07:00
Finally implement everything (some stuff not working).
This commit is contained in:
@@ -14,48 +14,48 @@
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="proxypython.cpp" line="206"/>
|
||||
<location filename="proxypython.cpp" line="202"/>
|
||||
<source>ModOrganizer path contains a semicolon</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="proxypython.cpp" line="208"/>
|
||||
<location filename="proxypython.cpp" line="204"/>
|
||||
<source>Python DLL not found</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="proxypython.cpp" line="210"/>
|
||||
<location filename="proxypython.cpp" line="206"/>
|
||||
<source>Invalid Python DLL</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="proxypython.cpp" line="212"/>
|
||||
<location filename="proxypython.cpp" line="208"/>
|
||||
<source>Initializing Python failed</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="proxypython.cpp" line="214"/>
|
||||
<location filename="proxypython.cpp" line="244"/>
|
||||
<location filename="proxypython.cpp" line="210"/>
|
||||
<location filename="proxypython.cpp" line="240"/>
|
||||
<source>invalid problem key %1</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="proxypython.cpp" line="222"/>
|
||||
<location filename="proxypython.cpp" line="218"/>
|
||||
<source>The path to Mod Organizer (%1) contains a semicolon. <br>While this is legal on NTFS drives, many softwares do not handle it correctly.<br>Unfortunately MO depends on libraries that seem to fall into that group.<br>As a result the python plugin cannot be loaded, and the only solution we canoffer is to remove the semicolon or move MO to a path without a semicolon.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="proxypython.cpp" line="233"/>
|
||||
<location filename="proxypython.cpp" line="229"/>
|
||||
<source>The Python plugin DLL was not found, maybe your antivirus deleted it. Re-installing MO2 might fix the problem.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="proxypython.cpp" line="236"/>
|
||||
<location filename="proxypython.cpp" line="232"/>
|
||||
<source>The Python plugin DLL is invalid, maybe your antivirus is blocking it. Re-installing MO2 and adding exclusions for it to your AV might fix the problem.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="proxypython.cpp" line="241"/>
|
||||
<location filename="proxypython.cpp" line="237"/>
|
||||
<source>The initialization of the Python plugin DLL failed, unfortunately without any details.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
|
||||
@@ -153,15 +153,11 @@ QStringList ProxyPython::pluginList(const QDir& pluginPath) const
|
||||
QString name = iter.next();
|
||||
QFileInfo info = iter.fileInfo();
|
||||
|
||||
if (info.fileName() == "pyCfg.py" || info.fileName() == "installer_wizard") {
|
||||
if (info.isFile() && name.endsWith(".py")) {
|
||||
result.append(name);
|
||||
}
|
||||
|
||||
if (info.isFile() && name.endsWith(".py")) {
|
||||
// result.append(name);
|
||||
}
|
||||
else if (info.isDir() && QDir(info.absoluteFilePath()).exists("__init__.py")) {
|
||||
// result.append(name);
|
||||
result.append(name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+37
-40
@@ -25,59 +25,56 @@ along with python proxy plugin. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#include <ipluginproxy.h>
|
||||
#include <iplugindiagnose.h>
|
||||
#include <ipluginproxy.h>
|
||||
|
||||
#include <pythonrunner.h>
|
||||
|
||||
|
||||
class ProxyPython : public QObject, public MOBase::IPluginProxy, public MOBase::IPluginDiagnose
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(MOBase::IPlugin MOBase::IPluginProxy MOBase::IPluginDiagnose)
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
|
||||
Q_PLUGIN_METADATA(IID "org.tannin.ProxyPython" FILE "proxypython.json")
|
||||
class ProxyPython : public QObject,
|
||||
public MOBase::IPluginProxy,
|
||||
public MOBase::IPluginDiagnose {
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(MOBase::IPlugin MOBase::IPluginProxy MOBase::IPluginDiagnose)
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
||||
Q_PLUGIN_METADATA(IID "org.mo2.ProxyPython")
|
||||
#endif
|
||||
|
||||
public:
|
||||
ProxyPython();
|
||||
ProxyPython();
|
||||
|
||||
virtual bool init(MOBase::IOrganizer *moInfo);
|
||||
virtual QString name() const override;
|
||||
virtual QString localizedName() const override;
|
||||
virtual QString author() const override;
|
||||
virtual QString description() const override;
|
||||
virtual MOBase::VersionInfo version() const override;
|
||||
virtual QList<MOBase::PluginSetting> settings() const override;
|
||||
virtual bool init(MOBase::IOrganizer* moInfo);
|
||||
virtual QString name() const override;
|
||||
virtual QString localizedName() const override;
|
||||
virtual QString author() const override;
|
||||
virtual QString description() const override;
|
||||
virtual MOBase::VersionInfo version() const override;
|
||||
virtual QList<MOBase::PluginSetting> settings() const override;
|
||||
|
||||
QStringList pluginList(const QDir& pluginPath) const override;
|
||||
QList<QObject*> load(const QString& identifier) override;
|
||||
void unload(const QString& identifier) override;
|
||||
QStringList pluginList(const QDir& pluginPath) const override;
|
||||
QList<QObject*> load(const QString& identifier) override;
|
||||
void unload(const QString& identifier) override;
|
||||
|
||||
public: // IPluginDiagnose
|
||||
|
||||
virtual std::vector<unsigned int> activeProblems() const override;
|
||||
virtual QString shortDescription(unsigned int key) const override;
|
||||
virtual QString fullDescription(unsigned int key) const override;
|
||||
virtual bool hasGuidedFix(unsigned int key) const override;
|
||||
virtual void startGuidedFix(unsigned int key) const override;
|
||||
public: // IPluginDiagnose
|
||||
virtual std::vector<unsigned int> activeProblems() const override;
|
||||
virtual QString shortDescription(unsigned int key) const override;
|
||||
virtual QString fullDescription(unsigned int key) const override;
|
||||
virtual bool hasGuidedFix(unsigned int key) const override;
|
||||
virtual void startGuidedFix(unsigned int key) const override;
|
||||
|
||||
private:
|
||||
MOBase::IOrganizer* m_MOInfo;
|
||||
HMODULE m_RunnerLib;
|
||||
std::unique_ptr<IPythonRunner> m_Runner;
|
||||
|
||||
MOBase::IOrganizer *m_MOInfo;
|
||||
HMODULE m_RunnerLib;
|
||||
std::unique_ptr<IPythonRunner> m_Runner;
|
||||
|
||||
enum class FailureType : unsigned int {
|
||||
NONE = 0,
|
||||
SEMICOLON = 1,
|
||||
DLL_NOT_FOUND = 2,
|
||||
INVALID_DLL = 3,
|
||||
INITIALIZATION = 4
|
||||
};
|
||||
|
||||
FailureType m_LoadFailure;
|
||||
enum class FailureType : unsigned int {
|
||||
NONE = 0,
|
||||
SEMICOLON = 1,
|
||||
DLL_NOT_FOUND = 2,
|
||||
INVALID_DLL = 3,
|
||||
INITIALIZATION = 4
|
||||
};
|
||||
|
||||
FailureType m_LoadFailure;
|
||||
};
|
||||
|
||||
#endif // PROXYPYTHON_H
|
||||
#endif // PROXYPYTHON_H
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
{}
|
||||
@@ -1,14 +1,11 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
# need to find Boost here with a dummy component to get Boost_LIBRARY_DIRS
|
||||
find_package(Boost COMPONENTS thread REQUIRED)
|
||||
|
||||
pybind11_add_module(pythonrunner SHARED)
|
||||
mo2_configure_library(pythonrunner
|
||||
WARNINGS OFF
|
||||
AUTOMOC ON
|
||||
TRANSLATIONS OFF
|
||||
PRIVATE_DEPENDS uibase boost Qt::Core
|
||||
PRIVATE_DEPENDS uibase Qt::Core
|
||||
)
|
||||
set_target_properties(pythonrunner
|
||||
PROPERTIES
|
||||
@@ -19,11 +16,6 @@ target_link_libraries(pythonrunner PRIVATE pybind11::embed)
|
||||
target_include_directories(pythonrunner PRIVATE ${PYTHON_ROOT}/Include)
|
||||
|
||||
# this is kind of broken but it only works with this...
|
||||
target_link_directories(pythonrunner
|
||||
PRIVATE
|
||||
${Boost_LIBRARY_DIRS})
|
||||
target_compile_options(pythonrunner
|
||||
PRIVATE $<$<CXX_COMPILER_ID:MSVC>:/MP>)
|
||||
target_compile_definitions(pythonrunner
|
||||
PRIVATE QT_NO_KEYWORDS PYTHONRUNNER_LIBRARY)
|
||||
mo2_install_target(pythonrunner INSTALLDIR bin/plugins/data)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,390 +0,0 @@
|
||||
#include "gamefeatureswrappers.h"
|
||||
|
||||
#include <any>
|
||||
#include <typeindex>
|
||||
|
||||
#include <ifiletree.h>
|
||||
#include <ipluginlist.h>
|
||||
#include <iprofile.h>
|
||||
#include <isavegame.h>
|
||||
#include <isavegameinfowidget.h>
|
||||
|
||||
#include "pythonwrapperutilities.h"
|
||||
#include "shared_ptr_converter.h"
|
||||
|
||||
/////////////////////////////
|
||||
/// BSAInvalidation Wrapper
|
||||
|
||||
bool BSAInvalidationWrapper::isInvalidationBSA(const QString& bsaName)
|
||||
{
|
||||
return basicWrapperFunctionImplementation<bool>(this, "isInvalidationBSA", bsaName);
|
||||
}
|
||||
|
||||
void BSAInvalidationWrapper::deactivate(MOBase::IProfile* profile)
|
||||
{
|
||||
return basicWrapperFunctionImplementation<void>(this, "deactivate",
|
||||
boost::python::ptr(profile));
|
||||
}
|
||||
|
||||
void BSAInvalidationWrapper::activate(MOBase::IProfile* profile)
|
||||
{
|
||||
return basicWrapperFunctionImplementation<void>(this, "activate",
|
||||
boost::python::ptr(profile));
|
||||
}
|
||||
|
||||
bool BSAInvalidationWrapper::prepareProfile(MOBase::IProfile* profile)
|
||||
{
|
||||
return basicWrapperFunctionImplementation<bool>(this, "prepareProfile",
|
||||
boost::python::ptr(profile));
|
||||
}
|
||||
/// end BSAInvalidation Wrapper
|
||||
/////////////////////////////
|
||||
/// DataArchives Wrapper
|
||||
|
||||
QStringList DataArchivesWrapper::vanillaArchives() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<QStringList>(this, "vanillaArchives");
|
||||
}
|
||||
|
||||
QStringList DataArchivesWrapper::archives(const MOBase::IProfile* profile) const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<QStringList>(this, "archives",
|
||||
boost::python::ptr(profile));
|
||||
}
|
||||
|
||||
void DataArchivesWrapper::addArchive(MOBase::IProfile* profile, int index,
|
||||
const QString& archiveName)
|
||||
{
|
||||
return basicWrapperFunctionImplementation<void>(
|
||||
this, "addArchive", boost::python::ptr(profile), index, archiveName);
|
||||
}
|
||||
|
||||
void DataArchivesWrapper::removeArchive(MOBase::IProfile* profile,
|
||||
const QString& archiveName)
|
||||
{
|
||||
return basicWrapperFunctionImplementation<void>(
|
||||
this, "removeArchive", boost::python::ptr(profile), archiveName);
|
||||
}
|
||||
/// end DataArchives Wrapper
|
||||
/////////////////////////////
|
||||
/// GamePlugins Wrapper
|
||||
|
||||
void GamePluginsWrapper::writePluginLists(const MOBase::IPluginList* pluginList)
|
||||
{
|
||||
return basicWrapperFunctionImplementation<void>(this, "writePluginLists",
|
||||
boost::python::ptr(pluginList));
|
||||
}
|
||||
|
||||
void GamePluginsWrapper::readPluginLists(MOBase::IPluginList* pluginList)
|
||||
{
|
||||
return basicWrapperFunctionImplementation<void>(this, "readPluginLists",
|
||||
boost::python::ptr(pluginList));
|
||||
}
|
||||
|
||||
QStringList GamePluginsWrapper::getLoadOrder()
|
||||
{
|
||||
return basicWrapperFunctionImplementation<QStringList>(this, "getLoadOrder");
|
||||
}
|
||||
|
||||
bool GamePluginsWrapper::lightPluginsAreSupported()
|
||||
{
|
||||
return basicWrapperFunctionImplementation<bool>(this, "lightPluginsAreSupported");
|
||||
}
|
||||
|
||||
/// end GamePlugins Wrapper
|
||||
/////////////////////////////
|
||||
/// LocalSavegames Wrapper
|
||||
|
||||
MappingType LocalSavegamesWrapper::mappings(const QDir& profileSaveDir) const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<MappingType>(this, "mappings",
|
||||
profileSaveDir);
|
||||
}
|
||||
|
||||
bool LocalSavegamesWrapper::prepareProfile(MOBase::IProfile* profile)
|
||||
{
|
||||
return basicWrapperFunctionImplementation<bool>(this, "prepareProfile",
|
||||
boost::python::ptr(profile));
|
||||
}
|
||||
|
||||
/// end LocalSavegames Wrapper
|
||||
/////////////////////////////
|
||||
/// ModDataChecker Wrapper
|
||||
|
||||
ModDataChecker::CheckReturn ModDataCheckerWrapper::dataLooksValid(
|
||||
std::shared_ptr<const MOBase::IFileTree> fileTree) const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<CheckReturn>(this, "dataLooksValid",
|
||||
fileTree);
|
||||
}
|
||||
|
||||
std::shared_ptr<MOBase::IFileTree>
|
||||
ModDataCheckerWrapper::fix(std::shared_ptr<MOBase::IFileTree> fileTree) const
|
||||
{
|
||||
return utils::clean_shared_ptr(basicWrapperFunctionImplementationWithDefault<
|
||||
std::shared_ptr<MOBase::IFileTree>>(
|
||||
this,
|
||||
[](auto&&... args) {
|
||||
return nullptr;
|
||||
},
|
||||
"fix", fileTree));
|
||||
}
|
||||
|
||||
/// end ModDataChecker Wrapper
|
||||
/////////////////////////////
|
||||
/// ModDataContent Wrapper
|
||||
|
||||
std::vector<ModDataContent::Content> ModDataContentWrapper::getAllContents() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<std::vector<Content>>(this,
|
||||
"getAllContents");
|
||||
}
|
||||
std::vector<int> ModDataContentWrapper::getContentsFor(
|
||||
std::shared_ptr<const MOBase::IFileTree> fileTree) const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<std::vector<int>>(this, "getContentsFor",
|
||||
fileTree);
|
||||
}
|
||||
|
||||
/// end ModDataContent Wrapper
|
||||
/////////////////////////////
|
||||
/// SaveGameInfo Wrapper
|
||||
|
||||
SaveGameInfoWrapper::MissingAssets
|
||||
SaveGameInfoWrapper::getMissingAssets(MOBase::ISaveGame const& save) const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<SaveGameInfoWrapper::MissingAssets>(
|
||||
this, "getMissingAssets", boost::ref(save));
|
||||
}
|
||||
|
||||
MOBase::ISaveGameInfoWidget*
|
||||
SaveGameInfoWrapper::getSaveGameWidget(QWidget* parent) const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<MOBase::ISaveGameInfoWidget*>(
|
||||
this, m_SaveGameWidget, "getSaveGameWidget", parent);
|
||||
}
|
||||
|
||||
/// end SaveGameInfo Wrapper
|
||||
/////////////////////////////
|
||||
/// ScriptExtender Wrapper
|
||||
|
||||
QString ScriptExtenderWrapper::BinaryName() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<QString>(this, "BinaryName");
|
||||
}
|
||||
|
||||
QString ScriptExtenderWrapper::PluginPath() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<QString>(this, "PluginPath");
|
||||
}
|
||||
|
||||
QString ScriptExtenderWrapper::loaderName() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<QString>(this, "loaderName");
|
||||
}
|
||||
|
||||
QString ScriptExtenderWrapper::loaderPath() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<QString>(this, "loaderPath");
|
||||
}
|
||||
|
||||
QString ScriptExtenderWrapper::savegameExtension() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<QString>(this, "savegameExtension");
|
||||
}
|
||||
|
||||
bool ScriptExtenderWrapper::isInstalled() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<bool>(this, "isInstalled");
|
||||
}
|
||||
|
||||
QString ScriptExtenderWrapper::getExtenderVersion() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<QString>(this, "getExtenderVersion");
|
||||
}
|
||||
|
||||
WORD ScriptExtenderWrapper::getArch() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<WORD>(this, "getArch");
|
||||
}
|
||||
|
||||
/// end ScriptExtender Wrapper
|
||||
/////////////////////////////
|
||||
/// UnmanagedMods Wrapper
|
||||
|
||||
QStringList UnmanagedModsWrapper::mods(bool onlyOfficial) const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<QStringList>(this, "mods", onlyOfficial);
|
||||
}
|
||||
|
||||
QString UnmanagedModsWrapper::displayName(const QString& modName) const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<QString>(this, "displayName", modName);
|
||||
}
|
||||
|
||||
QFileInfo UnmanagedModsWrapper::referenceFile(const QString& modName) const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<QFileInfo>(this, "referenceFile",
|
||||
modName);
|
||||
}
|
||||
|
||||
QStringList UnmanagedModsWrapper::secondaryFiles(const QString& modName) const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<QStringList>(this, "secondaryFiles",
|
||||
modName);
|
||||
}
|
||||
/// end UnmanagedMods Wrapper
|
||||
/////////////////////////////
|
||||
|
||||
game_features_map_from_python::game_features_map_from_python()
|
||||
{
|
||||
boost::python::converter::registry::push_back(
|
||||
&convertible, &construct,
|
||||
boost::python::type_id<std::map<std::type_index, std::any>>());
|
||||
}
|
||||
|
||||
void* game_features_map_from_python::convertible(PyObject* objPtr)
|
||||
{
|
||||
return PyDict_Check(objPtr) ? objPtr : nullptr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void insertGameFeature(std::map<std::type_index, std::any>& map,
|
||||
const boost::python::object& pyObject)
|
||||
{
|
||||
map[std::type_index(typeid(T))] = boost::python::extract<T*>(pyObject)();
|
||||
}
|
||||
|
||||
void game_features_map_from_python::construct(
|
||||
PyObject* objPtr, boost::python::converter::rvalue_from_python_stage1_data* data)
|
||||
{
|
||||
void* storage = ((boost::python::converter::rvalue_from_python_storage<
|
||||
std::map<std::type_index, std::any>>*)data)
|
||||
->storage.bytes;
|
||||
std::map<std::type_index, std::any>* result =
|
||||
new (storage) std::map<std::type_index, std::any>();
|
||||
boost::python::dict source(
|
||||
boost::python::handle<>(boost::python::borrowed(objPtr)));
|
||||
boost::python::list keys = source.keys();
|
||||
int len = boost::python::len(keys);
|
||||
for (int i = 0; i < len; ++i) {
|
||||
boost::python::object pyKey = keys[i];
|
||||
boost::python::object pyValue = source[pyKey];
|
||||
|
||||
boost::mp11::mp_for_each<
|
||||
// Must user pointers because mp_for_each construct object:
|
||||
boost::mp11::mp_transform<std::add_pointer_t, MpGameFeaturesList>>(
|
||||
[&](auto* pt) {
|
||||
using T = std::remove_pointer_t<decltype(pt)>;
|
||||
boost::python::extract<T*> extract(pyValue);
|
||||
if (extract.check()) {
|
||||
(*result)[std::type_index(typeid(T))] = extract();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
data->convertible = storage;
|
||||
}
|
||||
|
||||
void registerGameFeaturesPythonConverters()
|
||||
{
|
||||
namespace bpy = boost::python;
|
||||
|
||||
game_features_map_from_python();
|
||||
|
||||
// Features require defs for all methods as Python can access C++ features
|
||||
bpy::class_<BSAInvalidationWrapper, boost::noncopyable>("BSAInvalidation")
|
||||
.def("isInvalidationBSA",
|
||||
bpy::pure_virtual(&BSAInvalidation::isInvalidationBSA), bpy::arg("name"))
|
||||
.def("deactivate", bpy::pure_virtual(&BSAInvalidation::deactivate),
|
||||
bpy::arg("profile"))
|
||||
.def("activate", bpy::pure_virtual(&BSAInvalidation::activate),
|
||||
bpy::arg("profile"));
|
||||
|
||||
bpy::class_<DataArchivesWrapper, boost::noncopyable>("DataArchives")
|
||||
.def("vanillaArchives", bpy::pure_virtual(&DataArchives::vanillaArchives))
|
||||
.def("archives", bpy::pure_virtual(&DataArchives::archives),
|
||||
bpy::arg("profile"))
|
||||
.def("addArchive", bpy::pure_virtual(&DataArchives::addArchive),
|
||||
(bpy::arg("profile"), "index", "name"))
|
||||
.def("removeArchive", bpy::pure_virtual(&DataArchives::removeArchive),
|
||||
(bpy::arg("profile"), "name"));
|
||||
|
||||
bpy::class_<GamePluginsWrapper, boost::noncopyable>("GamePlugins")
|
||||
.def("writePluginLists", bpy::pure_virtual(&GamePlugins::writePluginLists),
|
||||
bpy::arg("plugin_list"))
|
||||
.def("readPluginLists", bpy::pure_virtual(&GamePlugins::readPluginLists),
|
||||
bpy::arg("plugin_list"))
|
||||
.def("getLoadOrder", bpy::pure_virtual(&GamePlugins::getLoadOrder))
|
||||
.def("lightPluginsAreSupported",
|
||||
bpy::pure_virtual(&GamePlugins::lightPluginsAreSupported));
|
||||
|
||||
bpy::class_<LocalSavegamesWrapper, boost::noncopyable>("LocalSavegames")
|
||||
.def("mappings", bpy::pure_virtual(&LocalSavegames::mappings),
|
||||
bpy::arg("profile_save_dir"))
|
||||
.def("prepareProfile", bpy::pure_virtual(&LocalSavegames::prepareProfile),
|
||||
bpy::arg("profile"));
|
||||
|
||||
auto modDataCheckerClass =
|
||||
bpy::class_<ModDataCheckerWrapper, boost::noncopyable>("ModDataChecker");
|
||||
{
|
||||
bpy::scope scope = modDataCheckerClass;
|
||||
|
||||
bpy::enum_<ModDataChecker::CheckReturn>("CheckReturn")
|
||||
.value("INVALID", ModDataChecker::CheckReturn::INVALID)
|
||||
.value("FIXABLE", ModDataChecker::CheckReturn::FIXABLE)
|
||||
.value("VALID", ModDataChecker::CheckReturn::VALID)
|
||||
.export_values();
|
||||
|
||||
modDataCheckerClass
|
||||
.def("dataLooksValid", bpy::pure_virtual(&ModDataChecker::dataLooksValid),
|
||||
bpy::arg("filetree"))
|
||||
.def("fix", bpy::pure_virtual(&ModDataChecker::fix), bpy::arg("filetree"));
|
||||
}
|
||||
|
||||
{
|
||||
bpy::scope scope =
|
||||
bpy::class_<ModDataContentWrapper, boost::noncopyable>("ModDataContent")
|
||||
.def("getAllContents",
|
||||
bpy::pure_virtual(&ModDataContent::getAllContents))
|
||||
.def("getContentsFor",
|
||||
bpy::pure_virtual(&ModDataContent::getContentsFor),
|
||||
bpy::arg("filetree"));
|
||||
|
||||
bpy::class_<ModDataContent::Content>(
|
||||
"Content",
|
||||
bpy::init<int, QString, QString, bpy::optional<bool>>(
|
||||
(bpy::arg("id"), "name", "icon", bpy::arg("filter_only") = false)))
|
||||
.add_property("id", &ModDataContent::Content::id)
|
||||
.add_property("name", &ModDataContent::Content::name)
|
||||
.add_property("icon", &ModDataContent::Content::icon)
|
||||
.def("isOnlyForFilter", &ModDataContent::Content::isOnlyForFilter);
|
||||
}
|
||||
|
||||
bpy::class_<SaveGameInfoWrapper, boost::noncopyable>("SaveGameInfo")
|
||||
.def("getMissingAssets", bpy::pure_virtual(&SaveGameInfo::getMissingAssets),
|
||||
bpy::arg("save"))
|
||||
.def("getSaveGameWidget", bpy::pure_virtual(&SaveGameInfo::getSaveGameWidget),
|
||||
bpy::return_value_policy<bpy::manage_new_object>(), bpy::arg("parent"),
|
||||
"[optional]");
|
||||
|
||||
bpy::class_<ScriptExtenderWrapper, boost::noncopyable>("ScriptExtender")
|
||||
.def("BinaryName", bpy::pure_virtual(&ScriptExtender::BinaryName))
|
||||
.def("PluginPath", bpy::pure_virtual(&ScriptExtender::PluginPath))
|
||||
.def("loaderName", bpy::pure_virtual(&ScriptExtender::loaderName))
|
||||
.def("loaderPath", bpy::pure_virtual(&ScriptExtender::loaderPath))
|
||||
.def("savegameExtension", bpy::pure_virtual(&ScriptExtender::savegameExtension))
|
||||
.def("isInstalled", bpy::pure_virtual(&ScriptExtender::isInstalled))
|
||||
.def("getExtenderVersion",
|
||||
bpy::pure_virtual(&ScriptExtender::getExtenderVersion))
|
||||
.def("getArch", bpy::pure_virtual(&ScriptExtender::getArch));
|
||||
|
||||
bpy::class_<UnmanagedModsWrapper, boost::noncopyable>("UnmanagedMods")
|
||||
.def("mods", bpy::pure_virtual(&UnmanagedMods::mods), bpy::arg("official_only"))
|
||||
.def("displayName", bpy::pure_virtual(&UnmanagedMods::displayName),
|
||||
bpy::arg("mod_name"))
|
||||
.def("referenceFile", bpy::pure_virtual(&UnmanagedMods::referenceFile),
|
||||
bpy::arg("mod_name"))
|
||||
.def("secondaryFiles", bpy::pure_virtual(&UnmanagedMods::secondaryFiles),
|
||||
bpy::arg("mod_name"));
|
||||
}
|
||||
@@ -1,158 +0,0 @@
|
||||
#ifndef GAMEFEATURESWRAPPERS_H
|
||||
#define GAMEFEATURESWRAPPERS_H
|
||||
|
||||
#include <map>
|
||||
|
||||
#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>
|
||||
|
||||
// this might need turning off if Q_MOC_RUN is defined
|
||||
#include <boost/mp11.hpp>
|
||||
#include <boost/python.hpp>
|
||||
|
||||
// This is a simple MPL list that contains all the game features in one place:
|
||||
using MpGameFeaturesList =
|
||||
boost::mp11::mp_list<BSAInvalidation, DataArchives, GamePlugins, LocalSavegames,
|
||||
ModDataChecker, ModDataContent, SaveGameInfo, ScriptExtender,
|
||||
UnmanagedMods>;
|
||||
|
||||
/////////////////////////////
|
||||
/// Wrapper declarations
|
||||
|
||||
class BSAInvalidationWrapper : public BSAInvalidation,
|
||||
public boost::python::wrapper<BSAInvalidation> {
|
||||
public:
|
||||
static constexpr const char* className = "BSAInvalidationWrapper";
|
||||
using boost::python::wrapper<BSAInvalidation>::get_override;
|
||||
|
||||
virtual bool isInvalidationBSA(const QString& bsaName) override;
|
||||
virtual void deactivate(MOBase::IProfile* profile) override;
|
||||
virtual void activate(MOBase::IProfile* profile) override;
|
||||
virtual bool prepareProfile(MOBase::IProfile* profile) override;
|
||||
};
|
||||
|
||||
class DataArchivesWrapper : public DataArchives,
|
||||
public boost::python::wrapper<DataArchives> {
|
||||
public:
|
||||
static constexpr const char* className = "DataArchivesWrapper";
|
||||
using boost::python::wrapper<DataArchives>::get_override;
|
||||
|
||||
virtual QStringList vanillaArchives() const override;
|
||||
virtual QStringList archives(const MOBase::IProfile* profile) const override;
|
||||
virtual void addArchive(MOBase::IProfile* profile, int index,
|
||||
const QString& archiveName) override;
|
||||
virtual void removeArchive(MOBase::IProfile* profile,
|
||||
const QString& archiveName) override;
|
||||
};
|
||||
|
||||
class GamePluginsWrapper : public GamePlugins,
|
||||
public boost::python::wrapper<GamePlugins> {
|
||||
public:
|
||||
static constexpr const char* className = "GamePluginsWrapper";
|
||||
using boost::python::wrapper<GamePlugins>::get_override;
|
||||
|
||||
virtual void writePluginLists(const MOBase::IPluginList* pluginList) override;
|
||||
virtual void readPluginLists(MOBase::IPluginList* pluginList) override;
|
||||
virtual QStringList getLoadOrder() override;
|
||||
virtual bool lightPluginsAreSupported() override;
|
||||
};
|
||||
|
||||
class LocalSavegamesWrapper : public LocalSavegames,
|
||||
public boost::python::wrapper<LocalSavegames> {
|
||||
public:
|
||||
static constexpr const char* className = "LocalSavegamesWrapper";
|
||||
using boost::python::wrapper<LocalSavegames>::get_override;
|
||||
|
||||
virtual MappingType mappings(const QDir& profileSaveDir) const override;
|
||||
virtual bool prepareProfile(MOBase::IProfile* profile) override;
|
||||
};
|
||||
|
||||
class ModDataCheckerWrapper : public ModDataChecker,
|
||||
public boost::python::wrapper<ModDataChecker> {
|
||||
public:
|
||||
static constexpr const char* className = "ModDataCheckerWrapper";
|
||||
using boost::python::wrapper<ModDataChecker>::get_override;
|
||||
|
||||
virtual CheckReturn
|
||||
dataLooksValid(std::shared_ptr<const MOBase::IFileTree> fileTree) const override;
|
||||
virtual std::shared_ptr<MOBase::IFileTree>
|
||||
fix(std::shared_ptr<MOBase::IFileTree> fileTree) const override;
|
||||
};
|
||||
|
||||
class ModDataContentWrapper : public ModDataContent,
|
||||
public boost::python::wrapper<ModDataContent> {
|
||||
public:
|
||||
static constexpr const char* className = "ModDataContentWrapper";
|
||||
using boost::python::wrapper<ModDataContent>::get_override;
|
||||
|
||||
virtual std::vector<Content> getAllContents() const override;
|
||||
virtual std::vector<int>
|
||||
getContentsFor(std::shared_ptr<const MOBase::IFileTree> fileTree) const override;
|
||||
};
|
||||
|
||||
class SaveGameInfoWrapper : public SaveGameInfo,
|
||||
public boost::python::wrapper<SaveGameInfo> {
|
||||
public:
|
||||
static constexpr const char* className = "SaveGameInfoWrapper";
|
||||
using boost::python::wrapper<SaveGameInfo>::get_override;
|
||||
|
||||
virtual MissingAssets
|
||||
getMissingAssets(MOBase::ISaveGame const& save) const override;
|
||||
virtual MOBase::ISaveGameInfoWidget*
|
||||
getSaveGameWidget(QWidget* parent = 0) const override;
|
||||
|
||||
private:
|
||||
// We need to keep the python objects alive:
|
||||
mutable std::map<QString, boost::python::object> m_SaveGames;
|
||||
mutable boost::python::object m_SaveGameWidget;
|
||||
};
|
||||
|
||||
class ScriptExtenderWrapper : public ScriptExtender,
|
||||
public boost::python::wrapper<ScriptExtender> {
|
||||
public:
|
||||
static constexpr const char* className = "ScriptExtenderWrapper";
|
||||
using boost::python::wrapper<ScriptExtender>::get_override;
|
||||
|
||||
virtual QString BinaryName() const override;
|
||||
virtual QString PluginPath() const override;
|
||||
virtual QString loaderName() const override;
|
||||
virtual QString loaderPath() const override;
|
||||
virtual QString savegameExtension() const override;
|
||||
virtual bool isInstalled() const override;
|
||||
virtual QString getExtenderVersion() const override;
|
||||
virtual WORD getArch() const override;
|
||||
};
|
||||
|
||||
class UnmanagedModsWrapper : public UnmanagedMods,
|
||||
public boost::python::wrapper<UnmanagedMods> {
|
||||
public:
|
||||
static constexpr const char* className = "UnmanagedModsWrapper";
|
||||
using boost::python::wrapper<UnmanagedMods>::get_override;
|
||||
|
||||
virtual QStringList mods(bool onlyOfficial) const override;
|
||||
virtual QString displayName(const QString& modName) const override;
|
||||
virtual QFileInfo referenceFile(const QString& modName) const override;
|
||||
virtual QStringList secondaryFiles(const QString& modName) const override;
|
||||
};
|
||||
|
||||
/// end Wrapper declarations
|
||||
/////////////////////////////
|
||||
|
||||
struct game_features_map_from_python {
|
||||
game_features_map_from_python();
|
||||
static void* convertible(PyObject* objPtr);
|
||||
static void
|
||||
construct(PyObject* objPtr,
|
||||
boost::python::converter::rvalue_from_python_stage1_data* data);
|
||||
};
|
||||
|
||||
void registerGameFeaturesPythonConverters();
|
||||
|
||||
#endif // GAMEFEATURESWRAPPERS_H
|
||||
@@ -1,12 +0,0 @@
|
||||
#include "gilock.h"
|
||||
|
||||
GILock::GILock()
|
||||
{
|
||||
m_State = PyGILState_Ensure();
|
||||
}
|
||||
|
||||
GILock::~GILock()
|
||||
{
|
||||
PyErr_Clear();
|
||||
PyGILState_Release(m_State);
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
#ifndef GILOCK_H
|
||||
#define GILOCK_H
|
||||
|
||||
#ifndef Q_MOC_RUN
|
||||
#include <boost/python.hpp>
|
||||
#endif // Q_MOC_RUN
|
||||
|
||||
class GILock {
|
||||
public:
|
||||
GILock();
|
||||
~GILock();
|
||||
|
||||
private:
|
||||
PyGILState_STATE m_State;
|
||||
};
|
||||
|
||||
#endif // GILOCK_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,299 +0,0 @@
|
||||
#ifndef PROXYPLUGINWRAPPERS_H
|
||||
#define PROXYPLUGINWRAPPERS_H
|
||||
|
||||
#include <iplugin.h>
|
||||
#include <iplugindiagnose.h>
|
||||
#include <ipluginfilemapper.h>
|
||||
#include <iplugingame.h>
|
||||
#include <iplugininstallercustom.h>
|
||||
#include <iplugininstallersimple.h>
|
||||
#include <ipluginmodpage.h>
|
||||
#include <ipluginpreview.h>
|
||||
#include <iplugintool.h>
|
||||
|
||||
#ifndef Q_MOC_RUN
|
||||
#include <boost/preprocessor/control/expr_if.hpp>
|
||||
#include <boost/python.hpp>
|
||||
#endif
|
||||
|
||||
// The wrapper for IPluginGame cannot override requirements or enabledByDefault since
|
||||
// they're final, so we need to be able to exclude the declarations.
|
||||
#define COMMON_I_PLUGIN_WRAPPER_DECLARATIONS_IMPL(include_requirements) \
|
||||
public: \
|
||||
virtual bool init(MOBase::IOrganizer* moInfo) override; \
|
||||
virtual QString name() const override; \
|
||||
virtual QString localizedName() const override; \
|
||||
virtual QString master() const override; \
|
||||
virtual QString author() const override; \
|
||||
virtual QString description() const override; \
|
||||
virtual MOBase::VersionInfo version() const override; \
|
||||
virtual QList<MOBase::PluginSetting> settings() const override; \
|
||||
QString localizedName_Default() const; \
|
||||
QString master_Default() const; \
|
||||
BOOST_PP_EXPR_IF( \
|
||||
include_requirements, \
|
||||
virtual std::vector<std::shared_ptr<const MOBase::IPluginRequirement>> \
|
||||
requirements() const override; \
|
||||
std::vector<std::shared_ptr<const MOBase::IPluginRequirement>> \
|
||||
requirements_Default() const; \
|
||||
virtual bool enabledByDefault() const override; \
|
||||
bool enabledByDefault_Default() const;)
|
||||
|
||||
#define COMMON_I_PLUGIN_WRAPPER_DECLARATIONS \
|
||||
COMMON_I_PLUGIN_WRAPPER_DECLARATIONS_IMPL(1)
|
||||
|
||||
// Even though the base interface is not a QObject, this has to be because we have no
|
||||
// way to pass Mod Organizer a plugin that implements multiple interfaces. QObject must
|
||||
// be the first base class because moc assumes the first base class is a QObject
|
||||
class IPluginWrapper : public QObject,
|
||||
public MOBase::IPlugin,
|
||||
public boost::python::wrapper<MOBase::IPlugin> {
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(MOBase::IPlugin)
|
||||
|
||||
COMMON_I_PLUGIN_WRAPPER_DECLARATIONS
|
||||
public:
|
||||
static constexpr const char* className = "IPluginWrapper";
|
||||
using boost::python::wrapper<MOBase::IPlugin>::get_override;
|
||||
};
|
||||
|
||||
// Even though the base interface is not an IPlugin or QObject, this has to be because
|
||||
// we have no way to pass Mod Organizer a plugin that implements multiple interfaces.
|
||||
// QObject must be the first base class because moc assumes the first base class is a
|
||||
// QObject
|
||||
class IPluginDiagnoseWrapper : public QObject,
|
||||
public MOBase::IPluginDiagnose,
|
||||
public MOBase::IPlugin,
|
||||
public boost::python::wrapper<MOBase::IPluginDiagnose> {
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(MOBase::IPlugin MOBase::IPluginDiagnose)
|
||||
|
||||
public:
|
||||
static constexpr const char* className = "IPluginDiagnoseWrapper";
|
||||
using boost::python::wrapper<MOBase::IPluginDiagnose>::get_override;
|
||||
|
||||
// Bring in public scope:
|
||||
using IPluginDiagnose::invalidate;
|
||||
|
||||
virtual std::vector<unsigned int> activeProblems() const override;
|
||||
virtual QString shortDescription(unsigned int key) const override;
|
||||
virtual QString fullDescription(unsigned int key) const override;
|
||||
virtual bool hasGuidedFix(unsigned int key) const override;
|
||||
virtual void startGuidedFix(unsigned int key) const override;
|
||||
|
||||
COMMON_I_PLUGIN_WRAPPER_DECLARATIONS
|
||||
};
|
||||
|
||||
// Even though the base interface is not an IPlugin or QObject, this has to be because
|
||||
// we have no way to pass Mod Organizer a plugin that implements multiple interfaces.
|
||||
// QObject must be the first base class because moc assumes the first base class is a
|
||||
// QObject
|
||||
class IPluginFileMapperWrapper
|
||||
: public QObject,
|
||||
public MOBase::IPluginFileMapper,
|
||||
public MOBase::IPlugin,
|
||||
public boost::python::wrapper<MOBase::IPluginFileMapper> {
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(MOBase::IPlugin MOBase::IPluginFileMapper)
|
||||
|
||||
public:
|
||||
static constexpr const char* className = "IPluginFileMapperWrapper";
|
||||
using boost::python::wrapper<MOBase::IPluginFileMapper>::get_override;
|
||||
|
||||
virtual MappingType mappings() const override;
|
||||
|
||||
COMMON_I_PLUGIN_WRAPPER_DECLARATIONS
|
||||
};
|
||||
|
||||
class IPluginGameWrapper : public MOBase::IPluginGame,
|
||||
public boost::python::wrapper<MOBase::IPluginGame> {
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(MOBase::IPlugin MOBase::IPluginGame)
|
||||
|
||||
public:
|
||||
static constexpr const char* className = "IPluginGameWrapper";
|
||||
using boost::python::wrapper<MOBase::IPluginGame>::get_override;
|
||||
|
||||
virtual void detectGame() override;
|
||||
virtual QString gameName() const override;
|
||||
virtual void initializeProfile(const QDir& directory,
|
||||
ProfileSettings settings) const override;
|
||||
virtual std::vector<std::shared_ptr<const MOBase::ISaveGame>>
|
||||
listSaves(QDir folder) const override;
|
||||
virtual bool isInstalled() const override;
|
||||
virtual QIcon gameIcon() const override;
|
||||
virtual QDir gameDirectory() const override;
|
||||
virtual QDir dataDirectory() const override;
|
||||
virtual void setGamePath(const QString& path) override;
|
||||
virtual QDir documentsDirectory() const override;
|
||||
virtual QDir savesDirectory() const override;
|
||||
virtual QList<MOBase::ExecutableInfo> executables() const override;
|
||||
virtual QList<MOBase::ExecutableForcedLoadSetting>
|
||||
executableForcedLoads() const override;
|
||||
virtual QString steamAPPId() const override;
|
||||
virtual QStringList primaryPlugins() const override;
|
||||
virtual QStringList gameVariants() const override;
|
||||
virtual void setGameVariant(const QString& variant) override;
|
||||
virtual QString binaryName() const override;
|
||||
virtual QString gameShortName() const override;
|
||||
virtual QStringList primarySources() const override;
|
||||
virtual QStringList validShortNames() const override;
|
||||
virtual QString gameNexusName() const override;
|
||||
virtual QStringList iniFiles() const override;
|
||||
virtual QStringList DLCPlugins() const override;
|
||||
virtual QStringList CCPlugins() const override;
|
||||
virtual LoadOrderMechanism loadOrderMechanism() const override;
|
||||
virtual SortMechanism sortMechanism() const override;
|
||||
virtual int nexusModOrganizerID() const override;
|
||||
virtual int nexusGameID() const override;
|
||||
virtual bool looksValid(QDir const& dir) const override;
|
||||
virtual QString gameVersion() const override;
|
||||
virtual QString getLauncherName() const override;
|
||||
|
||||
COMMON_I_PLUGIN_WRAPPER_DECLARATIONS_IMPL(0)
|
||||
|
||||
protected:
|
||||
// Apparently, Python developers interpret an underscore in a function name as it
|
||||
// being protected
|
||||
virtual std::map<std::type_index, std::any> featureList() const override;
|
||||
|
||||
// Thankfully, the default implementation of the templated 'T *feature()' function
|
||||
// should allow us to get away without overriding it.
|
||||
};
|
||||
|
||||
#define COMMON_I_PLUGIN_INSTALLER_WRAPPER_DECLARATIONS \
|
||||
public: \
|
||||
using IPluginInstaller::parentWidget; \
|
||||
using IPluginInstaller::manager; \
|
||||
virtual unsigned int priority() const override; \
|
||||
virtual bool isManualInstaller() const override; \
|
||||
virtual void onInstallationStart(QString const& archive, bool reinstallation, \
|
||||
MOBase::IModInterface* currentMod) override; \
|
||||
void onInstallationStart_Default(QString const& archive, bool reinstallation, \
|
||||
MOBase::IModInterface* currentMod) \
|
||||
{ \
|
||||
return IPluginInstaller::onInstallationStart(archive, reinstallation, \
|
||||
currentMod); \
|
||||
} \
|
||||
virtual void onInstallationEnd(EInstallResult result, \
|
||||
MOBase::IModInterface* newMod) override; \
|
||||
void onInstallationEnd_Default(EInstallResult result, \
|
||||
MOBase::IModInterface* newMod) \
|
||||
{ \
|
||||
return IPluginInstaller::onInstallationEnd(result, newMod); \
|
||||
} \
|
||||
virtual bool isArchiveSupported(std::shared_ptr<const MOBase::IFileTree> tree) \
|
||||
const override;
|
||||
|
||||
class IPluginInstallerSimpleWrapper
|
||||
: public MOBase::IPluginInstallerSimple,
|
||||
public boost::python::wrapper<MOBase::IPluginInstallerSimple> {
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(
|
||||
MOBase::IPlugin MOBase::IPluginInstaller MOBase::IPluginInstallerSimple)
|
||||
|
||||
COMMON_I_PLUGIN_WRAPPER_DECLARATIONS
|
||||
COMMON_I_PLUGIN_INSTALLER_WRAPPER_DECLARATIONS
|
||||
|
||||
public:
|
||||
static constexpr const char* className = "IPluginInstallerSimpleWrapper";
|
||||
using boost::python::wrapper<MOBase::IPluginInstallerSimple>::get_override;
|
||||
|
||||
virtual EInstallResult install(MOBase::GuessedValue<QString>& modName,
|
||||
std::shared_ptr<MOBase::IFileTree>& tree,
|
||||
QString& version, int& nexusID) override;
|
||||
};
|
||||
|
||||
class IPluginInstallerCustomWrapper
|
||||
: public MOBase::IPluginInstallerCustom,
|
||||
public boost::python::wrapper<MOBase::IPluginInstallerCustom> {
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(
|
||||
MOBase::IPlugin MOBase::IPluginInstaller MOBase::IPluginInstallerCustom)
|
||||
|
||||
COMMON_I_PLUGIN_WRAPPER_DECLARATIONS
|
||||
|
||||
COMMON_I_PLUGIN_INSTALLER_WRAPPER_DECLARATIONS
|
||||
|
||||
public:
|
||||
static constexpr const char* className = "IPluginInstallerCustomWrapper";
|
||||
using boost::python::wrapper<MOBase::IPluginInstallerCustom>::get_override;
|
||||
|
||||
virtual bool isArchiveSupported(const QString& archiveName) const override;
|
||||
virtual std::set<QString> supportedExtensions() const override;
|
||||
virtual EInstallResult install(MOBase::GuessedValue<QString>& modName,
|
||||
QString gameName, const QString& archiveName,
|
||||
const QString& version, int modID) override;
|
||||
};
|
||||
|
||||
class IPluginModPageWrapper : public MOBase::IPluginModPage,
|
||||
public boost::python::wrapper<MOBase::IPluginModPage> {
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(MOBase::IPlugin MOBase::IPluginModPage)
|
||||
|
||||
COMMON_I_PLUGIN_WRAPPER_DECLARATIONS
|
||||
public:
|
||||
static constexpr const char* className = "IPluginModPageWrapper";
|
||||
using boost::python::wrapper<MOBase::IPluginModPage>::get_override;
|
||||
|
||||
// Bring in public scope:
|
||||
using IPluginModPage::parentWidget;
|
||||
|
||||
virtual QString displayName() const override;
|
||||
virtual QIcon icon() const override;
|
||||
virtual QUrl pageURL() const override;
|
||||
virtual bool useIntegratedBrowser() const override;
|
||||
virtual bool
|
||||
handlesDownload(const QUrl& pageURL, const QUrl& downloadURL,
|
||||
MOBase::ModRepositoryFileInfo& fileInfo) const override;
|
||||
virtual void setParentWidget(QWidget* widget) override;
|
||||
|
||||
void setParentWidget_Default(QWidget* parent)
|
||||
{
|
||||
IPluginModPage::setParentWidget(parent);
|
||||
}
|
||||
};
|
||||
|
||||
class IPluginPreviewWrapper : public MOBase::IPluginPreview,
|
||||
public boost::python::wrapper<MOBase::IPluginPreview> {
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(MOBase::IPlugin MOBase::IPluginPreview)
|
||||
|
||||
COMMON_I_PLUGIN_WRAPPER_DECLARATIONS
|
||||
public:
|
||||
static constexpr const char* className = "IPluginPreviewWrapper";
|
||||
using boost::python::wrapper<MOBase::IPluginPreview>::get_override;
|
||||
|
||||
virtual std::set<QString> supportedExtensions() const override;
|
||||
virtual QWidget* genFilePreview(const QString& fileName,
|
||||
const QSize& maxSize) const override;
|
||||
};
|
||||
|
||||
class IPluginToolWrapper : public MOBase::IPluginTool,
|
||||
public boost::python::wrapper<MOBase::IPluginTool> {
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(MOBase::IPlugin MOBase::IPluginTool)
|
||||
|
||||
COMMON_I_PLUGIN_WRAPPER_DECLARATIONS
|
||||
public:
|
||||
static constexpr const char* className = "IPluginToolWrapper";
|
||||
using boost::python::wrapper<MOBase::IPluginTool>::get_override;
|
||||
|
||||
// Bring in public scope:
|
||||
using IPluginTool::parentWidget;
|
||||
|
||||
virtual QString displayName() const override;
|
||||
virtual QString tooltip() const override;
|
||||
virtual QIcon icon() const override;
|
||||
virtual void setParentWidget(QWidget* parent) override;
|
||||
|
||||
void setParentWidget_Default(QWidget* parent)
|
||||
{
|
||||
IPluginTool::setParentWidget(parent);
|
||||
}
|
||||
|
||||
public Q_SLOTS:
|
||||
virtual void display() const override;
|
||||
};
|
||||
|
||||
#endif // PROXYPLUGINWRAPPERS_H
|
||||
@@ -0,0 +1,50 @@
|
||||
#ifndef PYTHON_PYBIND11_QT_DETAILS_QLIST_HPP
|
||||
#define PYTHON_PYBIND11_QT_DETAILS_QLIST_HPP
|
||||
|
||||
#include <pybind11/pybind11.h>
|
||||
#include <pybind11/stl.h>
|
||||
|
||||
namespace pybind11::detail::qt {
|
||||
|
||||
// helper class for QList to construct from any proper iterable
|
||||
//
|
||||
template <typename Type, typename Value>
|
||||
struct qlist_caster {
|
||||
using value_conv = make_caster<Value>;
|
||||
|
||||
bool load(handle src, bool convert)
|
||||
{
|
||||
if (!isinstance<iterable>(src) || isinstance<bytes>(src) ||
|
||||
isinstance<str>(src)) {
|
||||
return false;
|
||||
}
|
||||
auto s = reinterpret_borrow<iterable>(src);
|
||||
value.clear();
|
||||
|
||||
if (isinstance<sequence>(src)) {
|
||||
value.reserve(s.cast<sequence>().size());
|
||||
}
|
||||
for (auto it : s) {
|
||||
value_conv conv;
|
||||
if (!conv.load(it, convert)) {
|
||||
return false;
|
||||
}
|
||||
value.push_back(cast_op<Value&&>(std::move(conv)));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static handle cast(T&& src, return_value_policy policy, handle parent)
|
||||
{
|
||||
return list_caster<QList<Value>, Value>{}.cast(std::forward<T>(src), policy,
|
||||
parent);
|
||||
}
|
||||
|
||||
PYBIND11_TYPE_CASTER(Type, const_name("Iterable[") + value_conv::name +
|
||||
const_name("]"));
|
||||
};
|
||||
|
||||
} // namespace pybind11::detail::qt
|
||||
|
||||
#endif
|
||||
@@ -11,45 +11,45 @@
|
||||
// this needs to be included here to get proper QVariantList and QVariantMap
|
||||
#include "details/pybind11_qt_qmap.h"
|
||||
#include "pybind11_qt_basic.h"
|
||||
#include "details/pybind11_qt_qlist.h"
|
||||
|
||||
namespace pybind11::detail {
|
||||
|
||||
// QList
|
||||
//
|
||||
template <class T>
|
||||
struct type_caster<QList<T>> : list_caster<QList<T>, T> {
|
||||
struct type_caster<QList<T>> : qt::qlist_caster<QList<T>, T> {
|
||||
};
|
||||
|
||||
// QSet
|
||||
//
|
||||
// template <class T>
|
||||
// struct type_caster<QSet<T>> : set_caster<QList<T>, T> {
|
||||
// };
|
||||
template <class T>
|
||||
struct type_caster<QSet<T>> : set_caster<QList<T>, T> {
|
||||
};
|
||||
|
||||
// QMap
|
||||
//
|
||||
// template <class K, class V>
|
||||
// struct type_caster<QMap<K, V>> : qt::qmap_caster<QMap<K, V>, K, V> {
|
||||
// };
|
||||
template <class K, class V>
|
||||
struct type_caster<QMap<K, V>> : qt::qmap_caster<QMap<K, V>, K, V> {
|
||||
};
|
||||
|
||||
// QStringList
|
||||
//
|
||||
template <>
|
||||
struct type_caster<QStringList> : list_caster<QStringList, QString> {
|
||||
struct type_caster<QStringList> : qt::qlist_caster<QStringList, QString> {
|
||||
};
|
||||
|
||||
// QVariantList
|
||||
//
|
||||
// template <>
|
||||
// struct type_caster<QVariantList> : list_caster<QVariantList, QVariant> {
|
||||
// };
|
||||
template <>
|
||||
struct type_caster<QVariantList> : qt::qlist_caster<QVariantList, QVariant> {
|
||||
};
|
||||
|
||||
// QVariantMap
|
||||
//
|
||||
// template <>
|
||||
// struct type_caster<QVariantMap>
|
||||
// : qt::qmap_caster<QVariantMap, QString, QVariant> {
|
||||
// };
|
||||
template <>
|
||||
struct type_caster<QVariantMap> : qt::qmap_caster<QVariantMap, QString, QVariant> {
|
||||
};
|
||||
|
||||
} // namespace pybind11::detail
|
||||
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="en_US">
|
||||
<context>
|
||||
<name>QObject</name>
|
||||
<message>
|
||||
<location filename="error.h" line="68"/>
|
||||
<source>An unexpected C++ exception was thrown in python code.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="error.h" line="117"/>
|
||||
<source>An unknown exception was thrown in python code.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
@@ -1,202 +0,0 @@
|
||||
#ifndef PYTHONWRAPPERUTILITIES_H
|
||||
#define PYTHONWRAPPERUTILITIES_H
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include <boost/python.hpp>
|
||||
|
||||
#include <log.h>
|
||||
#include <utility.h>
|
||||
|
||||
#include "error.h"
|
||||
#include "gilock.h"
|
||||
// #include "pybind11_qt/pybind11_qt.h"
|
||||
|
||||
namespace details {
|
||||
|
||||
/**
|
||||
* @brief Common stuffs for all basicWrapperFunction methods.
|
||||
*/
|
||||
template <class ReturnType, class WrapperTypePtr, class Fn, class... Args>
|
||||
ReturnType wrapperFunctionImplementation(WrapperTypePtr wrapper, bool apiTransfer,
|
||||
Fn fn, boost::python::object* objPtr,
|
||||
const char* methodName, Args... args)
|
||||
{
|
||||
boost::python::override implementation = [&]() {
|
||||
GILock lock;
|
||||
return wrapper->get_override(methodName);
|
||||
}();
|
||||
if (!implementation) {
|
||||
if constexpr (std::is_same_v<Fn, std::nullptr_t>) {
|
||||
throw pyexcept::MissingImplementation(wrapper->className, methodName);
|
||||
}
|
||||
else {
|
||||
return std::invoke(fn, wrapper, args...);
|
||||
}
|
||||
}
|
||||
|
||||
GILock lock;
|
||||
try {
|
||||
boost::python::object result = implementation(args...);
|
||||
if (objPtr) {
|
||||
*objPtr = result;
|
||||
}
|
||||
else if (apiTransfer) {
|
||||
// pybind11::detail::qt::sipAPI()->api_transfer_to(result.ptr(),
|
||||
// Py_None);
|
||||
}
|
||||
if constexpr (!std::is_same_v<ReturnType, void>) {
|
||||
return boost::python::extract<ReturnType>(result)();
|
||||
}
|
||||
}
|
||||
catch (const boost::python::error_already_set&) {
|
||||
throw pyexcept::PythonError("");
|
||||
}
|
||||
catch (...) {
|
||||
throw pyexcept::UnknownException();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace details
|
||||
|
||||
/**
|
||||
* @brief Call the given method on the wrapper with the given arguments, with
|
||||
* proper exception handling.
|
||||
*
|
||||
* @param wrapper The wrapper object to use to retrieve the python method. Must
|
||||
* have a publicly available `className` attribute.
|
||||
* @param methodName The name of the method.
|
||||
* @param args... Arguments for the method.
|
||||
*
|
||||
* @return the result of calling the given Python method on the wrapper.
|
||||
*
|
||||
* @throw pyexcept::MissingImplementation if the method does not exist.
|
||||
* @throw pyexcept::PythonError if an error occurs while executing the python
|
||||
* method.
|
||||
* @throw pyexecpt::UnknownException if an unknown error occurs.
|
||||
*/
|
||||
template <class ReturnType, class WrapperType, class... Args>
|
||||
ReturnType basicWrapperFunctionImplementation(const WrapperType* wrapper,
|
||||
const char* methodName, Args... args)
|
||||
{
|
||||
return details::wrapperFunctionImplementation<ReturnType>(
|
||||
wrapper, false, nullptr, nullptr, methodName, args...);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Call the given method on the wrapper with the given arguments, with
|
||||
* proper exception handling, and store the intermediate result in the given
|
||||
* python object.
|
||||
*
|
||||
* @param wrapper The wrapper object to use to retrieve the python method. Must
|
||||
* have a publicly available `className` attribute.
|
||||
* @param ref Python object to which the result of `get_override()` should be
|
||||
* stored.
|
||||
* @param methodName The name of the method.
|
||||
* @param args... Arguments for the method.
|
||||
*
|
||||
* @return the result of calling the given Python method on the wrapper.
|
||||
*
|
||||
* @throw pyexcept::MissingImplementation if the method does not exist.
|
||||
* @throw pyexcept::PythonError if an error occurs while executing the python
|
||||
* method.
|
||||
* @throw pyexecpt::UnknownException if an unknown error occurs.
|
||||
*/
|
||||
template <class ReturnType, class WrapperType, class... Args>
|
||||
ReturnType basicWrapperFunctionImplementation(const WrapperType* wrapper,
|
||||
boost::python::object& ref,
|
||||
const char* methodName, Args... args)
|
||||
{
|
||||
return details::wrapperFunctionImplementation<ReturnType>(
|
||||
wrapper, false, nullptr, &ref, methodName, args...);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Call the given method on the wrapper with the given arguments, with
|
||||
* proper exception handling, and transfer the responsibility of the returned
|
||||
* object to the C++ side.
|
||||
*
|
||||
* @param wrapper The wrapper object to use to retrieve the python method. Must
|
||||
* have a publicly available `className` attribute.
|
||||
* @param methodName The name of the method.
|
||||
* @param args... Arguments for the method.
|
||||
*
|
||||
* @return the result of calling the given Python method on the wrapper.
|
||||
*
|
||||
* @throw pyexcept::MissingImplementation if the method does not exist.
|
||||
* @throw pyexcept::PythonError if an error occurs while executing the python
|
||||
* method.
|
||||
* @throw pyexecpt::UnknownException if an unknown error occurs.
|
||||
*/
|
||||
template <class ReturnType, class WrapperType, class... Args>
|
||||
ReturnType wrapperFunctionImplementationWithApiTransfer(const WrapperType* wrapper,
|
||||
const char* methodName,
|
||||
Args... args)
|
||||
{
|
||||
return details::wrapperFunctionImplementation<ReturnType>(
|
||||
wrapper, true, nullptr, nullptr, methodName, args...);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Call the given method on the wrapper with the given arguments, with
|
||||
* proper exception handling, falling back to the given function if the method
|
||||
* does not exist.
|
||||
*
|
||||
* @param wrapper The wrapper object to use to retrieve the python method. Must
|
||||
* have a publicly available `className` attribute.
|
||||
* @param fn The function to call if the method does not exists.
|
||||
* @param methodName The name of the method.
|
||||
* @param args... Arguments for the method.
|
||||
*
|
||||
* Note: `fn` does not have to be a member-function of `wrapper` but
|
||||
* `std::invoke(fn, wrapper, args...)` must be valid.
|
||||
*
|
||||
* @return the result of calling the given Python method on the wrapper.
|
||||
*
|
||||
* @throw pyexcept::PythonError if an error occurs while executing the python
|
||||
* method.
|
||||
* @throw pyexecpt::UnknownException if an unknown error occurs.
|
||||
*/
|
||||
template <class ReturnType, class WrapperTypePtr, class Fn, class... Args>
|
||||
ReturnType basicWrapperFunctionImplementationWithDefault(WrapperTypePtr wrapper, Fn fn,
|
||||
const char* methodName,
|
||||
Args... args)
|
||||
{
|
||||
return details::wrapperFunctionImplementation<ReturnType>(
|
||||
wrapper, false, fn, nullptr, methodName, args...);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Call the given method on the wrapper with the given arguments, with
|
||||
* proper exception handling, and store the intermediate result in the given
|
||||
* python object, falling back to the given function if the method does not
|
||||
* exist.
|
||||
*
|
||||
* @param wrapper The wrapper object to use to retrieve the python method. Must
|
||||
* have a publicly available `className` attribute.
|
||||
* @param fn The function to call if the method does not exists.
|
||||
* @param ref Python object to which the result of `get_override()` should be
|
||||
* stored.
|
||||
* @param methodName The name of the method.
|
||||
* @param args... Arguments for the method.
|
||||
*
|
||||
* Note: `fn` does not have to be a member-function of `wrapper` but
|
||||
* `std::invoke(fn, wrapper, args...)` must be valid.
|
||||
*
|
||||
* @return the result of calling the given Python method on the wrapper.
|
||||
*
|
||||
* @throw pyexcept::PythonError if an error occurs while executing the python
|
||||
* method.
|
||||
* @throw pyexecpt::UnknownException if an unknown error occurs.
|
||||
*/
|
||||
template <class ReturnType, class WrapperType, class Fn, class... Args>
|
||||
ReturnType
|
||||
basicWrapperFunctionImplementationWithDefault(const WrapperType* wrapper, Fn fn,
|
||||
boost::python::object& ref,
|
||||
const char* methodName, Args... args)
|
||||
{
|
||||
return details::wrapperFunctionImplementation<ReturnType>(wrapper, false, fn, &ref,
|
||||
methodName, args...);
|
||||
}
|
||||
|
||||
#endif // PYTHONWRAPPERUTILITIES_H
|
||||
@@ -1,139 +0,0 @@
|
||||
#ifndef PYTHONRUNNER_SHARED_PTR_CONVERTER_H
|
||||
#define PYTHONRUNNER_SHARED_PTR_CONVERTER_H
|
||||
|
||||
#include <boost/python.hpp>
|
||||
|
||||
#include "error.h"
|
||||
#include "gilock.h"
|
||||
|
||||
namespace utils {
|
||||
|
||||
// Shared pointers are handled in a special way by Boost.Python since they hold
|
||||
// the wrapped Python object and only release it when the ref counter of the shared
|
||||
// ptr drops to 0 using shared_ptr_deleter.
|
||||
//
|
||||
// Unfortunately for us, this will happen outside of the Python proxy for some
|
||||
// objects and thus without the GIL lock, making everything crash, so we need a
|
||||
// custom deleter that holds the GIL while releasing the lock.
|
||||
//
|
||||
// Note that this is only useful for Python -> C++ conversion, and without this,
|
||||
// Boost will automatically wrapped the pointer. The C++ -> Python conversion is
|
||||
// handled separately by boost::python::register_ptr_to_python.
|
||||
//
|
||||
// This is an open Boost.Python problem: https://github.com/boostorg/python/pull/11
|
||||
|
||||
template <class SharedPtr>
|
||||
struct shared_ptr_from_python;
|
||||
|
||||
namespace details {
|
||||
|
||||
struct shared_ptr_deleter_with_gil_lock
|
||||
: boost::python::converter::shared_ptr_deleter {
|
||||
|
||||
using shared_ptr_deleter::shared_ptr_deleter;
|
||||
|
||||
void operator()(void const* o)
|
||||
{
|
||||
GILock lock;
|
||||
shared_ptr_deleter::operator()(o);
|
||||
}
|
||||
};
|
||||
|
||||
template <class SharedPtr>
|
||||
struct shared_ptr_void;
|
||||
|
||||
template <class T>
|
||||
struct shared_ptr_void<std::shared_ptr<T>> {
|
||||
using type = std::shared_ptr<void>;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct shared_ptr_void<boost::shared_ptr<T>> {
|
||||
using type = boost::shared_ptr<void>;
|
||||
};
|
||||
|
||||
template <class SharedPtr>
|
||||
using shared_ptr_void_t = typename shared_ptr_void<SharedPtr>::type;
|
||||
|
||||
} // namespace details
|
||||
|
||||
template <class SharedPtr>
|
||||
struct shared_ptr_from_python {
|
||||
using T = typename SharedPtr::element_type;
|
||||
|
||||
shared_ptr_from_python()
|
||||
{
|
||||
using namespace boost::python;
|
||||
converter::registry::insert(
|
||||
&convertible, &construct, type_id<SharedPtr>()
|
||||
#ifndef BOOST_PYTHON_NO_PY_SIGNATURES
|
||||
,
|
||||
&converter::expected_from_python_type_direct<T>::get_pytype
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
private:
|
||||
static void* convertible(PyObject* p)
|
||||
{
|
||||
if (p == Py_None)
|
||||
return p;
|
||||
|
||||
return boost::python::converter::get_lvalue_from_python(
|
||||
p, boost::python::converter::registered<T>::converters);
|
||||
}
|
||||
|
||||
static void
|
||||
construct(PyObject* source,
|
||||
boost::python::converter::rvalue_from_python_stage1_data* data)
|
||||
{
|
||||
using namespace boost::python;
|
||||
void* const storage =
|
||||
((converter::rvalue_from_python_storage<SharedPtr>*)data)
|
||||
->storage.bytes;
|
||||
// Deal with the "None" case.
|
||||
if (data->convertible == source)
|
||||
new (storage) SharedPtr();
|
||||
else {
|
||||
details::shared_ptr_void_t<SharedPtr> hold_convertible_ref_count(
|
||||
(void*)0, details::shared_ptr_deleter_with_gil_lock(
|
||||
handle<>(borrowed(source))));
|
||||
// use aliasing constructor
|
||||
new (storage) SharedPtr(hold_convertible_ref_count,
|
||||
static_cast<T*>(data->convertible));
|
||||
}
|
||||
|
||||
data->convertible = storage;
|
||||
}
|
||||
};
|
||||
|
||||
// release the bpy::object associated with the deleter of the given shared_ptr,
|
||||
// if the given shared_ptr has a Boost.Python deleter
|
||||
//
|
||||
// this should only be used when returning from Python objects that have been
|
||||
// created on the C++ side, e.g. if IFileTree.createOrphanTree() from Python and
|
||||
// then return the tree
|
||||
//
|
||||
// for reason yet to be known, Boost.Python had a custom deleter in this case that
|
||||
// tries to delete the bpy::object and fails, so we have to release the object
|
||||
// manually
|
||||
//
|
||||
template <class SharedPtr>
|
||||
SharedPtr clean_shared_ptr(SharedPtr&& ptr)
|
||||
{
|
||||
if (auto* d = get_deleter<boost::python::converter::shared_ptr_deleter>(ptr);
|
||||
d != nullptr) {
|
||||
// we cannot do a proper reset() here, even with the GIL lock, for unknown
|
||||
// reason, so we only release
|
||||
//
|
||||
// this might create lost references to Python object but this should not
|
||||
// happen too often so hopefully it's not a big issue
|
||||
//
|
||||
d->owner.release();
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
} // namespace utils
|
||||
|
||||
#endif
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "wrappers.h"
|
||||
|
||||
#include <tuple>
|
||||
|
||||
#include <pybind11/functional.h>
|
||||
#include <pybind11/operators.h>
|
||||
#include <pybind11/pybind11.h>
|
||||
@@ -7,8 +9,18 @@
|
||||
|
||||
#include "../pybind11_qt/pybind11_qt.h"
|
||||
|
||||
#include <ipluginlist.h>
|
||||
#include <isavegameinfowidget.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>
|
||||
|
||||
#include "pyfiletree.h"
|
||||
|
||||
@@ -18,6 +30,85 @@ using namespace pybind11::literals;
|
||||
|
||||
namespace mo2::python {
|
||||
|
||||
class PyBSAInvalidation : public BSAInvalidation {
|
||||
public:
|
||||
bool isInvalidationBSA(const QString& bsaName) override
|
||||
{
|
||||
PYBIND11_OVERRIDE_PURE(bool, BSAInvalidation, isInvalidationBSA, bsaName);
|
||||
}
|
||||
void deactivate(MOBase::IProfile* profile) override
|
||||
{
|
||||
PYBIND11_OVERRIDE_PURE(void, BSAInvalidation, deactivate, profile);
|
||||
}
|
||||
void activate(MOBase::IProfile* profile) override
|
||||
{
|
||||
PYBIND11_OVERRIDE_PURE(void, BSAInvalidation, activate, profile);
|
||||
}
|
||||
bool prepareProfile(MOBase::IProfile* profile) override
|
||||
{
|
||||
PYBIND11_OVERRIDE_PURE(bool, BSAInvalidation, prepareProfile, profile);
|
||||
}
|
||||
};
|
||||
|
||||
class PyDataArchives : public DataArchives {
|
||||
public:
|
||||
QStringList vanillaArchives() const override
|
||||
{
|
||||
PYBIND11_OVERRIDE_PURE(QStringList, DataArchives, vanillaArchives, );
|
||||
}
|
||||
QStringList archives(const MOBase::IProfile* profile) const override
|
||||
{
|
||||
PYBIND11_OVERRIDE_PURE(QStringList, DataArchives, archives, profile);
|
||||
}
|
||||
void addArchive(MOBase::IProfile* profile, int index,
|
||||
const QString& archiveName) override
|
||||
{
|
||||
PYBIND11_OVERRIDE_PURE(void, DataArchives, addArchive, profile, index,
|
||||
archiveName);
|
||||
}
|
||||
void removeArchive(MOBase::IProfile* profile,
|
||||
const QString& archiveName) override
|
||||
{
|
||||
PYBIND11_OVERRIDE_PURE(void, DataArchives, removeArchive, profile,
|
||||
archiveName);
|
||||
}
|
||||
};
|
||||
|
||||
class PyGamePlugins : public GamePlugins {
|
||||
public:
|
||||
void writePluginLists(const MOBase::IPluginList* pluginList) override
|
||||
{
|
||||
PYBIND11_OVERRIDE_PURE(void, GamePlugins, writePluginLists, pluginList);
|
||||
}
|
||||
void readPluginLists(MOBase::IPluginList* pluginList) override
|
||||
{
|
||||
// TODO: cannot update plugin list or create one from Python so this is
|
||||
// useless
|
||||
PYBIND11_OVERRIDE_PURE(void, GamePlugins, readPluginLists, pluginList);
|
||||
}
|
||||
QStringList getLoadOrder() override
|
||||
{
|
||||
PYBIND11_OVERRIDE_PURE(QStringList, GamePlugins, getLoadOrder, );
|
||||
}
|
||||
bool lightPluginsAreSupported() override
|
||||
{
|
||||
PYBIND11_OVERRIDE_PURE(bool, GamePlugins, lightPluginsAreSupported, );
|
||||
}
|
||||
};
|
||||
|
||||
class PyLocalSavegames : public LocalSavegames {
|
||||
public:
|
||||
MappingType mappings(const QDir& profileSaveDir) const override
|
||||
{
|
||||
PYBIND11_OVERRIDE_PURE(MappingType, LocalSavegames, mappings,
|
||||
profileSaveDir);
|
||||
}
|
||||
bool prepareProfile(MOBase::IProfile* profile) override
|
||||
{
|
||||
PYBIND11_OVERRIDE_PURE(bool, LocalSavegames, prepareProfile, profile);
|
||||
}
|
||||
};
|
||||
|
||||
class PyModDataChecker : public ModDataChecker {
|
||||
public:
|
||||
CheckReturn
|
||||
@@ -35,6 +126,37 @@ namespace mo2::python {
|
||||
}
|
||||
};
|
||||
|
||||
class PyModDataContent : public ModDataContent {
|
||||
public:
|
||||
std::vector<Content> getAllContents() const override
|
||||
{
|
||||
PYBIND11_OVERRIDE_PURE(std::vector<Content>, ModDataContent,
|
||||
getAllContents, );
|
||||
;
|
||||
}
|
||||
std::vector<int>
|
||||
getContentsFor(std::shared_ptr<const MOBase::IFileTree> fileTree) const override
|
||||
{
|
||||
PYBIND11_OVERRIDE_PURE(std::vector<int>, ModDataContent, getContentsFor,
|
||||
fileTree);
|
||||
}
|
||||
};
|
||||
|
||||
class PySaveGameInfo : public SaveGameInfo {
|
||||
public:
|
||||
MissingAssets getMissingAssets(MOBase::ISaveGame const& save) const override
|
||||
{
|
||||
PYBIND11_OVERRIDE_PURE(MissingAssets, SaveGameInfo, getMissingAssets,
|
||||
&save);
|
||||
}
|
||||
ISaveGameInfoWidget* getSaveGameWidget(QWidget* parent = 0) const override
|
||||
{
|
||||
// TODO: transfer ownership
|
||||
PYBIND11_OVERRIDE_PURE(ISaveGameInfoWidget*, SaveGameInfo,
|
||||
getSaveGameWidget, parent);
|
||||
}
|
||||
};
|
||||
|
||||
class PyScriptExtender : public ScriptExtender {
|
||||
public:
|
||||
QString BinaryName() const override
|
||||
@@ -78,8 +200,62 @@ namespace mo2::python {
|
||||
}
|
||||
};
|
||||
|
||||
class PyPyUnmanagedMods : public UnmanagedMods {
|
||||
public:
|
||||
QStringList mods(bool onlyOfficial) const override
|
||||
{
|
||||
PYBIND11_OVERRIDE_PURE(QStringList, UnmanagedMods, mods, onlyOfficial);
|
||||
}
|
||||
QString displayName(const QString& modName) const override
|
||||
{
|
||||
PYBIND11_OVERRIDE_PURE(QString, UnmanagedMods, displayName, modName);
|
||||
}
|
||||
QFileInfo referenceFile(const QString& modName) const override
|
||||
{
|
||||
PYBIND11_OVERRIDE_PURE(QFileInfo, UnmanagedMods, referenceFile, modName);
|
||||
}
|
||||
QStringList secondaryFiles(const QString& modName) const override
|
||||
{
|
||||
PYBIND11_OVERRIDE_PURE(QStringList, UnmanagedMods, secondaryFiles, modName);
|
||||
}
|
||||
};
|
||||
|
||||
void add_game_feature_bindings(pybind11::module_ m)
|
||||
{
|
||||
// BSAInvalidation
|
||||
|
||||
py::class_<BSAInvalidation, PyBSAInvalidation>(m, "BSAInvalidation")
|
||||
.def(py::init<>())
|
||||
.def("isInvalidationBSA", &BSAInvalidation::isInvalidationBSA, "name"_a)
|
||||
.def("deactivate", &BSAInvalidation::deactivate, "profile"_a)
|
||||
.def("activate", &BSAInvalidation::activate, "profile"_a);
|
||||
|
||||
// DataArchives
|
||||
|
||||
py::class_<DataArchives, PyDataArchives>(m, "DataArchives")
|
||||
.def(py::init<>())
|
||||
.def("vanillaArchives", &DataArchives::vanillaArchives)
|
||||
.def("archives", &DataArchives::archives, "profile"_a)
|
||||
.def("addArchive", &DataArchives::addArchive,
|
||||
("profile"_a, "index", "name"))
|
||||
.def("removeArchive", &DataArchives::removeArchive, "profile"_a, "name"_a);
|
||||
|
||||
// GamePlugins
|
||||
|
||||
py::class_<GamePlugins, PyGamePlugins>(m, "GamePlugins")
|
||||
.def(py::init<>())
|
||||
.def("writePluginLists", &GamePlugins::writePluginLists, "plugin_list"_a)
|
||||
.def("readPluginLists", &GamePlugins::readPluginLists, "plugin_list"_a)
|
||||
.def("getLoadOrder", &GamePlugins::getLoadOrder)
|
||||
.def("lightPluginsAreSupported", &GamePlugins::lightPluginsAreSupported);
|
||||
|
||||
// LocalSavegames
|
||||
|
||||
py::class_<LocalSavegames, PyLocalSavegames>(m, "LocalSavegames")
|
||||
.def(py::init<>())
|
||||
.def("mappings", &LocalSavegames::mappings, "profile_save_dir"_a)
|
||||
.def("prepareProfile", &LocalSavegames::prepareProfile, "profile"_a);
|
||||
|
||||
// ModDataChecker
|
||||
|
||||
py::class_<ModDataChecker, PyModDataChecker> pyModDataChecker(m,
|
||||
@@ -95,6 +271,30 @@ namespace mo2::python {
|
||||
.def("dataLooksValid", &ModDataChecker::dataLooksValid, "filetree"_a)
|
||||
.def("fix", &ModDataChecker::fix, "filetree"_a);
|
||||
|
||||
// ModDataContent
|
||||
py::class_<ModDataContent, PyModDataContent> pyModDataContent(m,
|
||||
"ModDataContent");
|
||||
|
||||
py::class_<ModDataContent::Content>(pyModDataContent, "Content")
|
||||
.def(py::init<int, QString, QString, bool>(), "id"_a, "name"_a, "icon"_a,
|
||||
"filter_only"_a = false)
|
||||
.def_property_readonly("id", &ModDataContent::Content::id)
|
||||
.def_property_readonly("name", &ModDataContent::Content::name)
|
||||
.def_property_readonly("icon", &ModDataContent::Content::icon)
|
||||
.def("isOnlyForFilter", &ModDataContent::Content::isOnlyForFilter);
|
||||
|
||||
pyModDataContent.def(py::init<>())
|
||||
.def("getAllContents", &ModDataContent::getAllContents)
|
||||
.def("getContentsFor", &ModDataContent::getContentsFor, "filetree"_a);
|
||||
|
||||
// SaveGameInfo
|
||||
|
||||
py::class_<SaveGameInfo, PySaveGameInfo>(m, "SaveGameInfo")
|
||||
.def(py::init<>())
|
||||
.def("getMissingAssets", &SaveGameInfo::getMissingAssets, "save"_a)
|
||||
.def("getSaveGameWidget", &SaveGameInfo::getSaveGameWidget,
|
||||
py::return_value_policy::reference, "parent"_a, "[optional]");
|
||||
|
||||
// ScriptExtender
|
||||
|
||||
py::class_<ScriptExtender, PyScriptExtender>(m, "ScriptExtender")
|
||||
@@ -107,6 +307,81 @@ namespace mo2::python {
|
||||
.def("isInstalled", &ScriptExtender::isInstalled)
|
||||
.def("getExtenderVersion", &ScriptExtender::getExtenderVersion)
|
||||
.def("getArch", &ScriptExtender::getArch);
|
||||
|
||||
// UnmanagedMods
|
||||
|
||||
py::class_<UnmanagedMods, PyPyUnmanagedMods>(m, "UnmanagedMods")
|
||||
.def(py::init<>())
|
||||
.def("mods", &UnmanagedMods::mods, "official_only"_a)
|
||||
.def("displayName", &UnmanagedMods::displayName, "mod_name"_a)
|
||||
.def("referenceFile", &UnmanagedMods::referenceFile, "mod_name"_a)
|
||||
.def("secondaryFiles", &UnmanagedMods::secondaryFiles, "mod_name"_a);
|
||||
}
|
||||
|
||||
} // namespace mo2::python
|
||||
|
||||
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>>{});
|
||||
}
|
||||
};
|
||||
|
||||
pybind11::object extract_feature(IPluginGame const& game, pybind11::object type)
|
||||
{
|
||||
py::object py_feature = py::none();
|
||||
GameFeaturesHelper::apply([&]<class Feature>(Feature* feature) {
|
||||
if (py::type::of<Feature>().is(type)) {
|
||||
py_feature = py::cast(game.feature<Feature>(),
|
||||
py::return_value_policy::reference);
|
||||
}
|
||||
});
|
||||
return py_feature;
|
||||
}
|
||||
|
||||
pybind11::dict extract_feature_list(IPluginGame const& game)
|
||||
{
|
||||
// constructing a dict from class name to actual object
|
||||
py::dict dict;
|
||||
GameFeaturesHelper::apply([&]<class Feature>(Feature* feature) {
|
||||
dict[py::type::of<Feature>()] =
|
||||
py::cast(game.feature<Feature>(), py::return_value_policy::reference);
|
||||
});
|
||||
return dict;
|
||||
}
|
||||
|
||||
std::map<std::type_index, std::any>
|
||||
convert_feature_list(py::dict const& py_features)
|
||||
{
|
||||
std::map<std::type_index, std::any> features;
|
||||
GameFeaturesHelper::apply([&]<class Feature>(Feature* feature) {
|
||||
const auto py_type = py::type::of<Feature>();
|
||||
if (py_features.contains(py_type)) {
|
||||
features[std::type_index(typeid(Feature))] =
|
||||
py_features[py_type].cast<Feature*>();
|
||||
}
|
||||
});
|
||||
return features;
|
||||
}
|
||||
|
||||
} // namespace mo2::python
|
||||
|
||||
@@ -4,188 +4,103 @@
|
||||
|
||||
#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
|
||||
>;
|
||||
std::map<std::type_index, std::any> PyPluginGame::featureList() const
|
||||
{
|
||||
py::dict pyFeatures = [this]() {
|
||||
PYBIND11_OVERRIDE_PURE(py::dict, IPluginGame, featureList, );
|
||||
}();
|
||||
|
||||
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>>{});
|
||||
}
|
||||
};
|
||||
return convert_feature_list(pyFeatures);
|
||||
}
|
||||
|
||||
// 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)
|
||||
py::enum_<IPluginGame::LoadOrderMechanism>(m, "LoadOrderMechanism")
|
||||
.value("FileTime", IPluginGame::LoadOrderMechanism::FileTime)
|
||||
.value("PluginsTxt", IPluginGame::LoadOrderMechanism::PluginsTxt)
|
||||
|
||||
.value("FILE_TIME", MOBase::IPluginGame::LoadOrderMechanism::FileTime)
|
||||
.value("PLUGINS_TXT", MOBase::IPluginGame::LoadOrderMechanism::PluginsTxt);
|
||||
.value("FILE_TIME", IPluginGame::LoadOrderMechanism::FileTime)
|
||||
.value("PLUGINS_TXT", IPluginGame::LoadOrderMechanism::PluginsTxt);
|
||||
|
||||
py::enum_<MOBase::IPluginGame::SortMechanism>(m, "SortMechanism")
|
||||
.value("NONE", MOBase::IPluginGame::SortMechanism::NONE)
|
||||
.value("MLOX", MOBase::IPluginGame::SortMechanism::MLOX)
|
||||
.value("BOSS", MOBase::IPluginGame::SortMechanism::BOSS)
|
||||
.value("LOOT", MOBase::IPluginGame::SortMechanism::LOOT);
|
||||
py::enum_<IPluginGame::SortMechanism>(m, "SortMechanism")
|
||||
.value("NONE", IPluginGame::SortMechanism::NONE)
|
||||
.value("MLOX", IPluginGame::SortMechanism::MLOX)
|
||||
.value("BOSS", IPluginGame::SortMechanism::BOSS)
|
||||
.value("LOOT", IPluginGame::SortMechanism::LOOT);
|
||||
|
||||
// this does not actually do the conversion, but might be convenient
|
||||
// for accessing the names for enum bits
|
||||
py::enum_<MOBase::IPluginGame::ProfileSetting>(m, "ProfileSetting")
|
||||
.value("mods", MOBase::IPluginGame::MODS)
|
||||
.value("configuration", MOBase::IPluginGame::CONFIGURATION)
|
||||
.value("savegames", MOBase::IPluginGame::SAVEGAMES)
|
||||
.value("preferDefaults", MOBase::IPluginGame::PREFER_DEFAULTS)
|
||||
py::enum_<IPluginGame::ProfileSetting>(m, "ProfileSetting")
|
||||
.value("mods", IPluginGame::MODS)
|
||||
.value("configuration", IPluginGame::CONFIGURATION)
|
||||
.value("savegames", IPluginGame::SAVEGAMES)
|
||||
.value("preferDefaults", IPluginGame::PREFER_DEFAULTS)
|
||||
|
||||
.value("MODS", MOBase::IPluginGame::MODS)
|
||||
.value("CONFIGURATION", MOBase::IPluginGame::CONFIGURATION)
|
||||
.value("SAVEGAMES", MOBase::IPluginGame::SAVEGAMES)
|
||||
.value("PREFER_DEFAULTS", MOBase::IPluginGame::PREFER_DEFAULTS);
|
||||
.value("MODS", IPluginGame::MODS)
|
||||
.value("CONFIGURATION", IPluginGame::CONFIGURATION)
|
||||
.value("SAVEGAMES", IPluginGame::SAVEGAMES)
|
||||
.value("PREFER_DEFAULTS", IPluginGame::PREFER_DEFAULTS);
|
||||
|
||||
py::class_<IPluginGame, IPlugin, std::unique_ptr<IPluginGame, py::nodelete>>(
|
||||
m, "IPluginGame")
|
||||
py::class_<IPluginGame, PyPluginGame, IPlugin,
|
||||
std::unique_ptr<IPluginGame, py::nodelete>>(
|
||||
m, "IPluginGame", py::multiple_inheritance())
|
||||
.def(py::init<>())
|
||||
|
||||
.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", &extract_feature_list)
|
||||
.def("feature", &extract_feature, "feature_type"_a,
|
||||
py::return_value_policy::reference)
|
||||
|
||||
.def(
|
||||
"feature",
|
||||
[](MOBase::IPluginGame* p, py::object clsObj) {
|
||||
py::object py_feature = py::none();
|
||||
|
||||
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)
|
||||
|
||||
// .def("localizedName", &MOBase::IPlugin::localizedName,
|
||||
// &IPluginGameWrapper::localizedName_Default) .def("master",
|
||||
// &MOBase::IPlugin::master, &IPluginGameWrapper::master_Default)
|
||||
|
||||
// .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))
|
||||
//
|
||||
;
|
||||
.def("detectGame", &IPluginGame::detectGame)
|
||||
.def("gameName", &IPluginGame::gameName)
|
||||
.def("initializeProfile", &IPluginGame::initializeProfile, "directory"_a,
|
||||
"settings"_a)
|
||||
.def("listSaves", &IPluginGame::listSaves, "folder"_a)
|
||||
.def("isInstalled", &IPluginGame::isInstalled)
|
||||
.def("gameIcon", &IPluginGame::gameIcon)
|
||||
.def("gameDirectory", &IPluginGame::gameDirectory)
|
||||
.def("dataDirectory", &IPluginGame::dataDirectory)
|
||||
.def("setGamePath", &IPluginGame::setGamePath, "path"_a)
|
||||
.def("documentsDirectory", &IPluginGame::documentsDirectory)
|
||||
.def("savesDirectory", &IPluginGame::savesDirectory)
|
||||
.def("executables", &IPluginGame::executables)
|
||||
.def("executableForcedLoads", &IPluginGame::executableForcedLoads)
|
||||
.def("steamAPPId", &IPluginGame::steamAPPId)
|
||||
.def("primaryPlugins", &IPluginGame::primaryPlugins)
|
||||
.def("gameVariants", &IPluginGame::gameVariants)
|
||||
.def("setGameVariant", &IPluginGame::setGameVariant, "variant"_a)
|
||||
.def("binaryName", &IPluginGame::binaryName)
|
||||
.def("gameShortName", &IPluginGame::gameShortName)
|
||||
.def("primarySources", &IPluginGame::primarySources)
|
||||
.def("validShortNames", &IPluginGame::validShortNames)
|
||||
.def("gameNexusName", &IPluginGame::gameNexusName)
|
||||
.def("iniFiles", &IPluginGame::iniFiles)
|
||||
.def("DLCPlugins", &IPluginGame::DLCPlugins)
|
||||
.def("CCPlugins", &IPluginGame::CCPlugins)
|
||||
.def("loadOrderMechanism", &IPluginGame::loadOrderMechanism)
|
||||
.def("sortMechanism", &IPluginGame::sortMechanism)
|
||||
.def("nexusModOrganizerID", &IPluginGame::nexusModOrganizerID)
|
||||
.def("nexusGameID", &IPluginGame::nexusGameID)
|
||||
.def("looksValid", &IPluginGame::looksValid, "directory"_a)
|
||||
.def("gameVersion", &IPluginGame::gameVersion)
|
||||
.def("getLauncherName", &IPluginGame::getLauncherName);
|
||||
}
|
||||
|
||||
// multiple installers
|
||||
void add_iplugininstaller_bindings(pybind11::module_ m)
|
||||
{
|
||||
py::enum_<MOBase::IPluginInstaller::EInstallResult>(m, "InstallResult")
|
||||
.value("SUCCESS", MOBase::IPluginInstaller::RESULT_SUCCESS)
|
||||
.value("FAILED", MOBase::IPluginInstaller::RESULT_FAILED)
|
||||
.value("CANCELED", MOBase::IPluginInstaller::RESULT_CANCELED)
|
||||
.value("MANUAL_REQUESTED", MOBase::IPluginInstaller::RESULT_MANUALREQUESTED)
|
||||
.value("NOT_ATTEMPTED", MOBase::IPluginInstaller::RESULT_NOTATTEMPTED);
|
||||
py::enum_<IPluginInstaller::EInstallResult>(m, "InstallResult")
|
||||
.value("SUCCESS", IPluginInstaller::RESULT_SUCCESS)
|
||||
.value("FAILED", IPluginInstaller::RESULT_FAILED)
|
||||
.value("CANCELED", IPluginInstaller::RESULT_CANCELED)
|
||||
.value("MANUAL_REQUESTED", IPluginInstaller::RESULT_MANUALREQUESTED)
|
||||
.value("NOT_ATTEMPTED", IPluginInstaller::RESULT_NOTATTEMPTED);
|
||||
|
||||
// this is bind but should not be inherited in Python - does not make sense,
|
||||
// having it makes it simpler to bind the Simple and Custom installers
|
||||
@@ -240,16 +155,16 @@ namespace mo2::python {
|
||||
py::class_<IPlugin, PyPlugin, std::unique_ptr<IPlugin, py::nodelete>>(
|
||||
m, "IPluginBase", py::multiple_inheritance())
|
||||
.def(py::init<>())
|
||||
.def("init", &MOBase::IPlugin::init, "organizer"_a)
|
||||
.def("name", &MOBase::IPlugin::name)
|
||||
.def("localizedName", &MOBase::IPlugin::localizedName)
|
||||
.def("master", &MOBase::IPlugin::master)
|
||||
.def("author", &MOBase::IPlugin::author)
|
||||
.def("description", &MOBase::IPlugin::description)
|
||||
.def("version", &MOBase::IPlugin::version)
|
||||
.def("requirements", &MOBase::IPlugin::requirements)
|
||||
.def("settings", &MOBase::IPlugin::settings)
|
||||
.def("enabledByDefault", &MOBase::IPlugin::enabledByDefault);
|
||||
.def("init", &IPlugin::init, "organizer"_a)
|
||||
.def("name", &IPlugin::name)
|
||||
.def("localizedName", &IPlugin::localizedName)
|
||||
.def("master", &IPlugin::master)
|
||||
.def("author", &IPlugin::author)
|
||||
.def("description", &IPlugin::description)
|
||||
.def("version", &IPlugin::version)
|
||||
.def("requirements", &IPlugin::requirements)
|
||||
.def("settings", &IPlugin::settings)
|
||||
.def("enabledByDefault", &IPlugin::enabledByDefault);
|
||||
|
||||
py::class_<IPyPlugin, PyPlugin, IPlugin,
|
||||
std::unique_ptr<IPyPlugin, py::nodelete>>(m, "IPlugin",
|
||||
@@ -266,14 +181,11 @@ namespace mo2::python {
|
||||
std::unique_ptr<IPyPluginDiagnose, py::nodelete>>(
|
||||
m, "IPluginDiagnose", py::multiple_inheritance())
|
||||
.def(py::init<>())
|
||||
.def("activeProblems", &MOBase::IPluginDiagnose::activeProblems)
|
||||
.def("shortDescription", &MOBase::IPluginDiagnose::shortDescription,
|
||||
py::arg("key"))
|
||||
.def("fullDescription", &MOBase::IPluginDiagnose::fullDescription,
|
||||
py::arg("key"))
|
||||
.def("hasGuidedFix", &MOBase::IPluginDiagnose::hasGuidedFix, py::arg("key"))
|
||||
.def("startGuidedFix", &MOBase::IPluginDiagnose::startGuidedFix,
|
||||
py::arg("key"))
|
||||
.def("activeProblems", &IPluginDiagnose::activeProblems)
|
||||
.def("shortDescription", &IPluginDiagnose::shortDescription, "key"_a)
|
||||
.def("fullDescription", &IPluginDiagnose::fullDescription, "key"_a)
|
||||
.def("hasGuidedFix", &IPluginDiagnose::hasGuidedFix, "key"_a)
|
||||
.def("startGuidedFix", &IPluginDiagnose::startGuidedFix, "key"_a)
|
||||
.def("_invalidate", &PyPluginDiagnose::invalidate);
|
||||
|
||||
py::class_<IPluginTool, PyPluginTool, IPlugin,
|
||||
@@ -337,14 +249,15 @@ namespace mo2::python {
|
||||
helper.append_if_instance<IPluginPreview>(plugin_obj);
|
||||
helper.append_if_instance<IPluginTool>(plugin_obj);
|
||||
|
||||
// helper.append_if_instance<IPluginGame>(plugin_obj);
|
||||
helper.append_if_instance<IPluginGame>(plugin_obj);
|
||||
|
||||
// we need to check the two installer types because IPluginInstaller does not
|
||||
// inherit QObject, and the trampoline do not have a common ancestor
|
||||
helper.append_if_instance<IPluginInstallerSimple>(plugin_obj);
|
||||
helper.append_if_instance<IPluginInstallerCustom>(plugin_obj);
|
||||
|
||||
if (helper.objects.isEmpty()) {
|
||||
if (py::isinstance<IPyPlugin>(plugin_obj)) {
|
||||
helper.objects.append(plugin_obj.cast<IPyPlugin*>());
|
||||
}
|
||||
helper.append_if_instance<IPyPlugin>(plugin_obj);
|
||||
}
|
||||
|
||||
return helper.objects;
|
||||
|
||||
@@ -27,14 +27,9 @@ namespace mo2::python {
|
||||
|
||||
using namespace MOBase;
|
||||
|
||||
class IPyPlugin : public QObject, public IPlugin {};
|
||||
|
||||
class IPyPluginFileMapper : public IPyPlugin, public IPluginFileMapper {};
|
||||
|
||||
class IPyPluginDiagnose : public IPyPlugin, public IPluginDiagnose {};
|
||||
|
||||
// we need two base trampoline because IPluginGame has some final methods.
|
||||
template <class PluginBase>
|
||||
class PyPluginBase : public PluginBase {
|
||||
class PyPluginBaseNoFinal : public PluginBase {
|
||||
public:
|
||||
using PluginBase::PluginBase;
|
||||
|
||||
@@ -54,11 +49,6 @@ namespace mo2::python {
|
||||
{
|
||||
PYBIND11_OVERRIDE(QString, PluginBase, master, );
|
||||
}
|
||||
std::vector<std::shared_ptr<const IPluginRequirement>> requirements() const
|
||||
{
|
||||
PYBIND11_OVERRIDE(std::vector<std::shared_ptr<const IPluginRequirement>>,
|
||||
PluginBase, requirements, );
|
||||
}
|
||||
QString author() const override
|
||||
{
|
||||
PYBIND11_OVERRIDE_PURE(QString, PluginBase, author, );
|
||||
@@ -75,12 +65,32 @@ namespace mo2::python {
|
||||
{
|
||||
PYBIND11_OVERRIDE_PURE(QList<PluginSetting>, PluginBase, settings, );
|
||||
}
|
||||
};
|
||||
|
||||
template <class PluginBase>
|
||||
class PyPluginBase : public PyPluginBaseNoFinal<PluginBase> {
|
||||
public:
|
||||
using PyPluginBaseNoFinal<PluginBase>::PyPluginBaseNoFinal;
|
||||
|
||||
std::vector<std::shared_ptr<const IPluginRequirement>> requirements() const
|
||||
{
|
||||
PYBIND11_OVERRIDE(std::vector<std::shared_ptr<const IPluginRequirement>>,
|
||||
PluginBase, requirements, );
|
||||
}
|
||||
bool enabledByDefault() const override
|
||||
{
|
||||
PYBIND11_OVERRIDE(bool, PluginBase, enabledByDefault, );
|
||||
}
|
||||
};
|
||||
|
||||
// these classes do not inherit IPlugin or QObject so we need intermediate class to
|
||||
// get proper bindings
|
||||
class IPyPlugin : public QObject, public IPlugin {};
|
||||
class IPyPluginFileMapper : public IPyPlugin, public IPluginFileMapper {};
|
||||
class IPyPluginDiagnose : public IPyPlugin, public IPluginDiagnose {};
|
||||
|
||||
// PyXXX classes - trampoline classes for the plugins
|
||||
|
||||
class PyPlugin : public PyPluginBase<IPyPlugin> {
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(MOBase::IPlugin)
|
||||
@@ -331,6 +341,150 @@ namespace mo2::python {
|
||||
}
|
||||
};
|
||||
|
||||
// game
|
||||
class PyPluginGame : public PyPluginBaseNoFinal<IPluginGame> {
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(MOBase::IPlugin MOBase::IPluginGame)
|
||||
public:
|
||||
void detectGame() override
|
||||
{
|
||||
PYBIND11_OVERRIDE_PURE(void, IPluginGame, detectGame, );
|
||||
}
|
||||
QString gameName() const override
|
||||
{
|
||||
PYBIND11_OVERRIDE_PURE(QString, IPluginGame, gameName, );
|
||||
}
|
||||
void initializeProfile(const QDir& directory,
|
||||
ProfileSettings settings) const override
|
||||
{
|
||||
PYBIND11_OVERRIDE_PURE(void, IPluginGame, initializeProfile, directory,
|
||||
settings);
|
||||
}
|
||||
std::vector<std::shared_ptr<const ISaveGame>>
|
||||
listSaves(QDir folder) const override
|
||||
{
|
||||
PYBIND11_OVERRIDE_PURE(std::vector<std::shared_ptr<const ISaveGame>>,
|
||||
IPluginGame, listSaves, folder);
|
||||
}
|
||||
bool isInstalled() const override
|
||||
{
|
||||
PYBIND11_OVERRIDE_PURE(bool, IPluginGame, isInstalled, );
|
||||
}
|
||||
QIcon gameIcon() const override
|
||||
{
|
||||
PYBIND11_OVERRIDE_PURE(QIcon, IPluginGame, gameIcon, );
|
||||
}
|
||||
QDir gameDirectory() const override
|
||||
{
|
||||
PYBIND11_OVERRIDE_PURE(QDir, IPluginGame, gameDirectory, );
|
||||
}
|
||||
QDir dataDirectory() const override
|
||||
{
|
||||
PYBIND11_OVERRIDE_PURE(QDir, IPluginGame, dataDirectory, );
|
||||
}
|
||||
void setGamePath(const QString& path) override
|
||||
{
|
||||
PYBIND11_OVERRIDE_PURE(void, IPluginGame, setGamePath, path);
|
||||
}
|
||||
QDir documentsDirectory() const override
|
||||
{
|
||||
PYBIND11_OVERRIDE_PURE(QDir, IPluginGame, documentsDirectory, );
|
||||
}
|
||||
QDir savesDirectory() const override
|
||||
{
|
||||
PYBIND11_OVERRIDE_PURE(QDir, IPluginGame, savesDirectory, );
|
||||
}
|
||||
QList<ExecutableInfo> executables() const override
|
||||
{
|
||||
PYBIND11_OVERRIDE_PURE(QList<ExecutableInfo>, IPluginGame, executables, );
|
||||
}
|
||||
QList<ExecutableForcedLoadSetting> executableForcedLoads() const override
|
||||
{
|
||||
PYBIND11_OVERRIDE_PURE(QList<ExecutableForcedLoadSetting>, IPluginGame,
|
||||
executableForcedLoads, );
|
||||
}
|
||||
QString steamAPPId() const override
|
||||
{
|
||||
PYBIND11_OVERRIDE_PURE(QString, IPluginGame, steamAPPId, );
|
||||
}
|
||||
QStringList primaryPlugins() const override
|
||||
{
|
||||
PYBIND11_OVERRIDE_PURE(QStringList, IPluginGame, primaryPlugins, );
|
||||
}
|
||||
QStringList gameVariants() const override
|
||||
{
|
||||
PYBIND11_OVERRIDE_PURE(QStringList, IPluginGame, gameVariants, );
|
||||
}
|
||||
void setGameVariant(const QString& variant) override
|
||||
{
|
||||
PYBIND11_OVERRIDE_PURE(void, IPluginGame, setGameVariant, variant);
|
||||
}
|
||||
QString binaryName() const override
|
||||
{
|
||||
PYBIND11_OVERRIDE_PURE(QString, IPluginGame, binaryName, );
|
||||
}
|
||||
QString gameShortName() const override
|
||||
{
|
||||
PYBIND11_OVERRIDE_PURE(QString, IPluginGame, gameShortName, );
|
||||
}
|
||||
QStringList primarySources() const override
|
||||
{
|
||||
PYBIND11_OVERRIDE_PURE(QStringList, IPluginGame, primarySources, );
|
||||
}
|
||||
QStringList validShortNames() const override
|
||||
{
|
||||
PYBIND11_OVERRIDE_PURE(QStringList, IPluginGame, validShortNames, );
|
||||
}
|
||||
QString gameNexusName() const override
|
||||
{
|
||||
PYBIND11_OVERRIDE_PURE(QString, IPluginGame, gameNexuesName, );
|
||||
}
|
||||
QStringList iniFiles() const override
|
||||
{
|
||||
PYBIND11_OVERRIDE_PURE(QStringList, IPluginGame, iniFiles, );
|
||||
}
|
||||
QStringList DLCPlugins() const override
|
||||
{
|
||||
PYBIND11_OVERRIDE_PURE(QStringList, IPluginGame, DLCPlugins, );
|
||||
}
|
||||
QStringList CCPlugins() const override
|
||||
{
|
||||
PYBIND11_OVERRIDE_PURE(QStringList, IPluginGame, CCPlugins, );
|
||||
}
|
||||
LoadOrderMechanism loadOrderMechanism() const override
|
||||
{
|
||||
PYBIND11_OVERRIDE_PURE(LoadOrderMechanism, IPluginGame,
|
||||
loadOrderMechanism, );
|
||||
}
|
||||
SortMechanism sortMechanism() const override
|
||||
{
|
||||
PYBIND11_OVERRIDE_PURE(SortMechanism, IPluginGame, sortMechanism, );
|
||||
}
|
||||
int nexusModOrganizerID() const override
|
||||
{
|
||||
PYBIND11_OVERRIDE_PURE(int, IPluginGame, nexusModOrganizerID, );
|
||||
}
|
||||
int nexusGameID() const override
|
||||
{
|
||||
PYBIND11_OVERRIDE_PURE(int, IPluginGame, nexusGameID, );
|
||||
}
|
||||
bool looksValid(QDir const& dir) const override
|
||||
{
|
||||
PYBIND11_OVERRIDE_PURE(bool, IPluginGame, looksValid, dir);
|
||||
}
|
||||
QString gameVersion() const override
|
||||
{
|
||||
PYBIND11_OVERRIDE_PURE(QString, IPluginGame, gameVersion, );
|
||||
}
|
||||
QString getLauncherName() const override
|
||||
{
|
||||
PYBIND11_OVERRIDE_PURE(QString, IPluginGame, getLauncherName, );
|
||||
}
|
||||
|
||||
protected:
|
||||
std::map<std::type_index, std::any> featureList() const override;
|
||||
};
|
||||
|
||||
} // namespace mo2::python
|
||||
|
||||
#endif
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user