Add Game Features support

This commit is contained in:
AnyOldName3
2018-04-25 17:25:12 +01:00
parent 0a9b4b9fc4
commit 902024e508
8 changed files with 592 additions and 13 deletions
+1
View File
@@ -34,6 +34,7 @@ SET(project_path "${default_project_path}" CACHE PATH "path to the other mo proj
SET(lib_path "${project_path}/../../install/libs")
INCLUDE_DIRECTORIES(${project_path}/uibase/src
${project_path}/game_features/src
${PYTHON_ROOT}/Include
${SIP_ROOT}
${PYTHON_ROOT}/PC)
+391
View File
@@ -0,0 +1,391 @@
#include "gamefeatureswrappers.h"
#include <boost/any.hpp>
#include <typeindex>
#include <ipluginlist.h>
#include <iprofile.h>
#include <isavegame.h>
#include <isavegameinfowidget.h>
#include "gilock.h"
#include "pycatch.h"
/////////////////////////////
/// BSAInvalidation Wrapper
bool BSAInvalidationWrapper::isInvalidationBSA(const QString &bsaName)
{
GILock lock;
try {
return this->get_override("isInvalidationBSA")(bsaName);
} PYCATCH;
}
void BSAInvalidationWrapper::deactivate(MOBase::IProfile *profile)
{
GILock lock;
try {
this->get_override("deactivate")(boost::python::ptr(profile));
} PYCATCH;
}
void BSAInvalidationWrapper::activate(MOBase::IProfile *profile)
{
GILock lock;
try {
this->get_override("activate")(boost::python::ptr(profile));
} PYCATCH;
}
/// end BSAInvalidation Wrapper
/////////////////////////////
/// DataArchives Wrapper
QStringList DataArchivesWrapper::vanillaArchives() const
{
GILock lock;
try {
return this->get_override("vanillaArchives")();
} PYCATCH;
}
QStringList DataArchivesWrapper::archives(const MOBase::IProfile *profile) const
{
GILock lock;
try {
return this->get_override("archives")(boost::python::ptr(profile));
} PYCATCH;
}
void DataArchivesWrapper::addArchive(MOBase::IProfile *profile, int index, const QString &archiveName)
{
GILock lock;
try {
this->get_override("addArchive")(boost::python::ptr(profile), index, archiveName);
} PYCATCH;
}
void DataArchivesWrapper::removeArchive(MOBase::IProfile * profile, const QString & archiveName)
{
GILock lock;
try {
this->get_override("removeArchive")(boost::python::ptr(profile), archiveName);
} PYCATCH;
}
/// end DataArchives Wrapper
/////////////////////////////
/// GamePlugins Wrapper
void GamePluginsWrapper::writePluginLists(const MOBase::IPluginList * pluginList)
{
GILock lock;
try {
this->get_override("writePluginLists")(boost::python::ptr(pluginList));
} PYCATCH;
}
void GamePluginsWrapper::readPluginLists(MOBase::IPluginList * pluginList)
{
GILock lock;
try {
this->get_override("readPluginLists")(boost::python::ptr(pluginList));
} PYCATCH;
}
/// end GamePlugins Wrapper
/////////////////////////////
/// LocalSavegames Wrapper
MappingType LocalSavegamesWrapper::mappings(const QDir & profileSaveDir) const
{
GILock lock;
try {
return this->get_override("mappings")(profileSaveDir);
} PYCATCH;
}
void LocalSavegamesWrapper::prepareProfile(MOBase::IProfile * profile)
{
GILock lock;
try {
this->get_override("prepareProfile")(boost::python::ptr(profile));
} PYCATCH;
}
/// end LocalSavegames Wrapper
/////////////////////////////
/// SaveGameInfo Wrapper
MOBase::ISaveGame const * SaveGameInfoWrapper::getSaveGameInfo(QString const & file) const
{
GILock lock;
try {
return this->get_override("getSaveGameInfo")(file);
} PYCATCH;
}
SaveGameInfoWrapper::MissingAssets SaveGameInfoWrapper::getMissingAssets(QString const & file) const
{
GILock lock;
try {
return this->get_override("getMissingAssets")(file);
} PYCATCH;
}
MOBase::ISaveGameInfoWidget * SaveGameInfoWrapper::getSaveGameWidget(QWidget * parent) const
{
qCritical("Calling method with unimplemented from_python converter.");
GILock lock;
try {
return this->get_override("getSaveGameWidget")(boost::python::ptr(parent));
} PYCATCH;
}
bool SaveGameInfoWrapper::hasScriptExtenderSave(QString const & file) const
{
GILock lock;
try {
return this->get_override("hasScriptExtenderSave")(file);
} PYCATCH;
}
/// end SaveGameInfo Wrapper
/////////////////////////////
/// ScriptExtender Wrapper
QString ScriptExtenderWrapper::BinaryName() const
{
GILock lock;
try {
return this->get_override("BinaryName")();
} PYCATCH;
}
QString ScriptExtenderWrapper::PluginPath() const
{
GILock lock;
try {
return this->get_override("PluginPath")();
} PYCATCH;
}
QString ScriptExtenderWrapper::loaderName() const
{
GILock lock;
try {
return this->get_override("loaderName")();
} PYCATCH;
}
QString ScriptExtenderWrapper::loaderPath() const
{
GILock lock;
try {
return this->get_override("loaderPath")();
} PYCATCH;
}
QStringList ScriptExtenderWrapper::saveGameAttachmentExtensions() const
{
GILock lock;
try {
return this->get_override("saveGameAttachmentExtensions")();
} PYCATCH;
}
bool ScriptExtenderWrapper::isInstalled() const
{
GILock lock;
try {
return this->get_override("isInstalled")();
} PYCATCH;
}
QString ScriptExtenderWrapper::getExtenderVersion() const
{
GILock lock;
try {
return this->get_override("getExtenderVersion")();
} PYCATCH;
}
WORD ScriptExtenderWrapper::getArch() const
{
GILock lock;
try {
return this->get_override("getArch")();
} PYCATCH;
}
/// end ScriptExtender Wrapper
/////////////////////////////
/// UnmanagedMods Wrapper
QStringList UnmanagedModsWrapper::mods(bool onlyOfficial) const
{
GILock lock;
try {
return this->get_override("mods")(onlyOfficial);
} PYCATCH;
}
QString UnmanagedModsWrapper::displayName(const QString & modName) const
{
GILock lock;
try {
return this->get_override("displayName")(modName);
} PYCATCH;
}
QFileInfo UnmanagedModsWrapper::referenceFile(const QString & modName) const
{
GILock lock;
try {
return this->get_override("referenceFile")(modName);
} PYCATCH;
}
QStringList UnmanagedModsWrapper::secondaryFiles(const QString & modName) const
{
GILock lock;
try {
return this->get_override("secondaryFiles")(modName);
} PYCATCH;
}
/// end UnmanagedMods Wrapper
/////////////////////////////
template<typename T>
void insertGameFeature(std::map<std::type_index, boost::any> &map, const boost::python::object &pyObject)
{
map[std::type_index(typeid(T))] = boost::python::extract<T*>(pyObject)();
}
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, boost::any>>());
}
void * game_features_map_from_python::convertible(PyObject * objPtr)
{
return PyDict_Check(objPtr) ? objPtr : nullptr;
}
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, boost::any>>*)data)->storage.bytes;
std::map<std::type_index, boost::any> *result = new (storage) std::map<std::type_index, boost::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];
// pyKey should be a Boost.Python.class corresponding to a game feature.
std::string className = boost::python::extract<std::string>(pyKey.attr("__name__"))();
if (className == "BSAInvalidation")
insertGameFeature<BSAInvalidation>(*result, source[pyKey]);
else if (className == "DataArchives")
insertGameFeature<DataArchives>(*result, source[pyKey]);
else if (className == "GamePlugins")
insertGameFeature<GamePlugins>(*result, source[pyKey]);
else if (className == "LocalSavegames")
insertGameFeature<LocalSavegames>(*result, source[pyKey]);
else if (className == "SaveGameInfo")
insertGameFeature<SaveGameInfo>(*result, source[pyKey]);
else if (className == "ScriptExtender")
insertGameFeature<ScriptExtender>(*result, source[pyKey]);
else if (className == "UnmanagedMods")
insertGameFeature<UnmanagedMods>(*result, source[pyKey]);
}
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))
.def("deactivate", bpy::pure_virtual(&BSAInvalidation::deactivate))
.def("activate", bpy::pure_virtual(&BSAInvalidation::activate))
;
bpy::class_<DataArchivesWrapper, boost::noncopyable>("DataArchives")
.def("vanillaArchives", bpy::pure_virtual(&DataArchives::vanillaArchives))
.def("archives", bpy::pure_virtual(&DataArchives::archives))
.def("addArchive", bpy::pure_virtual(&DataArchives::addArchive))
.def("removeArchive", bpy::pure_virtual(&DataArchives::removeArchive))
;
bpy::class_<GamePluginsWrapper, boost::noncopyable>("GamePlugins")
.def("writePluginLists", bpy::pure_virtual(&GamePlugins::writePluginLists))
.def("readPluginLists", bpy::pure_virtual(&GamePlugins::readPluginLists))
;
bpy::class_<LocalSavegamesWrapper, boost::noncopyable>("LocalSavegames")
.def("mappings", bpy::pure_virtual(&LocalSavegames::mappings))
.def("prepareProfile", bpy::pure_virtual(&LocalSavegames::prepareProfile))
;
bpy::class_<SaveGameInfoWrapper, boost::noncopyable>("SaveGameInfo")
.def("getSaveGameInfo", bpy::pure_virtual(&SaveGameInfo::getSaveGameInfo), bpy::return_value_policy<bpy::manage_new_object>())
.def("getMissingAssets", bpy::pure_virtual(&SaveGameInfo::getMissingAssets))
.def("getSaveGameWidget", bpy::pure_virtual(&SaveGameInfo::getSaveGameWidget), bpy::return_value_policy<bpy::manage_new_object>())
.def("hasScriptExtenderSave", bpy::pure_virtual(&SaveGameInfo::hasScriptExtenderSave))
;
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("saveGameAttachmentExtensions", bpy::pure_virtual(&ScriptExtender::saveGameAttachmentExtensions))
.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))
.def("displayName", bpy::pure_virtual(&UnmanagedMods::displayName))
.def("referenceFile", bpy::pure_virtual(&UnmanagedMods::referenceFile))
.def("secondaryFiles", bpy::pure_virtual(&UnmanagedMods::secondaryFiles))
;
}
+85
View File
@@ -0,0 +1,85 @@
#ifndef GAMEFEATURESWRAPPERS_H
#define GAMEFEATURESWRAPPERS_H
#include <bsainvalidation.h>
#include <dataarchives.h>
#include <gameplugins.h>
#include <localsavegames.h>
#include <savegameinfo.h>
#include <scriptextender.h>
#include <unmanagedmods.h>
// this might need turning off if Q_MOC_RUN is defined
#include <boost/python.hpp>
/////////////////////////////
/// Wrapper declarations
class BSAInvalidationWrapper : public BSAInvalidation, public boost::python::wrapper<BSAInvalidation>
{
virtual bool isInvalidationBSA(const QString &bsaName) override;
virtual void deactivate(MOBase::IProfile *profile) override;
virtual void activate(MOBase::IProfile *profile) override;
};
class DataArchivesWrapper : public DataArchives, public boost::python::wrapper<DataArchives>
{
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>
{
virtual void writePluginLists(const MOBase::IPluginList *pluginList) override;
virtual void readPluginLists(MOBase::IPluginList *pluginList) override;
};
class LocalSavegamesWrapper : public LocalSavegames, public boost::python::wrapper<LocalSavegames>
{
virtual MappingType mappings(const QDir &profileSaveDir) const override;
virtual void prepareProfile(MOBase::IProfile *profile) override;
};
class SaveGameInfoWrapper : public SaveGameInfo, public boost::python::wrapper<SaveGameInfo>
{
virtual MOBase::ISaveGame const *getSaveGameInfo(QString const &file) const override;
virtual MissingAssets getMissingAssets(QString const &file) const override;
virtual MOBase::ISaveGameInfoWidget *getSaveGameWidget(QWidget *parent = 0) const override;
virtual bool hasScriptExtenderSave(QString const &file) const override;
};
class ScriptExtenderWrapper : public ScriptExtender, public boost::python::wrapper<ScriptExtender>
{
virtual QString BinaryName() const override;
virtual QString PluginPath() const override;
virtual QString loaderName() const override;
virtual QString loaderPath() const override;
virtual QStringList saveGameAttachmentExtensions() 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>
{
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
+34 -7
View File
@@ -1,9 +1,9 @@
#include "proxypluginwrappers.h"
#include <utility.h>
#include "error.h"
#include "gilock.h"
#include <QUrl>
#include <QWidget>
#include "pycatch.h"
#include "sipApiAccess.h"
namespace boost
@@ -23,9 +23,6 @@ namespace boost
using namespace MOBase;
#define PYCATCH catch (const boost::python::error_already_set &) { reportPythonError(); throw MyException("unhandled exception"); }\
catch (...) { throw MyException("An unknown exception was thrown in python code"); }
#define COMMON_I_PLUGIN_WRAPPER_DEFINITIONS(class_name) \
bool class_name::init(MOBase::IOrganizer *moInfo) \
@@ -153,6 +150,7 @@ MappingType IPluginFileMapperWrapper::mappings() const
QString IPluginGameWrapper::gameName() const
{
GILock lock;
try {
return this->get_override("gameName")();
} PYCATCH;
@@ -160,6 +158,7 @@ QString IPluginGameWrapper::gameName() const
void IPluginGameWrapper::initializeProfile(const QDir & directory, ProfileSettings settings) const
{
GILock lock;
try {
this->get_override("initializeProfile")(directory, settings);
} PYCATCH;
@@ -167,6 +166,7 @@ void IPluginGameWrapper::initializeProfile(const QDir & directory, ProfileSettin
QString IPluginGameWrapper::savegameExtension() const
{
GILock lock;
try {
return this->get_override("savegameExtension")();
} PYCATCH;
@@ -174,6 +174,7 @@ QString IPluginGameWrapper::savegameExtension() const
QString IPluginGameWrapper::savegameSEExtension() const
{
GILock lock;
try {
return this->get_override("savegameSEExtension")();
} PYCATCH;
@@ -181,6 +182,7 @@ QString IPluginGameWrapper::savegameSEExtension() const
bool IPluginGameWrapper::isInstalled() const
{
GILock lock;
try {
return this->get_override("isInstalled")();
} PYCATCH;
@@ -188,6 +190,7 @@ bool IPluginGameWrapper::isInstalled() const
QIcon IPluginGameWrapper::gameIcon() const
{
GILock lock;
try {
return this->get_override("gameIcon")();
} PYCATCH;
@@ -195,6 +198,7 @@ QIcon IPluginGameWrapper::gameIcon() const
QDir IPluginGameWrapper::gameDirectory() const
{
GILock lock;
try {
return this->get_override("gameDirectory")();
} PYCATCH;
@@ -202,6 +206,7 @@ QDir IPluginGameWrapper::gameDirectory() const
QDir IPluginGameWrapper::dataDirectory() const
{
GILock lock;
try {
return this->get_override("dataDirectory")();
} PYCATCH;
@@ -209,6 +214,7 @@ QDir IPluginGameWrapper::dataDirectory() const
void IPluginGameWrapper::setGamePath(const QString & path)
{
GILock lock;
try {
this->get_override("setGamePath")(path);
} PYCATCH;
@@ -216,6 +222,7 @@ void IPluginGameWrapper::setGamePath(const QString & path)
QDir IPluginGameWrapper::documentsDirectory() const
{
GILock lock;
try {
return this->get_override("documentsDirectory")();
} PYCATCH;
@@ -223,6 +230,7 @@ QDir IPluginGameWrapper::documentsDirectory() const
QDir IPluginGameWrapper::savesDirectory() const
{
GILock lock;
try {
return this->get_override("savesDirectory")();
} PYCATCH;
@@ -230,6 +238,7 @@ QDir IPluginGameWrapper::savesDirectory() const
QList<MOBase::ExecutableInfo> IPluginGameWrapper::executables() const
{
GILock lock;
try {
return this->get_override("executables")();
} PYCATCH;
@@ -237,6 +246,7 @@ QList<MOBase::ExecutableInfo> IPluginGameWrapper::executables() const
QString IPluginGameWrapper::steamAPPId() const
{
GILock lock;
try {
return this->get_override("steamAPPId")();
} PYCATCH;
@@ -244,6 +254,7 @@ QString IPluginGameWrapper::steamAPPId() const
QStringList IPluginGameWrapper::primaryPlugins() const
{
GILock lock;
try {
return this->get_override("primaryPlugins")();
} PYCATCH;
@@ -251,6 +262,7 @@ QStringList IPluginGameWrapper::primaryPlugins() const
QStringList IPluginGameWrapper::gameVariants() const
{
GILock lock;
try {
return this->get_override("gameVariants")();
} PYCATCH;
@@ -258,6 +270,7 @@ QStringList IPluginGameWrapper::gameVariants() const
void IPluginGameWrapper::setGameVariant(const QString & variant)
{
GILock lock;
try {
this->get_override("setGameVariant")(variant);
} PYCATCH;
@@ -265,6 +278,7 @@ void IPluginGameWrapper::setGameVariant(const QString & variant)
QString IPluginGameWrapper::binaryName() const
{
GILock lock;
try {
return this->get_override("binaryName")();
} PYCATCH;
@@ -272,6 +286,7 @@ QString IPluginGameWrapper::binaryName() const
QString IPluginGameWrapper::gameShortName() const
{
GILock lock;
try {
return this->get_override("gameShortName")();
} PYCATCH;
@@ -279,6 +294,7 @@ QString IPluginGameWrapper::gameShortName() const
QStringList IPluginGameWrapper::validShortNames() const
{
GILock lock;
try {
return this->get_override("validShortNames")();
} PYCATCH;
@@ -286,6 +302,7 @@ QStringList IPluginGameWrapper::validShortNames() const
QString IPluginGameWrapper::gameNexusName() const
{
GILock lock;
try {
return this->get_override("gameNexusName")();
} PYCATCH;
@@ -293,6 +310,7 @@ QString IPluginGameWrapper::gameNexusName() const
QStringList IPluginGameWrapper::iniFiles() const
{
GILock lock;
try {
return this->get_override("iniFiles")();
} PYCATCH;
@@ -300,6 +318,7 @@ QStringList IPluginGameWrapper::iniFiles() const
QStringList IPluginGameWrapper::DLCPlugins() const
{
GILock lock;
try {
return this->get_override("DLCPlugins")();
} PYCATCH;
@@ -307,6 +326,7 @@ QStringList IPluginGameWrapper::DLCPlugins() const
QStringList IPluginGameWrapper::CCPlugins() const
{
GILock lock;
try {
return this->get_override("CCPlugins")();
} PYCATCH;
@@ -314,13 +334,15 @@ QStringList IPluginGameWrapper::CCPlugins() const
IPluginGame::LoadOrderMechanism IPluginGameWrapper::loadOrderMechanism() const
{
GILock lock;
try {
return this->get_override("loadorderMechanism")();
return this->get_override("loadOrderMechanism")();
} PYCATCH;
}
IPluginGame::SortMechanism IPluginGameWrapper::sortMechanism() const
{
GILock lock;
try {
return this->get_override("sortMechanism")();
} PYCATCH;
@@ -328,6 +350,7 @@ IPluginGame::SortMechanism IPluginGameWrapper::sortMechanism() const
int IPluginGameWrapper::nexusModOrganizerID() const
{
GILock lock;
try {
return this->get_override("nexusModOrganizerID")();
} PYCATCH;
@@ -335,6 +358,7 @@ int IPluginGameWrapper::nexusModOrganizerID() const
int IPluginGameWrapper::nexusGameID() const
{
GILock lock;
try {
return this->get_override("nexusGameID")();
} PYCATCH;
@@ -342,6 +366,7 @@ int IPluginGameWrapper::nexusGameID() const
bool IPluginGameWrapper::looksValid(QDir const & dir) const
{
GILock lock;
try {
return this->get_override("looksValid")(dir);
} PYCATCH;
@@ -349,6 +374,7 @@ bool IPluginGameWrapper::looksValid(QDir const & dir) const
QString IPluginGameWrapper::gameVersion() const
{
GILock lock;
try {
return this->get_override("gameVersion")();
} PYCATCH;
@@ -356,6 +382,7 @@ QString IPluginGameWrapper::gameVersion() const
QString IPluginGameWrapper::getLauncherName() const
{
GILock lock;
try {
return this->get_override("getLauncherName")();
} PYCATCH;
@@ -365,7 +392,7 @@ COMMON_I_PLUGIN_WRAPPER_DEFINITIONS(IPluginGameWrapper)
std::map<std::type_index, boost::any> IPluginGameWrapper::featureList() const
{
qCritical("Calling unproxied method IPluginGameWrapper::featureList()");
GILock lock;
try {
return this->get_override("_featureList")();
} PYCATCH;
+1 -2
View File
@@ -108,11 +108,10 @@ public:
COMMON_I_PLUGIN_WRAPPER_DECLARATIONS
protected:
// TODO: implementing converters for this is required as otherwise Mod Organizer will crash on load when the game is being managed by this plugin
// Apparently, Python developers interpret an underscore in a function name as it being protected
virtual std::map<std::type_index, boost::any> featureList() const override;
// Thankfully, the default implementation of the templated 'T *feature()' function should allow us to get away without overriding it.
};
+11
View File
@@ -0,0 +1,11 @@
#ifndef PYCATCH_H
#define PYCATCH_H
#include <utility.h>
#include "error.h"
#define PYCATCH catch (const boost::python::error_already_set &) { reportPythonError(); throw MOBase::MyException("unhandled exception"); }\
catch (...) { throw MOBase::MyException("An unknown exception was thrown in python code"); }
#endif // PYCATCH_H
+52 -4
View File
@@ -9,6 +9,7 @@
#include <iplugintool.h>
#include "uibasewrappers.h"
#include "proxypluginwrappers.h"
#include "gamefeatureswrappers.h"
#include "sipApiAccess.h"
#include <Windows.h>
@@ -72,7 +73,11 @@ namespace bpy = boost::python;
struct QString_to_python_str
{
static PyObject *convert(const QString &str) {
return bpy::incref(bpy::object(str.toUtf8().constData()).ptr());
// It's safer to explicitly convert to unicode as if we don't, this can return either str or unicode without it being easy to know which to expect
bpy::object pyStr = bpy::object(str.toUtf8().constData());
if (PyString_Check(pyStr.ptr()))
pyStr = pyStr.attr("decode")("utf-8");
return bpy::incref(pyStr.ptr());
}
};
@@ -334,6 +339,26 @@ struct QList_from_python_obj
};
template <typename T>
struct std_vector_to_python_list
{
static PyObject *convert(const std::vector<T> &vector)
{
bpy::list pyList;
try {
for (const T &item : vector)
pyList.append(item);
}
catch (const bpy::error_already_set&) {
reportPythonError();
}
return bpy::incref(pyList.ptr());
}
};
template <typename T>
struct std_vector_from_python_obj
{
@@ -825,6 +850,16 @@ BOOST_PYTHON_MODULE(mobase)
.def("isCustom", &ExecutableInfo::isCustom)
;
bpy::class_<ISaveGameWrapper, boost::noncopyable>("ISaveGame")
.def("getFilename", bpy::pure_virtual(&ISaveGame::getFilename))
.def("getCreationTime", bpy::pure_virtual(&ISaveGame::getCreationTime))
.def("getSaveGroupIdentifier", bpy::pure_virtual(&ISaveGame::getSaveGroupIdentifier))
.def("allFiles", bpy::pure_virtual(&ISaveGame::allFiles))
.def("hasScriptExtenderFile", bpy::pure_virtual(&ISaveGame::hasScriptExtenderFile))
;
// TODO: ISaveGameInfoWidget bindings
Functor1_converter<bool, const IOrganizer::FileInfo&>();
Functor1_converter<void, const QString&>();
Functor1_converter<bool, const QString&>();
@@ -1013,8 +1048,6 @@ BOOST_PYTHON_MODULE(mobase)
.def_readwrite("createTarget", &Mapping::createTarget)
;
std_vector_from_python_obj<Mapping>();
bpy::class_<IPluginFileMapperWrapper, boost::noncopyable>("IPluginFileMapper")
.def("mappings", bpy::pure_virtual(&MOBase::IPluginFileMapper::mappings))
;
@@ -1083,6 +1116,14 @@ BOOST_PYTHON_MODULE(mobase)
.def("isActive", bpy::pure_virtual(&MOBase::IPluginGame::isActive))
.def("settings", bpy::pure_virtual(&MOBase::IPluginGame::settings))
// The syntax has to differ slightly from C++ because these are templated
.def("featureBSAInvalidation", &MOBase::IPluginGame::feature<BSAInvalidation>, bpy::return_value_policy<bpy::reference_existing_object>())
.def("featureDataArchives", &MOBase::IPluginGame::feature<DataArchives>, bpy::return_value_policy<bpy::reference_existing_object>())
.def("featureGamePlugins", &MOBase::IPluginGame::feature<GamePlugins>, bpy::return_value_policy<bpy::reference_existing_object>())
.def("featureLocalSavegames", &MOBase::IPluginGame::feature<LocalSavegames>, bpy::return_value_policy<bpy::reference_existing_object>())
.def("featureSaveGameInfo", &MOBase::IPluginGame::feature<SaveGameInfo>, bpy::return_value_policy<bpy::reference_existing_object>())
.def("featureScriptExtender", &MOBase::IPluginGame::feature<ScriptExtender>, bpy::return_value_policy<bpy::reference_existing_object>())
.def("featureUnmanagedMods", &MOBase::IPluginGame::feature<UnmanagedMods>, bpy::return_value_policy<bpy::reference_existing_object>())
;
bpy::enum_<MOBase::IPluginInstaller::EInstallResult>("InstallResult")
@@ -1120,13 +1161,20 @@ BOOST_PYTHON_MODULE(mobase)
bpy::to_python_converter<QList<QFileInfo>,
QList_to_python_list<QFileInfo>>();
QList_from_python_obj<QVariant>();
QList_to_python_list<QVariant>();
bpy::to_python_converter<QList<QVariant>,
QList_to_python_list<QVariant>>();
QMap_converters<QString, QVariant>();
QMap_converters<QString, QStringList>();
std_vector_from_python_obj<unsigned int>();
std_vector_from_python_obj<Mapping>();
bpy::to_python_converter<std::vector<Mapping>,
std_vector_to_python_list<Mapping>>();
stdset_from_python_list<QString>();
registerGameFeaturesPythonConverters();
}
+17
View File
@@ -21,8 +21,12 @@
#include <idownloadmanager.h>
#include <ipluginlist.h>
#include <imodlist.h>
#include <isavegame.h>
#include <isavegameinfowidget.h>
#include "error.h"
#include "gilock.h"
#include "pycatch.h"
extern MOBase::IOrganizer *s_Organizer;
@@ -434,4 +438,17 @@ struct IModListWrapper: MOBase::IModList, boost::python::wrapper<MOBase::IModLis
};
// This needs to be extendable in Python, so actually needs a wrapper
// Everything else probably doesn't
class ISaveGameWrapper : public MOBase::ISaveGame, public boost::python::wrapper<MOBase::ISaveGame>
{
public:
virtual QString getFilename() const override { try { return this->get_override("getFilename")(); } PYCATCH };
virtual QDateTime getCreationTime() const override { try { return this->get_override("getCreationTime")(); } PYCATCH };
virtual QString getSaveGroupIdentifier() const override { try { return this->get_override("getSaveGroupIdentifier")(); } PYCATCH };
virtual QStringList allFiles() const override { try { return this->get_override("allFiles")(); } PYCATCH };
virtual bool hasScriptExtenderFile() const override { try { return this->get_override("hasScriptExtenderFile")(); } PYCATCH };
};
#endif // UIBASEWRAPPERS_H