2018-07-24 01:51:04 -05:00
#include "pythonrunner.h"
#pragma warning( disable : 4100 )
#pragma warning( disable : 4996 )
2020-05-11 23:40:06 +02:00
#include <idownloadmanager.h>
2020-05-01 21:32:08 +02:00
#include <ifiletree.h>
2020-05-11 23:40:06 +02:00
#include <iinstallationmanager.h>
#include <imodinterface.h>
#include <imodlist.h>
#include <imodrepositorybridge.h>
2018-07-24 01:51:04 -05:00
#include <iplugin.h>
#include <iplugingame.h>
#include <iplugininstaller.h>
#include <iplugintool.h>
2020-05-11 23:40:06 +02:00
#include <iprofile.h>
2020-05-20 20:52:31 +02:00
#include <log.h>
2020-05-11 23:40:06 +02:00
2018-07-24 01:51:04 -05:00
#include "uibasewrappers.h"
#include "proxypluginwrappers.h"
#include "gamefeatureswrappers.h"
#include "sipApiAccess.h"
#include <Windows.h>
#include <utility.h>
#include <QDir>
#include <QFile>
#include <QCoreApplication>
#include <QWidget>
2020-05-04 01:47:30 +02:00
#include <variant>
#include <tuple>
2018-07-24 01:51:04 -05:00
#ifndef Q_MOC_RUN
#include <boost/python.hpp>
2020-05-02 00:24:45 +02:00
#include <boost/mp11.hpp>
2020-05-11 23:00:29 +02:00
#endif
2020-05-03 13:38:47 +02:00
2020-05-02 00:24:45 +02:00
#include "tuple_helper.h"
2020-05-03 13:38:47 +02:00
#include "variant_helper.h"
2020-05-11 23:00:29 +02:00
#include "converters.h"
2020-11-19 20:40:05 +01:00
#include "shared_ptr_converter.h"
2020-11-09 18:23:57 +01:00
#include "pylogger.h"
2018-07-24 01:51:04 -05:00
2020-05-05 17:52:54 +02:00
using namespace MOBase ;
namespace bpy = boost :: python ;
namespace mp11 = boost :: mp11 ;
2020-05-11 23:02:08 +02:00
/**
* This macro should be used within a bpy::class_ declaration and will define two
* methods: __getattr__ and Name, where Name will simply return the object as a QClass*
* object, while __getattr__ will delegate to the underlying QClass object when required.
*
* This allow access to Qt interface for object exposed using boost::python (e.g., signals,
* methods from QObject or QWidget, etc.).
*/
2020-05-11 23:00:29 +02:00
#define Q_DELEGATE(Class, QClass, Name) \
.def(Name, +[](Class* w) -> QClass* { return w; }, bpy::return_value_policy<bpy::reference_existing_object>()) \
.def("__getattr__", +[](Class* w, bpy::str str) -> bpy::object { \
return bpy::object{ (QClass*)w }.attr(str); \
})
2020-05-01 21:32:08 +02:00
2018-07-24 01:51:04 -05:00
BOOST_PYTHON_MODULE ( mobase )
{
PyEval_InitThreads ();
2020-05-01 21:32:30 +02:00
bpy :: import ( "PyQt5.QtCore" );
2020-05-11 23:00:29 +02:00
bpy :: import ( "PyQt5.QtWidgets" );
2020-05-01 21:32:30 +02:00
2020-05-11 23:00:29 +02:00
utils :: register_qstring_converter ();
utils :: register_qvariant_converter ();
2018-07-24 01:51:04 -05:00
2020-05-11 23:00:29 +02:00
utils :: register_qclass_converter < QObject > ();
utils :: register_qclass_converter < QDateTime > ();
utils :: register_qclass_converter < QDir > ();
utils :: register_qclass_converter < QFileInfo > ();
utils :: register_qclass_converter < QWidget > ();
2020-06-15 22:48:21 +02:00
utils :: register_qclass_converter < QMainWindow > ();
2020-05-11 23:00:29 +02:00
utils :: register_qclass_converter < QIcon > ();
utils :: register_qclass_converter < QSize > ();
utils :: register_qclass_converter < QUrl > ();
2018-07-24 01:51:04 -05:00
2020-05-11 23:00:29 +02:00
// QFlags:
utils :: register_qflags_converter < IPluginList :: PluginStates > ();
utils :: register_qflags_converter < IPluginGame :: ProfileSettings > ();
2020-05-21 17:47:08 +02:00
utils :: register_qflags_converter < IModList :: ModStates > ();
2018-07-24 01:51:04 -05:00
2020-05-03 20:57:50 +02:00
// Pointers:
bpy :: register_ptr_to_python < std :: shared_ptr < FileTreeEntry >> ();
bpy :: register_ptr_to_python < std :: shared_ptr < const FileTreeEntry >> ();
2020-10-25 12:57:53 +01:00
bpy :: implicitly_convertible < std :: shared_ptr < FileTreeEntry > , std :: shared_ptr < const FileTreeEntry >> ();
2020-05-03 20:57:50 +02:00
bpy :: register_ptr_to_python < std :: shared_ptr < IFileTree >> ();
bpy :: register_ptr_to_python < std :: shared_ptr < const IFileTree >> ();
2020-10-25 12:57:53 +01:00
bpy :: implicitly_convertible < std :: shared_ptr < IFileTree > , std :: shared_ptr < const IFileTree >> ();
2020-11-19 21:21:58 +01:00
utils :: shared_ptr_from_python < std :: shared_ptr < const ISaveGame >> ();
2020-11-18 19:23:00 +01:00
bpy :: register_ptr_to_python < std :: shared_ptr < const ISaveGame >> ();
2020-11-19 21:21:58 +01:00
utils :: shared_ptr_from_python < std :: shared_ptr < const IPluginRequirement >> ();
bpy :: register_ptr_to_python < std :: shared_ptr < const IPluginRequirement >> ();
2020-05-03 20:57:50 +02:00
// Containers:
2020-05-25 21:24:50 +02:00
utils :: register_sequence_container < std :: vector < int >> ();
2020-11-11 11:23:15 +01:00
utils :: register_sequence_container < std :: vector < unsigned int >> ();
2020-05-03 20:57:50 +02:00
utils :: register_sequence_container < QList < ExecutableInfo >> ();
2020-07-20 19:44:51 +02:00
utils :: register_sequence_container < QList < ExecutableForcedLoadSetting >> ();
2020-05-03 20:57:50 +02:00
utils :: register_sequence_container < QList < PluginSetting >> ();
utils :: register_sequence_container < QList < ModRepositoryFileInfo >> ();
2020-06-07 17:56:58 +02:00
utils :: register_sequence_container < QStringList > ();
2020-05-03 20:57:50 +02:00
utils :: register_sequence_container < QList < QString >> ();
utils :: register_sequence_container < QList < QFileInfo >> ();
2020-05-13 14:33:15 +02:00
utils :: register_sequence_container < QList < QVariant >> (); // Required for QVariant since this is QVariantList.
2020-11-18 19:23:00 +01:00
utils :: register_sequence_container < std :: vector < std :: shared_ptr < const FileTreeEntry >>> ();
utils :: register_sequence_container < std :: vector < std :: shared_ptr < const ISaveGame >>> ();
2020-11-19 21:21:58 +01:00
utils :: register_sequence_container < std :: vector < std :: shared_ptr < const IPluginRequirement >>> ();
2020-05-25 21:24:50 +02:00
utils :: register_sequence_container < std :: vector < ModDataContent :: Content >> ();
2020-05-03 20:57:50 +02:00
utils :: register_sequence_container < std :: vector < Mapping >> ();
utils :: register_set_container < std :: set < QString >> ();
2020-11-06 09:06:55 -05:00
2020-05-13 14:33:15 +02:00
utils :: register_associative_container < QMap < QString , QVariant >> (); // Required for QVariant since this is QVariantMap.
2020-05-03 20:57:50 +02:00
utils :: register_associative_container < QMap < QString , QStringList >> ();
2020-08-29 19:55:06 +02:00
utils :: register_associative_container < std :: map < QString , IModList :: ModStates >> ();
2020-09-20 21:30:01 +02:00
utils :: register_associative_container < std :: map < QString , QVariant >> ();
2020-08-29 19:55:06 +02:00
2020-05-03 20:57:50 +02:00
utils :: register_associative_container < IFileTree :: OverwritesType > ();
2020-11-11 17:25:55 +01:00
utils :: register_optional < std :: optional < IPluginRequirement :: Problem >> ();
2020-05-03 20:57:50 +02:00
// Tuple:
2020-05-09 21:13:45 +02:00
bpy :: register_tuple < std :: tuple < bool , DWORD >> (); // IOrganizer::waitForApplication
2020-06-08 21:45:01 +02:00
bpy :: register_tuple < std :: tuple < bool , bool >> (); // IProfile::invalidationActive
2020-05-04 20:09:24 +02:00
bpy :: register_tuple < std :: tuple < IPluginInstaller :: EInstallResult , std :: shared_ptr < IFileTree > , QString , int >> ();
2020-05-03 20:57:50 +02:00
// Variants:
2020-05-04 20:09:24 +02:00
bpy :: register_variant < std :: variant <
2020-11-06 09:06:55 -05:00
IPluginInstaller :: EInstallResult ,
std :: shared_ptr < IFileTree > ,
2020-05-04 20:09:24 +02:00
std :: tuple < IPluginInstaller :: EInstallResult , std :: shared_ptr < IFileTree > , QString , int >>> ();
2020-05-14 23:18:23 +02:00
bpy :: register_variant < std :: variant < IFileTree :: OverwritesType , std :: size_t >> ();
2020-05-04 01:47:30 +02:00
bpy :: register_variant < std :: variant < QString , bool >> ();
2020-05-03 20:57:50 +02:00
// Functions:
2020-05-11 23:00:29 +02:00
utils :: register_functor_converter < void () > (); // converter for the onRefreshed-callback
utils :: register_functor_converter < void ( const QString & ) > ();
2020-10-14 18:48:14 +02:00
utils :: register_functor_converter < void ( int ) > ();
2020-05-11 23:00:29 +02:00
utils :: register_functor_converter < void ( const QString & , unsigned int ) > ();
2020-08-27 18:30:22 +02:00
utils :: register_functor_converter < void ( const QString & , int , int ) > (); // converter for the onModMoved-callback and onPluginMoved callbacks
2020-08-29 19:55:06 +02:00
utils :: register_functor_converter < void ( const std :: map < QString , IModList :: ModStates >& ) > (); // converter for the onModStateChanged-callback (IModList)
2020-09-05 13:49:11 +02:00
utils :: register_functor_converter < void ( const std :: map < QString , IPluginList :: PluginStates >& ) > (); // converter for the onPluginStateChanged-callback (IPluginList)
2020-08-27 18:30:22 +02:00
utils :: register_functor_converter < void ( const QString & , const QString & , const QVariant & , const QVariant & ) > ();
utils :: register_functor_converter < void ( QMainWindow * ) > ();
2020-10-24 20:52:52 +02:00
utils :: register_functor_converter < void ( IProfile * ), bpy :: pointer_wrapper < IProfile *>> ();
utils :: register_functor_converter < void ( IProfile * , const QString & , const QString & ), bpy :: pointer_wrapper < IProfile *>> ();
2020-06-15 22:48:21 +02:00
utils :: register_functor_converter < void ( IProfile * , IProfile * ), bpy :: pointer_wrapper < IProfile *>> ();
2020-05-11 23:00:29 +02:00
utils :: register_functor_converter < bool ( const QString & ) > ();
2020-11-04 21:48:22 +01:00
utils :: register_functor_converter < IFileTree :: WalkReturn ( const QString & , std :: shared_ptr < const FileTreeEntry > ) > ();
2020-08-27 18:30:22 +02:00
utils :: register_functor_converter < bool ( const IOrganizer :: FileInfo & ) > ();
2020-05-11 23:00:29 +02:00
utils :: register_functor_converter < bool ( std :: shared_ptr < FileTreeEntry > const & ) > ();
utils :: register_functor_converter < std :: variant < QString , bool > ( QString const & ) > ();
2020-10-25 16:52:20 +01:00
utils :: register_functor_converter < void ( IModInterface * ), bpy :: pointer_wrapper < IModInterface *>> ();
2020-11-11 11:23:15 +01:00
utils :: register_functor_converter < bool ( IOrganizer * ), bpy :: pointer_wrapper < IOrganizer *>> ();
2020-11-12 21:49:37 +01:00
utils :: register_functor_converter < void ( const IPlugin * ), bpy :: pointer_wrapper < const IPlugin *>> ();
2020-05-03 20:57:50 +02:00
2020-08-29 19:55:06 +02:00
// This one is kept for backward-compatibility while we deprecate onModStateChanged for singl mod.
utils :: register_functor_converter < void ( const QString & , IModList :: ModStates ) > (); // converter for the onModStateChanged-callback (IModList).
2020-09-05 13:49:11 +02:00
utils :: register_functor_converter < void ( const QString & , IPluginList :: PluginStates ) > (); // converter for the onPluginStateChanged-callback (IPluginList).
2020-08-29 19:55:06 +02:00
2020-05-11 23:00:29 +02:00
//
// Class declarations:
//
2018-07-24 01:51:04 -05:00
bpy :: enum_ < MOBase :: VersionInfo :: ReleaseType > ( "ReleaseType" )
. value ( "final" , MOBase :: VersionInfo :: RELEASE_FINAL )
. value ( "candidate" , MOBase :: VersionInfo :: RELEASE_CANDIDATE )
. value ( "beta" , MOBase :: VersionInfo :: RELEASE_BETA )
. value ( "alpha" , MOBase :: VersionInfo :: RELEASE_ALPHA )
. value ( "prealpha" , MOBase :: VersionInfo :: RELEASE_PREALPHA )
2020-05-13 15:55:05 +02:00
. value ( "FINAL" , MOBase :: VersionInfo :: RELEASE_FINAL )
. value ( "CANDIDATE" , MOBase :: VersionInfo :: RELEASE_CANDIDATE )
. value ( "BETA" , MOBase :: VersionInfo :: RELEASE_BETA )
. value ( "ALPHA" , MOBase :: VersionInfo :: RELEASE_ALPHA )
. value ( "PRE_ALPHA" , MOBase :: VersionInfo :: RELEASE_PREALPHA )
2018-07-24 01:51:04 -05:00
;
bpy :: enum_ < MOBase :: VersionInfo :: VersionScheme > ( "VersionScheme" )
. value ( "discover" , MOBase :: VersionInfo :: SCHEME_DISCOVER )
. value ( "regular" , MOBase :: VersionInfo :: SCHEME_REGULAR )
. value ( "decimalmark" , MOBase :: VersionInfo :: SCHEME_DECIMALMARK )
. value ( "numbersandletters" , MOBase :: VersionInfo :: SCHEME_NUMBERSANDLETTERS )
. value ( "date" , MOBase :: VersionInfo :: SCHEME_DATE )
. value ( "literal" , MOBase :: VersionInfo :: SCHEME_LITERAL )
2020-05-13 15:55:05 +02:00
. value ( "DISCOVER" , MOBase :: VersionInfo :: SCHEME_DISCOVER )
. value ( "REGULAR" , MOBase :: VersionInfo :: SCHEME_REGULAR )
. value ( "DECIMAL_MARK" , MOBase :: VersionInfo :: SCHEME_DECIMALMARK )
. value ( "NUMBERS_AND_LETTERS" , MOBase :: VersionInfo :: SCHEME_NUMBERSANDLETTERS )
. value ( "DATE" , MOBase :: VersionInfo :: SCHEME_DATE )
. value ( "LITERAL" , MOBase :: VersionInfo :: SCHEME_LITERAL )
2018-07-24 01:51:04 -05:00
;
bpy :: class_ < VersionInfo > ( "VersionInfo" )
2020-07-14 13:14:53 +02:00
. def ( bpy :: init < QString , VersionInfo :: VersionScheme > (
( bpy :: arg ( "value" ), bpy :: arg ( "scheme" ) = VersionInfo :: SCHEME_DISCOVER )))
2020-07-14 13:21:30 +02:00
// Note: Order of the two init<> below is important because ReleaseType is a simple enum with an
// implicit int conversion.
2020-07-14 13:14:53 +02:00
. def ( bpy :: init < int , int , int , int , VersionInfo :: ReleaseType > (
( bpy :: arg ( "major" ), "minor" , "subminor" , "subsubminor" , bpy :: arg ( "release_type" ) = VersionInfo :: RELEASE_FINAL )))
2020-07-14 13:21:30 +02:00
. def ( bpy :: init < int , int , int , VersionInfo :: ReleaseType > (
( bpy :: arg ( "major" ), "minor" , "subminor" , bpy :: arg ( "release_type" ) = VersionInfo :: RELEASE_FINAL )))
2018-07-24 01:51:04 -05:00
. def ( "clear" , & VersionInfo :: clear )
2020-07-14 13:14:53 +02:00
. def ( "parse" , & VersionInfo :: parse ,
( bpy :: arg ( "value" ), bpy :: arg ( "scheme" ) = VersionInfo :: SCHEME_DISCOVER , bpy :: arg ( "is_manual" ) = false ))
2018-07-24 01:51:04 -05:00
. def ( "canonicalString" , & VersionInfo :: canonicalString )
2020-07-14 14:36:11 +02:00
. def ( "displayString" , & VersionInfo :: displayString , bpy :: arg ( "forced_segments" ) = 2 )
2018-07-24 01:51:04 -05:00
. def ( "isValid" , & VersionInfo :: isValid )
. def ( "scheme" , & VersionInfo :: scheme )
2020-05-09 18:19:31 +02:00
. def ( "__str__" , & VersionInfo :: canonicalString )
2018-07-24 01:51:04 -05:00
. def ( bpy :: self < bpy :: self )
. def ( bpy :: self > bpy :: self )
. def ( bpy :: self <= bpy :: self )
. def ( bpy :: self >= bpy :: self )
. def ( bpy :: self != bpy :: self )
. def ( bpy :: self == bpy :: self )
;
2020-07-14 13:14:53 +02:00
bpy :: class_ < PluginSetting > (
"PluginSetting" , bpy :: init < const QString & , const QString & , const QVariant &> (
( bpy :: arg ( "key" ), "description" , "default_value" )))
. def_readwrite ( "key" , & PluginSetting :: key )
. def_readwrite ( "description" , & PluginSetting :: description )
. def_readwrite ( "default_value" , & PluginSetting :: defaultValue );
2018-07-24 01:51:04 -05:00
2020-11-06 09:06:55 -05:00
bpy :: class_ < ExecutableInfo > ( "ExecutableInfo" ,
2020-07-14 13:14:53 +02:00
bpy :: init < const QString & , const QFileInfo &> (( bpy :: arg ( "title" ), "binary" )))
. def ( "withArgument" , & ExecutableInfo :: withArgument , bpy :: return_self <> (), bpy :: arg ( "argument" ))
. def ( "withWorkingDirectory" , & ExecutableInfo :: withWorkingDirectory , bpy :: return_self <> (), bpy :: arg ( "directory" ))
. def ( "withSteamAppId" , & ExecutableInfo :: withSteamAppId , bpy :: return_self <> (), bpy :: arg ( "app_id" ))
2020-06-14 10:52:45 +02:00
. def ( "asCustom" , & ExecutableInfo :: asCustom , bpy :: return_self <> ())
2018-07-24 01:51:04 -05:00
. def ( "isValid" , & ExecutableInfo :: isValid )
. def ( "title" , & ExecutableInfo :: title )
. def ( "binary" , & ExecutableInfo :: binary )
. def ( "arguments" , & ExecutableInfo :: arguments )
. def ( "workingDirectory" , & ExecutableInfo :: workingDirectory )
. def ( "steamAppID" , & ExecutableInfo :: steamAppID )
. def ( "isCustom" , & ExecutableInfo :: isCustom )
;
2020-11-06 09:06:55 -05:00
bpy :: class_ < ExecutableForcedLoadSetting > ( "ExecutableForcedLoadSetting" ,
2020-07-14 13:14:53 +02:00
bpy :: init < const QString & , const QString &> (( bpy :: arg ( "process" ), "library" )))
. def ( "withForced" , & ExecutableForcedLoadSetting :: withForced , bpy :: return_self <> (), bpy :: arg ( "forced" ))
. def ( "withEnabled" , & ExecutableForcedLoadSetting :: withEnabled , bpy :: return_self <> (), bpy :: arg ( "enabled" ))
2020-06-14 10:52:45 +02:00
. def ( "enabled" , & ExecutableForcedLoadSetting :: enabled )
. def ( "forced" , & ExecutableForcedLoadSetting :: forced )
. def ( "library" , & ExecutableForcedLoadSetting :: library )
. def ( "process" , & ExecutableForcedLoadSetting :: process )
;
2020-11-19 20:40:05 +01:00
bpy :: class_ < ISaveGameWrapper , bpy :: bases <> , boost :: noncopyable > ( "ISaveGame" )
2020-11-18 19:23:00 +01:00
. def ( "getFilepath" , bpy :: pure_virtual ( & ISaveGame :: getFilepath ))
2018-07-24 01:51:04 -05:00
. def ( "getCreationTime" , bpy :: pure_virtual ( & ISaveGame :: getCreationTime ))
2020-11-18 19:23:00 +01:00
. def ( "getName" , bpy :: pure_virtual ( & ISaveGame :: getName ))
2018-07-24 01:51:04 -05:00
. def ( "getSaveGroupIdentifier" , bpy :: pure_virtual ( & ISaveGame :: getSaveGroupIdentifier ))
. def ( "allFiles" , bpy :: pure_virtual ( & ISaveGame :: allFiles ))
;
2020-05-11 23:18:44 +02:00
// See Q_DELEGATE for more details.
2020-07-14 13:14:53 +02:00
bpy :: class_ < ISaveGameInfoWidgetWrapper , bpy :: bases <> , ISaveGameInfoWidgetWrapper * , boost :: noncopyable > (
"ISaveGameInfoWidget" , bpy :: init < bpy :: optional < QWidget *>> ( bpy :: arg ( "parent" )))
. def ( "setSave" , bpy :: pure_virtual ( & ISaveGameInfoWidget :: setSave ), bpy :: arg ( "save" ))
2020-05-11 23:00:29 +02:00
Q_DELEGATE ( ISaveGameInfoWidget , QWidget , "_widget" )
2020-05-10 16:01:14 +02:00
;
2018-07-24 01:51:04 -05:00
2020-11-11 11:23:15 +01:00
// Plugin requirements:
2020-11-11 16:14:28 +01:00
auto iPluginRequirementClass = bpy :: class_ <
2020-11-19 21:21:58 +01:00
IPluginRequirementWrapper , bpy :: bases <> , boost :: noncopyable > ( "IPluginRequirement" );
2020-11-11 16:14:28 +01:00
{
bpy :: scope scope = iPluginRequirementClass ;
bpy :: class_ < IPluginRequirement :: Problem > ( "Problem" ,
bpy :: init < QString , QString > (( bpy :: arg ( "short_description" ), bpy :: arg ( "long_description" ) = "" )))
. def ( "shortDescription" , & IPluginRequirement :: Problem :: shortDescription )
. def ( "longDescription" , & IPluginRequirement :: Problem :: longDescription );
iPluginRequirementClass
2020-11-11 17:25:55 +01:00
. def ( "check" , bpy :: pure_virtual ( & IPluginRequirement :: check ))
2020-11-11 16:14:28 +01:00
;
}
2020-11-11 11:23:15 +01:00
bpy :: class_ < PluginRequirementFactory , boost :: noncopyable > ( "PluginRequirementFactory" )
// pluginDependency
. def ( "pluginDependency" , + []( QStringList const & pluginNames ) {
return PluginRequirementFactory :: pluginDependency ( pluginNames );
2020-11-19 21:21:58 +01:00
}, bpy :: arg ( "plugins" ))
2020-11-11 11:23:15 +01:00
. def ( "pluginDependency" , + []( QString const & pluginName ) {
return PluginRequirementFactory :: pluginDependency ( pluginName );
2020-11-19 21:21:58 +01:00
}, bpy :: arg ( "plugin" ))
2020-11-11 11:23:15 +01:00
. staticmethod ( "pluginDependency" )
// gameDependency
. def ( "gameDependency" , + []( QStringList const & gameNames ) {
return PluginRequirementFactory :: gameDependency ( gameNames );
2020-11-19 21:21:58 +01:00
}, bpy :: arg ( "games" ))
2020-11-11 11:23:15 +01:00
. def ( "gameDependency" , + []( QString const & gameNames ) {
return PluginRequirementFactory :: gameDependency ( gameNames );
2020-11-19 21:21:58 +01:00
}, bpy :: arg ( "game" ))
2020-11-11 11:23:15 +01:00
. staticmethod ( "gameDependency" )
// diagnose
2020-11-19 21:21:58 +01:00
. def ( "diagnose" , & PluginRequirementFactory :: diagnose , bpy :: arg ( "diagnose" ))
2020-11-11 11:23:15 +01:00
. staticmethod ( "diagnose" )
// basic
2020-11-19 21:21:58 +01:00
. def ( "basic" , & PluginRequirementFactory :: basic , ( bpy :: arg ( "checker" ), "description" ))
2020-11-11 11:23:15 +01:00
. staticmethod ( "basic" );
2020-05-03 18:26:27 +02:00
bpy :: class_ < IOrganizer :: FileInfo > ( "FileInfo" , bpy :: init <> ())
2020-05-09 23:30:10 +02:00
. def_readwrite ( "filePath" , & IOrganizer :: FileInfo :: filePath )
. def_readwrite ( "archive" , & IOrganizer :: FileInfo :: archive )
. def_readwrite ( "origins" , & IOrganizer :: FileInfo :: origins )
2020-05-03 18:26:27 +02:00
;
2020-05-09 21:13:45 +02:00
bpy :: class_ < IOrganizer , boost :: noncopyable > ( "IOrganizer" , bpy :: no_init )
. def ( "createNexusBridge" , & IOrganizer :: createNexusBridge , bpy :: return_value_policy < bpy :: reference_existing_object > ())
. def ( "profileName" , & IOrganizer :: profileName )
. def ( "profilePath" , & IOrganizer :: profilePath )
. def ( "downloadsPath" , & IOrganizer :: downloadsPath )
. def ( "overwritePath" , & IOrganizer :: overwritePath )
. def ( "basePath" , & IOrganizer :: basePath )
. def ( "modsPath" , & IOrganizer :: modsPath )
. def ( "appVersion" , & IOrganizer :: appVersion )
2020-07-14 13:14:53 +02:00
. def ( "createMod" , & IOrganizer :: createMod , bpy :: return_value_policy < bpy :: reference_existing_object > (), bpy :: arg ( "name" ))
. def ( "getGame" , & IOrganizer :: getGame , bpy :: return_value_policy < bpy :: reference_existing_object > (), bpy :: arg ( "name" ))
. def ( "modDataChanged" , & IOrganizer :: modDataChanged , bpy :: arg ( "mod" ))
2020-11-11 11:23:15 +01:00
. def ( "isPluginEnabled" , + []( IOrganizer * o , IPlugin * plugin ) { return o -> isPluginEnabled ( plugin ); }, bpy :: arg ( "plugin" ))
. def ( "isPluginEnabled" , + []( IOrganizer * o , QString const & plugin ) { return o -> isPluginEnabled ( plugin ); }, bpy :: arg ( "plugin" ))
2020-07-14 13:14:53 +02:00
. def ( "pluginSetting" , & IOrganizer :: pluginSetting , ( bpy :: arg ( "plugin_name" ), "key" ))
. def ( "setPluginSetting" , & IOrganizer :: setPluginSetting , ( bpy :: arg ( "plugin_name" ), "key" , "value" ))
2020-07-20 19:36:58 +02:00
. def ( "persistent" , & IOrganizer :: persistent , ( bpy :: arg ( "plugin_name" ), "key" , bpy :: arg ( "default" ) = QVariant ()))
2020-07-14 13:14:53 +02:00
. def ( "setPersistent" , & IOrganizer :: setPersistent , ( bpy :: arg ( "plugin_name" ), "key" , "value" , bpy :: arg ( "sync" ) = true ))
2020-05-09 21:13:45 +02:00
. def ( "pluginDataPath" , & IOrganizer :: pluginDataPath )
2020-07-14 13:14:53 +02:00
. def ( "installMod" , & IOrganizer :: installMod , bpy :: return_value_policy < bpy :: reference_existing_object > (), ( bpy :: arg ( "filename" ), bpy :: arg ( "name_suggestion" ) = "" ))
. def ( "resolvePath" , & IOrganizer :: resolvePath , bpy :: arg ( "filename" ))
. def ( "listDirectories" , & IOrganizer :: listDirectories , bpy :: arg ( "directory" ))
2020-06-08 18:37:59 +02:00
// Provide multiple overloads of findFiles:
2020-07-14 13:14:53 +02:00
. def ( "findFiles" , + []( const IOrganizer * o , QString const & p , std :: function < bool ( QString const & ) > f ) { return o -> findFiles ( p , f ); },
( bpy :: arg ( "path" ), "filter" ))
2020-06-08 18:37:59 +02:00
// In C++, it is possible to create a QStringList implicitly from a single QString. This is not possible with the current
2020-11-06 09:06:55 -05:00
// converters in python (and I do not think it is a good idea to have it everywhere), but here it is nice to be able to
2020-06-08 18:37:59 +02:00
// pass a single string, so we add an extra overload.
2020-11-06 09:06:55 -05:00
// Important: the order matters, because a Python string can be converted to a QStringList since it is a sequence of
2020-06-08 18:37:59 +02:00
// single-character strings:
2020-07-14 13:14:53 +02:00
. def ( "findFiles" , + []( const IOrganizer * o , QString const & p , const QStringList & gf ) { return o -> findFiles ( p , gf ); },
( bpy :: arg ( "path" ), "patterns" ))
. def ( "findFiles" , + []( const IOrganizer * o , QString const & p , const QString & f ) { return o -> findFiles ( p , QStringList { f }); },
( bpy :: arg ( "path" ), "pattern" ))
2020-06-08 18:37:59 +02:00
2020-07-14 13:14:53 +02:00
. def ( "getFileOrigins" , & IOrganizer :: getFileOrigins , bpy :: arg ( "filename" ))
. def ( "findFileInfos" , & IOrganizer :: findFileInfos , ( bpy :: arg ( "path" ), "filter" ))
2020-05-09 21:13:45 +02:00
. def ( "downloadManager" , & IOrganizer :: downloadManager , bpy :: return_value_policy < bpy :: reference_existing_object > ())
. def ( "pluginList" , & IOrganizer :: pluginList , bpy :: return_value_policy < bpy :: reference_existing_object > ())
. def ( "modList" , & IOrganizer :: modList , bpy :: return_value_policy < bpy :: reference_existing_object > ())
. def ( "profile" , & IOrganizer :: profile , bpy :: return_value_policy < bpy :: reference_existing_object > ())
2020-05-09 21:32:23 +02:00
// Custom implementation for startApplication and waitForApplication because 1) HANDLE (= void*) is not properly
// converted from/to python, and 2) we need to convert the by-ptr argument to a return-tuple for waitForApplication:
2020-11-06 09:06:55 -05:00
. def ( "startApplication" ,
+ []( IOrganizer * o , const QString & executable , const QStringList & args , const QString & cwd , const QString & profile ,
2020-05-09 21:13:45 +02:00
const QString & forcedCustomOverwrite , bool ignoreCustomOverwrite ) {
return ( std :: uintptr_t ) o -> startApplication ( executable , args , cwd , profile , forcedCustomOverwrite , ignoreCustomOverwrite );
2020-11-06 09:06:55 -05:00
}, ( bpy :: arg ( "executable" ), ( bpy :: arg ( "args" ) = QStringList ()), ( bpy :: arg ( "cwd" ) = "" ), ( bpy :: arg ( "profile" ) = "" ),
2020-05-09 21:32:23 +02:00
( bpy :: arg ( "forcedCustomOverwrite" ) = "" ), ( bpy :: arg ( "ignoreCustomOverwrite" ) = false )), bpy :: return_value_policy < bpy :: return_by_value > ())
2020-05-09 21:13:45 +02:00
. def ( "waitForApplication" , + []( IOrganizer * o , std :: uintptr_t handle ) {
DWORD returnCode ;
bool result = o -> waitForApplication (( HANDLE ) handle , & returnCode );
return std :: make_tuple ( result , returnCode );
2020-07-14 13:14:53 +02:00
}, bpy :: arg ( "handle" ))
2020-10-25 16:18:55 +01:00
. def ( "refresh" , & IOrganizer :: refresh , ( bpy :: arg ( "save_changes" ) = true ))
2020-06-15 22:48:21 +02:00
. def ( "managedGame" , & IOrganizer :: managedGame , bpy :: return_value_policy < bpy :: reference_existing_object > ())
2020-05-09 21:32:23 +02:00
2020-07-14 13:14:53 +02:00
. def ( "onAboutToRun" , & IOrganizer :: onAboutToRun , bpy :: arg ( "callback" ))
. def ( "onFinishedRun" , & IOrganizer :: onFinishedRun , bpy :: arg ( "callback" ))
. def ( "onUserInterfaceInitialized" , & IOrganizer :: onUserInterfaceInitialized , bpy :: arg ( "callback" ))
2020-10-24 20:52:52 +02:00
. def ( "onProfileCreated" , & IOrganizer :: onProfileCreated , bpy :: arg ( "callback" ))
. def ( "onProfileRenamed" , & IOrganizer :: onProfileRenamed , bpy :: arg ( "callback" ))
. def ( "onProfileRemoved" , & IOrganizer :: onProfileRemoved , bpy :: arg ( "callback" ))
2020-07-14 13:14:53 +02:00
. def ( "onProfileChanged" , & IOrganizer :: onProfileChanged , bpy :: arg ( "callback" ))
2020-11-12 21:49:37 +01:00
2020-07-14 13:14:53 +02:00
. def ( "onPluginSettingChanged" , & IOrganizer :: onPluginSettingChanged , bpy :: arg ( "callback" ))
2020-11-12 21:49:37 +01:00
. def ( "onPluginEnabled" , + []( IOrganizer * o , std :: function < void ( const IPlugin * ) > const & func ) {
o -> onPluginEnabled ( func );
}, bpy :: arg ( "callback" ))
. def ( "onPluginEnabled" , + []( IOrganizer * o , QString const & name , std :: function < void () > const & func ) {
o -> onPluginEnabled ( name , func );
}, ( bpy :: arg ( "name" ), bpy :: arg ( "callback" )))
. def ( "onPluginDisabled" , + []( IOrganizer * o , std :: function < void ( const IPlugin * ) > const & func ) {
o -> onPluginDisabled ( func );
}, bpy :: arg ( "callback" ))
. def ( "onPluginDisabled" , + []( IOrganizer * o , QString const & name , std :: function < void () > const & func ) {
o -> onPluginDisabled ( name , func );
}, ( bpy :: arg ( "name" ), bpy :: arg ( "callback" )))
2020-10-25 16:18:55 +01:00
// DEPRECATED:
2020-10-25 17:46:00 +01:00
. def ( "getMod" , + []( IOrganizer * o , QString const & name ) {
utils :: show_deprecation_warning ( "getMod" ,
"IOrganizer::getMod(str) is deprecated, use IModList::getMod(str) instead." );
return o -> modList () -> getMod ( name );
}, bpy :: return_value_policy < bpy :: reference_existing_object > (), bpy :: arg ( "name" ))
2020-10-25 17:15:22 +01:00
. def ( "removeMod" , + []( IOrganizer * o , IModInterface * mod ) {
utils :: show_deprecation_warning ( "removeMod" ,
"IOrganizer::removeMod(IModInterface) is deprecated, use IModList::removeMod(IModInterface) instead." );
return o -> modList () -> removeMod ( mod );
}, bpy :: arg ( "mod" ))
2020-10-25 16:52:28 +01:00
. def ( "modsSortedByProfilePriority" , + []( IOrganizer * o ) {
utils :: show_deprecation_warning ( "modsSortedByProfilePriority" ,
"IOrganizer::modsSortedByProfilePriority() is deprecated, use IModList::allModsByProfilePriority() instead." );
return o -> modList () -> allModsByProfilePriority ();
})
2020-10-25 16:18:55 +01:00
. def ( "refreshModList" , + []( IOrganizer * o , bool s ) {
utils :: show_deprecation_warning ( "refreshModList" ,
"IOrganizer::refreshModList(bool) is deprecated, use IOrganizer::refresh(bool) instead." );
o -> refresh ( s );
}, ( bpy :: arg ( "save_changes" ) = true ))
. def ( "onModInstalled" , + []( IOrganizer * organizer , const std :: function < void ( QString const & ) >& func ) {
utils :: show_deprecation_warning ( "onModInstalled" ,
"IOrganizer::onModInstalled(Callable[[str], None]) is deprecated, "
"use IModList::onModInstalled(Callable[[IModInterface], None]) instead." );
2020-10-25 16:52:20 +01:00
return organizer -> modList () -> onModInstalled ([ func ]( MOBase :: IModInterface * m ) { func ( m -> name ()); });;
2020-10-25 16:18:55 +01:00
}, bpy :: arg ( "callback" ))
2020-11-06 09:22:23 -05:00
. def ( "getPluginDataPath" , & IOrganizer :: getPluginDataPath )
. staticmethod ( "getPluginDataPath" )
2018-07-24 01:51:04 -05:00
;
2020-05-01 21:32:08 +02:00
// FileTreeEntry Scope:
2020-05-03 18:24:32 +02:00
auto fileTreeEntryClass = bpy :: class_ < FileTreeEntry , boost :: noncopyable > ( "FileTreeEntry" , bpy :: no_init );
2020-05-01 21:32:08 +02:00
{
2020-11-06 09:06:55 -05:00
2020-05-01 21:32:08 +02:00
bpy :: scope scope = fileTreeEntryClass ;
2020-11-06 09:06:55 -05:00
2020-05-03 12:57:23 +02:00
bpy :: enum_ < FileTreeEntry :: FileTypes > ( "FileTypes" )
2020-05-01 21:32:08 +02:00
. value ( "FILE_OR_DIRECTORY" , FileTreeEntry :: FILE_OR_DIRECTORY )
. value ( "FILE" , FileTreeEntry :: FILE )
. value ( "DIRECTORY" , FileTreeEntry :: DIRECTORY )
. export_values ()
;
fileTreeEntryClass
. def ( "isFile" , & FileTreeEntry :: isFile )
. def ( "isDir" , & FileTreeEntry :: isDir )
2020-05-03 12:57:23 +02:00
// Forcing the conversion to FileTypeS to avoid having to expose FileType in python:
. def ( "fileType" , + []( FileTreeEntry * p ) { return FileTreeEntry :: FileTypes { p -> fileType () }; })
2020-05-01 21:32:08 +02:00
// This should probably not be exposed in python since we provide automatic downcast:
// .def("getTree", static_cast<std::shared_ptr<IFileTree>(FileTreeEntry::*)()>(&FileTreeEntry::astree))
2020-05-02 13:22:34 +02:00
. def ( "name" , & FileTreeEntry :: name )
. def ( "suffix" , & FileTreeEntry :: suffix )
2020-07-14 13:14:53 +02:00
. def ( "hasSuffix" , + []( FileTreeEntry * entry , QStringList suffixes ) { return entry -> hasSuffix ( suffixes ); }, bpy :: arg ( "suffixes" ))
. def ( "hasSuffix" , + []( FileTreeEntry * entry , QString suffix ) { return entry -> hasSuffix ( suffix ); }, bpy :: arg ( "suffix" ))
2020-05-09 18:19:31 +02:00
. def ( "parent" , static_cast < std :: shared_ptr < IFileTree > ( FileTreeEntry ::* )() > ( & FileTreeEntry :: parent ), "[optional]" )
2020-05-02 13:22:34 +02:00
. def ( "path" , & FileTreeEntry :: path , bpy :: arg ( "sep" ) = " \\ " )
2020-07-14 13:14:53 +02:00
. def ( "pathFrom" , & FileTreeEntry :: pathFrom , ( bpy :: arg ( "tree" ), bpy :: arg ( "sep" ) = " \\ " ))
2020-05-01 21:32:08 +02:00
// Mutable operation:
. def ( "detach" , & FileTreeEntry :: detach )
2020-07-14 13:14:53 +02:00
. def ( "moveTo" , & FileTreeEntry :: moveTo , bpy :: arg ( "tree" ))
2020-05-01 21:32:08 +02:00
2020-05-03 18:27:26 +02:00
// Special methods:
. def ( "__eq__" , + []( const FileTreeEntry * entry , QString other ) {
return entry -> compare ( other ) == 0 ;
})
. def ( "__eq__" , + []( const FileTreeEntry * entry , std :: shared_ptr < FileTreeEntry > other ) {
return entry == other . get ();
})
2020-05-01 21:32:08 +02:00
// Special methods for debug:
2020-05-03 18:27:26 +02:00
. def ( "__repr__" , + []( const FileTreeEntry * entry ) { return "FileTreeEntry( \" " + entry -> name () + " \" )" ; })
2020-05-01 21:32:08 +02:00
;
}
// IFileTree scope:
2020-05-09 18:19:31 +02:00
auto iFileTreeClass = bpy :: class_ < IFileTree , bpy :: bases < FileTreeEntry > , boost :: noncopyable > ( "IFileTree" , bpy :: no_init );
2020-05-01 21:32:08 +02:00
{
2020-11-06 09:06:55 -05:00
2020-05-01 21:32:08 +02:00
bpy :: scope scope = iFileTreeClass ;
bpy :: enum_ < IFileTree :: InsertPolicy > ( "InsertPolicy" )
. value ( "FAIL_IF_EXISTS" , IFileTree :: InsertPolicy :: FAIL_IF_EXISTS )
. value ( "REPLACE" , IFileTree :: InsertPolicy :: REPLACE )
. value ( "MERGE" , IFileTree :: InsertPolicy :: MERGE )
. export_values ()
;
2020-05-18 16:16:26 +02:00
bpy :: enum_ < IFileTree :: WalkReturn > ( "WalkReturn" )
. value ( "CONTINUE" , IFileTree :: WalkReturn :: CONTINUE )
. value ( "STOP" , IFileTree :: WalkReturn :: STOP )
. value ( "SKIP" , IFileTree :: WalkReturn :: SKIP )
. export_values ()
;
2020-05-01 21:32:08 +02:00
iFileTreeClass
2020-05-14 23:18:23 +02:00
// Non-mutable operations:
2020-07-14 13:14:53 +02:00
. def ( "exists" , static_cast < bool ( IFileTree ::* )( QString , IFileTree :: FileTypes ) const > ( & IFileTree :: exists ),
( bpy :: arg ( "path" ), bpy :: arg ( "type" ) = IFileTree :: FILE_OR_DIRECTORY ))
. def ( "find" , static_cast < std :: shared_ptr < FileTreeEntry > ( IFileTree ::* )( QString , IFileTree :: FileTypes ) > ( & IFileTree :: find ),
bpy :: return_value_policy < utils :: downcast_return < FileTreeEntry , IFileTree >> (), ( bpy :: arg ( "path" ), bpy :: arg ( "type" ) = IFileTree :: FILE_OR_DIRECTORY ), "[optional]" )
. def ( "pathTo" , & IFileTree :: pathTo , ( bpy :: arg ( "entry" ), bpy :: arg ( "sep" ) = " \\ " ))
2020-05-01 21:32:08 +02:00
2020-05-14 23:18:23 +02:00
// Note: walk() would probably be better as a generator in python, but it is likely impossible to construct
// from the C++ walk() method.
2020-07-14 13:14:53 +02:00
. def ( "walk" , & IFileTree :: walk , ( bpy :: arg ( "callback" ), bpy :: arg ( "sep" ) = " \\ " ))
2020-05-14 23:18:23 +02:00
2020-05-01 21:32:08 +02:00
// Kind-of-static operations:
. def ( "createOrphanTree" , & IFileTree :: createOrphanTree , bpy :: arg ( "name" ) = "" )
2020-05-14 23:18:23 +02:00
// addFile() and addDirectory throws exception instead of returning null pointer in order
// to have better traces.
2020-07-14 13:14:53 +02:00
. def ( "addFile" , + []( IFileTree * w , QString path , bool replaceIfExists ) {
auto result = w -> addFile ( path , replaceIfExists );
2020-05-14 23:18:23 +02:00
if ( result == nullptr ) {
throw std :: logic_error ( "addFile failed" );
}
return result ;
2020-07-14 13:14:53 +02:00
}, ( bpy :: arg ( "path" ), bpy :: arg ( "replace_if_exists" ) = false ))
. def ( "addDirectory" , + []( IFileTree * w , QString path ) {
auto result = w -> addDirectory ( path );
2020-05-14 23:18:23 +02:00
if ( result == nullptr ) {
throw std :: logic_error ( "addDirectory failed" );
}
return result ;
2020-07-14 13:14:53 +02:00
}, bpy :: arg ( "path" ))
2020-05-01 21:32:08 +02:00
2020-11-06 09:06:55 -05:00
// Merge needs custom return types depending if the user wants overrides or not. A failure is translated
2020-05-14 23:18:23 +02:00
// into an exception for easier tracing and handling.
. def ( "merge" , + []( IFileTree * p , std :: shared_ptr < IFileTree > other , bool returnOverwrites ) -> std :: variant < IFileTree :: OverwritesType , std :: size_t > {
2020-05-01 21:32:08 +02:00
IFileTree :: OverwritesType overwrites ;
auto result = p -> merge ( other , returnOverwrites ? & overwrites : nullptr );
if ( result == IFileTree :: MERGE_FAILED ) {
2020-05-14 23:18:23 +02:00
throw std :: logic_error ( "merge failed" );
2020-05-01 21:32:08 +02:00
}
if ( returnOverwrites ) {
2020-05-03 18:26:11 +02:00
return { overwrites };
2020-05-01 21:32:08 +02:00
}
2020-05-03 18:26:11 +02:00
return { result };
2020-07-14 13:14:53 +02:00
}, ( bpy :: arg ( "other" ), bpy :: arg ( "overwrites" ) = false ))
2020-05-01 21:32:08 +02:00
2020-05-14 23:18:23 +02:00
// Insert and erase returns an iterator, which makes no sense in python, so we convert it to bool. Erase is also
// renamed "remove" since "erase" is very C++.
. def ( "insert" , + []( IFileTree * p , std :: shared_ptr < FileTreeEntry > entry , IFileTree :: InsertPolicy insertPolicy ) {
return p -> insert ( entry , insertPolicy ) == p -> end ();
2020-07-14 13:14:53 +02:00
}, ( bpy :: arg ( "entry" ), bpy :: arg ( "policy" ) = IFileTree :: InsertPolicy :: FAIL_IF_EXISTS ))
2020-05-01 21:32:08 +02:00
2020-07-14 13:14:53 +02:00
. def ( "remove" , + []( IFileTree * p , QString name ) { return p -> erase ( name ). first != p -> end (); }, bpy :: arg ( "name" ))
. def ( "remove" , + []( IFileTree * p , std :: shared_ptr < FileTreeEntry > entry ) { return p -> erase ( entry ) != p -> end (); }, bpy :: arg ( "entry" ))
2020-05-01 21:32:08 +02:00
2020-07-14 13:14:53 +02:00
. def ( "move" , & IFileTree :: move , ( bpy :: arg ( "entry" ), "path" , bpy :: arg ( "policy" ) = IFileTree :: InsertPolicy :: FAIL_IF_EXISTS ))
2020-08-06 11:10:26 +02:00
. def ( "copy" , + []( IFileTree * w , std :: shared_ptr < FileTreeEntry > entry , QString path , IFileTree :: InsertPolicy insertPolicy ) {
2020-06-12 20:54:52 +02:00
auto result = w -> copy ( entry , path , insertPolicy );
if ( result == nullptr ) {
throw std :: logic_error ( "copy failed" );
}
return result ;
2020-07-14 13:14:53 +02:00
}, ( bpy :: arg ( "entry" ), bpy :: arg ( "path" ) = "" , bpy :: arg ( "insert_policy" ) = IFileTree :: InsertPolicy :: FAIL_IF_EXISTS ))
2020-05-14 23:18:23 +02:00
2020-05-01 21:32:08 +02:00
. def ( "clear" , & IFileTree :: clear )
2020-07-14 13:14:53 +02:00
. def ( "removeAll" , & IFileTree :: removeAll , bpy :: arg ( "names" ))
. def ( "removeIf" , & IFileTree :: removeIf , bpy :: arg ( "filter" ))
2020-05-01 21:32:08 +02:00
// Special methods:
. def ( "__getitem__" , static_cast < std :: shared_ptr < FileTreeEntry > ( IFileTree ::* )( std :: size_t ) > ( & IFileTree :: at ),
2020-05-11 23:00:29 +02:00
bpy :: return_value_policy < utils :: downcast_return < FileTreeEntry , IFileTree >> ())
. def ( "__iter__" , bpy :: range < bpy :: return_value_policy < utils :: downcast_return < FileTreeEntry , IFileTree >>> (
2020-05-01 21:32:08 +02:00
static_cast < IFileTree :: iterator ( IFileTree ::* )() > ( & IFileTree :: begin ),
static_cast < IFileTree :: iterator ( IFileTree ::* )() > ( & IFileTree :: end )))
. def ( "__len__" , & IFileTree :: size )
. def ( "__bool__" , + []( const IFileTree * tree ) { return ! tree -> empty (); })
2020-05-03 18:27:26 +02:00
. def ( "__repr__" , + []( const IFileTree * entry ) { return "IFileTree( \" " + entry -> name () + " \" )" ; })
2020-05-01 21:32:08 +02:00
;
}
2020-11-06 09:06:55 -05:00
2020-05-01 21:32:08 +02:00
2020-05-11 23:36:35 +02:00
bpy :: class_ < IProfile , boost :: noncopyable > ( "IProfile" , bpy :: no_init )
. def ( "name" , & IProfile :: name )
. def ( "absolutePath" , & IProfile :: absolutePath )
. def ( "localSavesEnabled" , & IProfile :: localSavesEnabled )
. def ( "localSettingsEnabled" , & IProfile :: localSettingsEnabled )
2020-06-08 21:45:01 +02:00
. def ( "invalidationActive" , + []( const IProfile * p ) {
bool supported ;
bool active = p -> invalidationActive ( & supported );
return std :: make_tuple ( active , supported );
})
2020-09-27 20:56:41 +02:00
. def ( "absoluteIniFilePath" , & IProfile :: absoluteIniFilePath , bpy :: arg ( "inifile" ))
2018-07-24 01:51:04 -05:00
;
2020-05-12 19:25:57 +02:00
bpy :: class_ < IModRepositoryBridge , boost :: noncopyable > ( "IModRepositoryBridge" , bpy :: no_init )
2020-07-14 13:14:53 +02:00
. def ( "requestDescription" , & IModRepositoryBridge :: requestDescription , ( bpy :: arg ( "game_name" ), "mod_id" , "user_data" ))
. def ( "requestFiles" , & IModRepositoryBridge :: requestFiles , ( bpy :: arg ( "game_name" ), "mod_id" , "user_data" ))
. def ( "requestFileInfo" , & IModRepositoryBridge :: requestFileInfo , ( bpy :: arg ( "game_name" ), "mod_id" , "file_id" , "user_data" ))
. def ( "requestDownloadURL" , & IModRepositoryBridge :: requestDownloadURL , ( bpy :: arg ( "game_name" ), "mod_id" , "file_id" , "user_data" ))
. def ( "requestToggleEndorsement" , & IModRepositoryBridge :: requestToggleEndorsement , ( bpy :: arg ( "game_name" ), "mod_id" , "mod_version" , "endorse" , "user_data" ))
2020-05-11 23:00:29 +02:00
Q_DELEGATE ( IModRepositoryBridge , QObject , "_object" )
2018-07-24 01:51:04 -05:00
;
2020-05-11 23:36:35 +02:00
bpy :: class_ < ModRepositoryFileInfo > ( "ModRepositoryFileInfo" , bpy :: no_init )
2020-07-14 13:14:53 +02:00
. def ( bpy :: init < const ModRepositoryFileInfo &> ( bpy :: arg ( "other" )))
. def ( bpy :: init < bpy :: optional < QString , int , int >> (( bpy :: arg ( "game_name" ), "mod_id" , "file_id" )))
2020-05-09 18:19:31 +02:00
. def ( "__str__" , & ModRepositoryFileInfo :: toString )
2020-07-14 13:14:53 +02:00
. def ( "createFromJson" , & ModRepositoryFileInfo :: createFromJson , bpy :: arg ( "data" )). staticmethod ( "createFromJson" )
2018-07-24 01:51:04 -05:00
. def_readwrite ( "name" , & ModRepositoryFileInfo :: name )
. def_readwrite ( "uri" , & ModRepositoryFileInfo :: uri )
. def_readwrite ( "description" , & ModRepositoryFileInfo :: description )
. def_readwrite ( "version" , & ModRepositoryFileInfo :: version )
. def_readwrite ( "newestVersion" , & ModRepositoryFileInfo :: newestVersion )
. def_readwrite ( "categoryID" , & ModRepositoryFileInfo :: categoryID )
. def_readwrite ( "modName" , & ModRepositoryFileInfo :: modName )
. def_readwrite ( "gameName" , & ModRepositoryFileInfo :: gameName )
. def_readwrite ( "modID" , & ModRepositoryFileInfo :: modID )
. def_readwrite ( "fileID" , & ModRepositoryFileInfo :: fileID )
. def_readwrite ( "fileSize" , & ModRepositoryFileInfo :: fileSize )
. def_readwrite ( "fileName" , & ModRepositoryFileInfo :: fileName )
. def_readwrite ( "fileCategory" , & ModRepositoryFileInfo :: fileCategory )
. def_readwrite ( "fileTime" , & ModRepositoryFileInfo :: fileTime )
. def_readwrite ( "repository" , & ModRepositoryFileInfo :: repository )
. def_readwrite ( "userData" , & ModRepositoryFileInfo :: userData )
;
2020-05-11 23:36:35 +02:00
bpy :: class_ < IDownloadManager , boost :: noncopyable > ( "IDownloadManager" , bpy :: no_init )
2020-07-14 13:14:53 +02:00
. def ( "startDownloadURLs" , & IDownloadManager :: startDownloadURLs , bpy :: arg ( "urls" ))
. def ( "startDownloadNexusFile" , & IDownloadManager :: startDownloadNexusFile , ( bpy :: arg ( "mod_id" ), "file_id" ))
. def ( "downloadPath" , & IDownloadManager :: downloadPath , bpy :: arg ( "id" ))
2020-10-14 18:48:14 +02:00
. def ( "onDownloadComplete" , & IDownloadManager :: onDownloadComplete , bpy :: arg ( "callback" ))
. def ( "onDownloadPaused" , & IDownloadManager :: onDownloadPaused , bpy :: arg ( "callback" ))
. def ( "onDownloadFailed" , & IDownloadManager :: onDownloadFailed , bpy :: arg ( "callback" ))
. def ( "onDownloadRemoved" , & IDownloadManager :: onDownloadRemoved , bpy :: arg ( "callback" ))
2018-07-24 01:51:04 -05:00
;
2020-05-09 21:13:45 +02:00
bpy :: class_ < IInstallationManager , boost :: noncopyable > ( "IInstallationManager" , bpy :: no_init )
2020-07-14 16:39:45 +02:00
. def ( "getSupportedExtensions" , & IInstallationManager :: getSupportedExtensions )
2020-07-14 13:14:53 +02:00
. def ( "extractFile" , & IInstallationManager :: extractFile , ( bpy :: arg ( "entry" ), bpy :: arg ( "silent" ) = false ))
. def ( "extractFiles" , & IInstallationManager :: extractFiles , ( bpy :: arg ( "entries" ), bpy :: arg ( "silent" ) = false ))
. def ( "createFile" , & IInstallationManager :: createFile , bpy :: arg ( "entry" ))
. def ( "installArchive" , & IInstallationManager :: installArchive , ( bpy :: arg ( "mod_name" ), "archive" , "mod_id" ))
2020-05-01 21:32:08 +02:00
;
2018-07-24 01:51:04 -05:00
2020-09-20 15:20:22 +02:00
bpy :: enum_ < EndorsedState > ( "EndorsedState" )
. value ( "ENDORSED_FALSE" , EndorsedState :: ENDORSED_FALSE )
. value ( "ENDORSED_TRUE" , EndorsedState :: ENDORSED_TRUE )
. value ( "ENDORSED_UNKNOWN" , EndorsedState :: ENDORSED_UNKNOWN )
. value ( "ENDORSED_NEVER" , EndorsedState :: ENDORSED_NEVER )
;
bpy :: enum_ < TrackedState > ( "TrackedState" )
. value ( "TRACKED_FALSE" , TrackedState :: TRACKED_FALSE )
. value ( "TRACKED_TRUE" , TrackedState :: TRACKED_TRUE )
. value ( "TRACKED_UNKNOWN" , TrackedState :: TRACKED_UNKNOWN )
;
2020-05-11 23:36:35 +02:00
bpy :: class_ < IModInterface , boost :: noncopyable > ( "IModInterface" , bpy :: no_init )
. def ( "name" , & IModInterface :: name )
. def ( "absolutePath" , & IModInterface :: absolutePath )
2020-09-20 15:20:22 +02:00
. def ( "comments" , & IModInterface :: comments )
. def ( "notes" , & IModInterface :: notes )
. def ( "gameName" , & IModInterface :: gameName )
. def ( "repository" , & IModInterface :: repository )
2020-09-22 21:13:23 +02:00
. def ( "nexusId" , & IModInterface :: nexusId )
2020-09-20 15:20:22 +02:00
. def ( "version" , & IModInterface :: version )
. def ( "newestVersion" , & IModInterface :: newestVersion )
. def ( "ignoredVersion" , & IModInterface :: ignoredVersion )
. def ( "installationFile" , & IModInterface :: installationFile )
. def ( "converted" , & IModInterface :: converted )
. def ( "validated" , & IModInterface :: validated )
. def ( "color" , & IModInterface :: color )
. def ( "url" , & IModInterface :: url )
. def ( "primaryCategory" , & IModInterface :: primaryCategory )
. def ( "categories" , & IModInterface :: categories )
. def ( "trackedState" , & IModInterface :: trackedState )
. def ( "endorsedState" , & IModInterface :: endorsedState )
2020-11-04 21:48:22 +01:00
. def ( "fileTree" , & IModInterface :: fileTree )
2020-09-20 15:20:22 +02:00
2020-07-14 13:14:53 +02:00
. def ( "setVersion" , & IModInterface :: setVersion , bpy :: arg ( "version" ))
. def ( "setNewestVersion" , & IModInterface :: setNewestVersion , bpy :: arg ( "version" ))
. def ( "setIsEndorsed" , & IModInterface :: setIsEndorsed , bpy :: arg ( "endorsed" ))
. def ( "setNexusID" , & IModInterface :: setNexusID , bpy :: arg ( "nexus_id" ))
. def ( "addNexusCategory" , & IModInterface :: addNexusCategory , bpy :: arg ( "category_id" ))
. def ( "addCategory" , & IModInterface :: addCategory , bpy :: arg ( "name" ))
. def ( "removeCategory" , & IModInterface :: removeCategory , bpy :: arg ( "name" ))
. def ( "setGameName" , & IModInterface :: setGameName , bpy :: arg ( "name" ))
. def ( "setName" , & IModInterface :: setName , bpy :: arg ( "name" ))
2020-10-09 20:32:07 +02:00
. def ( "setUrl" , & IModInterface :: setUrl , bpy :: arg ( "url" ))
2020-05-11 23:36:35 +02:00
. def ( "remove" , & IModInterface :: remove )
2020-09-20 21:30:01 +02:00
. def ( "pluginSetting" , & IModInterface :: pluginSetting , ( bpy :: arg ( "plugin_name" ), "key" , bpy :: arg ( "default" ) = QVariant ()))
. def ( "pluginSettings" , & IModInterface :: pluginSettings , bpy :: arg ( "plugin_name" ))
. def ( "setPluginSetting" , & IModInterface :: setPluginSetting , ( bpy :: arg ( "plugin_name" ), "key" , bpy :: arg ( "value" )))
2020-09-21 23:37:30 +02:00
. def ( "clearPluginSettings" , & IModInterface :: clearPluginSettings , bpy :: arg ( "plugin_name" ))
2020-09-20 21:30:01 +02:00
2018-07-24 01:51:04 -05:00
;
bpy :: enum_ < MOBase :: EGuessQuality > ( "GuessQuality" )
2020-05-02 13:22:55 +02:00
. value ( "INVALID" , MOBase :: GUESS_INVALID )
. value ( "FALLBACK" , MOBase :: GUESS_FALLBACK )
. value ( "GOOD" , MOBase :: GUESS_GOOD )
. value ( "META" , MOBase :: GUESS_META )
. value ( "PRESET" , MOBase :: GUESS_PRESET )
. value ( "USER" , MOBase :: GUESS_USER )
2018-07-24 01:51:04 -05:00
;
2020-05-02 15:34:06 +02:00
bpy :: class_ < MOBase :: GuessedValue < QString > , boost :: noncopyable > ( "GuessedString" )
. def ( bpy :: init <> ())
2020-07-14 13:33:48 +02:00
. def ( bpy :: init < QString const & , EGuessQuality > (( bpy :: arg ( "value" ), "quality" )))
2018-07-24 01:51:04 -05:00
. def ( "update" ,
2020-05-02 00:24:45 +02:00
static_cast < GuessedValue < QString >& ( GuessedValue < QString >::* )( const QString & ) > ( & GuessedValue < QString >:: update ),
2020-07-14 13:14:53 +02:00
bpy :: return_self <> (), bpy :: arg ( "value" ))
2020-05-02 00:24:45 +02:00
. def ( "update" ,
static_cast < GuessedValue < QString >& ( GuessedValue < QString >::* )( const QString & , EGuessQuality ) > ( & GuessedValue < QString >:: update ),
2020-07-14 13:14:53 +02:00
bpy :: return_self <> (), ( bpy :: arg ( "value" ), "quality" ))
2020-05-02 13:22:55 +02:00
// Methods to simulate the assignment operator:
2020-11-06 09:06:55 -05:00
. def ( "reset" , + []( GuessedValue < QString >* gv ) {
2020-07-14 13:14:53 +02:00
* gv = GuessedValue < QString > (); }, bpy :: return_self <> ())
2020-11-06 09:06:55 -05:00
. def ( "reset" , + []( GuessedValue < QString >* gv , const QString & value , EGuessQuality eq ) {
2020-07-14 14:36:11 +02:00
* gv = GuessedValue < QString > ( value , eq ); }, bpy :: return_self <> (), ( bpy :: arg ( "value" ), "quality" ))
2020-11-06 09:06:55 -05:00
. def ( "reset" , + []( GuessedValue < QString >* gv , const GuessedValue < QString >& other ) {
2020-07-14 14:36:11 +02:00
* gv = other ; }, bpy :: return_self <> (), bpy :: arg ( "other" ))
2020-05-02 13:22:55 +02:00
// Use an intermediate lambda to avoid having to register the std::function conversion:
2020-05-04 01:47:30 +02:00
. def ( "setFilter" , + []( GuessedValue < QString >* gv , std :: function < std :: variant < QString , bool > ( QString const & ) > fn ) {
2020-05-03 12:57:01 +02:00
gv -> setFilter ([ fn ]( QString & s ) {
auto ret = fn ( s );
2020-05-04 01:47:30 +02:00
return std :: visit ([ & s ]( auto v ) {
2020-05-03 12:57:01 +02:00
if constexpr ( std :: is_same_v < decltype ( v ), QString > ) {
s = v ;
return true ;
}
else if constexpr ( std :: is_same_v < decltype ( v ), bool > ) {
return v ;
}
}, ret );
});
2020-07-14 13:14:53 +02:00
}, bpy :: arg ( "filter" ))
2020-05-02 13:22:55 +02:00
2020-05-03 20:57:50 +02:00
// This makes a copy in python but it more practical than exposing an iterator:
. def ( "variants" , & GuessedValue < QString >:: variants , bpy :: return_value_policy < bpy :: copy_const_reference > ())
2020-05-02 00:24:45 +02:00
. def ( "__str__" , & MOBase :: GuessedValue < QString >:: operator const QString & , bpy :: return_value_policy < bpy :: copy_const_reference > ())
2018-07-24 01:51:04 -05:00
;
2018-12-21 02:30:58 -06:00
bpy :: enum_ < IPluginList :: PluginState > ( "PluginState" )
. value ( "missing" , IPluginList :: STATE_MISSING )
. value ( "inactive" , IPluginList :: STATE_INACTIVE )
. value ( "active" , IPluginList :: STATE_ACTIVE )
2020-05-13 15:55:05 +02:00
. value ( "MISSING" , IPluginList :: STATE_MISSING )
. value ( "INACTIVE" , IPluginList :: STATE_INACTIVE )
. value ( "ACTIVE" , IPluginList :: STATE_ACTIVE )
2018-12-21 02:30:58 -06:00
;
2020-05-11 23:36:35 +02:00
bpy :: class_ < IPluginList , boost :: noncopyable > ( "IPluginList" , bpy :: no_init )
2020-07-14 13:14:53 +02:00
. def ( "state" , & MOBase :: IPluginList :: state , bpy :: arg ( "name" ))
. def ( "priority" , & MOBase :: IPluginList :: priority , bpy :: arg ( "name" ))
2020-08-30 14:03:23 +02:00
. def ( "setPriority" , & MOBase :: IPluginList :: setPriority , ( bpy :: arg ( "name" ), "priority" ))
2020-07-14 13:14:53 +02:00
. def ( "loadOrder" , & MOBase :: IPluginList :: loadOrder , bpy :: arg ( "name" ))
. def ( "isMaster" , & MOBase :: IPluginList :: isMaster , bpy :: arg ( "name" ))
. def ( "masters" , & MOBase :: IPluginList :: masters , bpy :: arg ( "name" ))
. def ( "origin" , & MOBase :: IPluginList :: origin , bpy :: arg ( "name" ))
. def ( "onRefreshed" , & MOBase :: IPluginList :: onRefreshed , bpy :: arg ( "callback" ))
. def ( "onPluginMoved" , & MOBase :: IPluginList :: onPluginMoved , bpy :: arg ( "callback" ))
2020-09-05 13:49:11 +02:00
// Kept but deprecated for backward compatibility:
2020-09-05 14:49:19 +02:00
. def ( "onPluginStateChanged" , + []( IPluginList * modList , const std :: function < void ( const QString & , IPluginList :: PluginStates ) >& fn ) {
2020-09-05 13:49:11 +02:00
utils :: show_deprecation_warning ( "onPluginStateChanged" ,
"onPluginStateChanged(Callable[[str, IPluginList.PluginStates], None]) is deprecated, "
"use onPluginStateChanged(Callable[[Dict[str, IPluginList.PluginStates], None]) instead." );
return modList -> onPluginStateChanged ([ fn ]( auto const & map ) {
for ( const auto & entry : map ) {
fn ( entry . first , entry . second );
}
});
}, bpy :: arg ( "callback" ))
2020-08-27 18:30:22 +02:00
. def ( "onPluginStateChanged" , & MOBase :: IPluginList :: onPluginStateChanged , bpy :: arg ( "callback" ))
2020-05-11 23:36:35 +02:00
. def ( "pluginNames" , & MOBase :: IPluginList :: pluginNames )
2020-07-14 13:14:53 +02:00
. def ( "setState" , & MOBase :: IPluginList :: setState , ( bpy :: arg ( "name" ), "state" ))
. def ( "setLoadOrder" , & MOBase :: IPluginList :: setLoadOrder , bpy :: arg ( "loadorder" ))
2018-07-24 01:51:04 -05:00
;
2018-12-21 02:30:58 -06:00
bpy :: enum_ < IModList :: ModState > ( "ModState" )
. value ( "exists" , IModList :: STATE_EXISTS )
. value ( "active" , IModList :: STATE_ACTIVE )
. value ( "essential" , IModList :: STATE_ESSENTIAL )
. value ( "empty" , IModList :: STATE_EMPTY )
. value ( "endorsed" , IModList :: STATE_ENDORSED )
. value ( "valid" , IModList :: STATE_VALID )
. value ( "alternate" , IModList :: STATE_ALTERNATE )
2020-05-13 15:55:05 +02:00
. value ( "EXISTS" , IModList :: STATE_EXISTS )
. value ( "ACTIVE" , IModList :: STATE_ACTIVE )
. value ( "ESSENTIAL" , IModList :: STATE_ESSENTIAL )
. value ( "EMPTY" , IModList :: STATE_EMPTY )
. value ( "ENDORSED" , IModList :: STATE_ENDORSED )
. value ( "VALID" , IModList :: STATE_VALID )
. value ( "ALTERNATE" , IModList :: STATE_ALTERNATE )
2018-12-21 02:30:58 -06:00
;
2020-05-11 23:36:35 +02:00
bpy :: class_ < IModList , boost :: noncopyable > ( "IModList" , bpy :: no_init )
2020-07-14 13:14:53 +02:00
. def ( "displayName" , & MOBase :: IModList :: displayName , bpy :: arg ( "name" ))
2020-05-11 23:36:35 +02:00
. def ( "allMods" , & MOBase :: IModList :: allMods )
2020-10-25 18:37:53 +01:00
. def ( "allModsByProfilePriority" , & MOBase :: IModList :: allModsByProfilePriority , bpy :: arg ( "profile" ) = bpy :: ptr (( IProfile * ) nullptr ))
2020-10-25 16:52:28 +01:00
2020-10-25 17:46:00 +01:00
. def ( "getMod" , & MOBase :: IModList :: getMod , bpy :: return_value_policy < bpy :: reference_existing_object > (), bpy :: arg ( "name" ))
2020-10-25 17:15:22 +01:00
. def ( "removeMod" , & MOBase :: IModList :: removeMod , bpy :: arg ( "mod" ))
2020-07-14 13:14:53 +02:00
. def ( "state" , & MOBase :: IModList :: state , bpy :: arg ( "name" ))
2020-08-29 12:59:38 +02:00
. def ( "setActive" ,
static_cast < int ( IModList ::* )( QStringList const & , bool ) > ( & MOBase :: IModList :: setActive ), ( bpy :: arg ( "names" ), "active" ))
. def ( "setActive" ,
static_cast < bool ( IModList ::* )( QString const & , bool ) > ( & MOBase :: IModList :: setActive ), ( bpy :: arg ( "name" ), "active" ))
2020-07-14 13:14:53 +02:00
. def ( "priority" , & MOBase :: IModList :: priority , bpy :: arg ( "name" ))
. def ( "setPriority" , & MOBase :: IModList :: setPriority , ( bpy :: arg ( "name" ), "priority" ))
2020-08-29 19:55:06 +02:00
// Kept but deprecated for backward compatibility:
. def ( "onModStateChanged" , + []( IModList * modList , const std :: function < void ( const QString & , IModList :: ModStates ) >& fn ) {
2020-08-30 11:15:31 +02:00
utils :: show_deprecation_warning ( "onModStateChanged" ,
2020-08-29 19:55:06 +02:00
"onModStateChanged(Callable[[str, IModList.ModStates], None]) is deprecated, "
"use onModStateChanged(Callable[[Dict[str, IModList.ModStates], None]) instead." );
return modList -> onModStateChanged ([ fn ]( auto const & map ) {
for ( const auto & entry : map ) {
fn ( entry . first , entry . second );
}
});
}, bpy :: arg ( "callback" ))
2020-10-25 16:18:55 +01:00
. def ( "onModInstalled" , & MOBase :: IModList :: onModInstalled , bpy :: arg ( "callback" ))
. def ( "onModRemoved" , & MOBase :: IModList :: onModRemoved , bpy :: arg ( "callback" ))
2020-07-14 13:14:53 +02:00
. def ( "onModStateChanged" , & MOBase :: IModList :: onModStateChanged , bpy :: arg ( "callback" ))
. def ( "onModMoved" , & MOBase :: IModList :: onModMoved , bpy :: arg ( "callback" ))
2018-07-24 01:51:04 -05:00
;
2020-11-11 11:23:15 +01:00
// Note: localizedName(), master() and requirements have to go in all the plugin wrappers declaration,
2020-09-06 11:44:50 +02:00
// since the default functions are specific to each wrapper, otherwise in turns into an
// infinite recursion mess.
2020-05-09 18:19:31 +02:00
bpy :: class_ < IPluginWrapper , boost :: noncopyable > ( "IPlugin" )
2020-07-14 14:36:11 +02:00
. def ( "init" , bpy :: pure_virtual ( & MOBase :: IPlugin :: init ), bpy :: arg ( "organizer" ))
2020-05-09 18:19:31 +02:00
. def ( "name" , bpy :: pure_virtual ( & MOBase :: IPlugin :: name ))
2020-09-06 11:44:50 +02:00
. def ( "localizedName" , & MOBase :: IPlugin :: localizedName , & IPluginWrapper :: localizedName_Default )
2020-11-11 21:00:47 +01:00
. def ( "master" , & MOBase :: IPlugin :: master , & IPluginToolWrapper :: master_Default )
2020-05-09 18:19:31 +02:00
. def ( "author" , bpy :: pure_virtual ( & MOBase :: IPlugin :: author ))
. def ( "description" , bpy :: pure_virtual ( & MOBase :: IPlugin :: description ))
. def ( "version" , bpy :: pure_virtual ( & MOBase :: IPlugin :: version ))
2020-11-11 11:23:15 +01:00
. def ( "requirements" , & MOBase :: IPlugin :: requirements , & IPluginWrapper :: requirements_Default )
2020-05-09 18:19:31 +02:00
. def ( "settings" , bpy :: pure_virtual ( & MOBase :: IPlugin :: settings ))
;
2018-07-24 01:51:04 -05:00
2020-05-09 18:19:31 +02:00
bpy :: class_ < IPluginDiagnoseWrapper , bpy :: bases < IPlugin > , boost :: noncopyable > ( "IPluginDiagnose" )
2020-09-06 11:44:50 +02:00
. def ( "localizedName" , & MOBase :: IPlugin :: localizedName , & IPluginDiagnoseWrapper :: localizedName_Default )
2020-11-11 21:00:47 +01:00
. def ( "master" , & MOBase :: IPlugin :: master , & IPluginToolWrapper :: master_Default )
2020-11-11 11:23:15 +01:00
. def ( "requirements" , & MOBase :: IPlugin :: requirements , & IPluginDiagnoseWrapper :: requirements_Default )
2020-09-06 11:44:50 +02:00
2018-07-24 01:51:04 -05:00
. def ( "activeProblems" , bpy :: pure_virtual ( & MOBase :: IPluginDiagnose :: activeProblems ))
2020-07-14 13:14:53 +02:00
. def ( "shortDescription" , bpy :: pure_virtual ( & MOBase :: IPluginDiagnose :: shortDescription ), bpy :: arg ( "key" ))
. def ( "fullDescription" , bpy :: pure_virtual ( & MOBase :: IPluginDiagnose :: fullDescription ), bpy :: arg ( "key" ))
. def ( "hasGuidedFix" , bpy :: pure_virtual ( & MOBase :: IPluginDiagnose :: hasGuidedFix ), bpy :: arg ( "key" ))
. def ( "startGuidedFix" , bpy :: pure_virtual ( & MOBase :: IPluginDiagnose :: startGuidedFix ), bpy :: arg ( "key" ))
2018-07-24 01:51:04 -05:00
. def ( "_invalidate" , & IPluginDiagnoseWrapper :: invalidate )
;
2020-10-18 10:59:57 +02:00
bpy :: class_ < Mapping > ( "Mapping" , bpy :: init <> ())
. def ( "__init__" , bpy :: make_constructor ( + []( QString src , QString dst , bool dir , bool crt ) -> Mapping * {
return new Mapping { src , dst , dir , crt };
}, bpy :: default_call_policies (),
( bpy :: arg ( "source" ), bpy :: arg ( "destination" ), bpy :: arg ( "is_directory" ), bpy :: arg ( "create_target" ) = false )))
2018-07-24 01:51:04 -05:00
. def_readwrite ( "source" , & Mapping :: source )
. def_readwrite ( "destination" , & Mapping :: destination )
. def_readwrite ( "isDirectory" , & Mapping :: isDirectory )
. def_readwrite ( "createTarget" , & Mapping :: createTarget )
2020-10-18 10:59:57 +02:00
. def ( "__str__" , + []( Mapping * m ) {
return fmt :: format ( L "Mapping({}, {}, {}, {})" , m -> source . toStdWString (), m -> destination . toStdWString (), m -> isDirectory , m -> createTarget );
})
2018-07-24 01:51:04 -05:00
;
2020-05-09 18:19:31 +02:00
bpy :: class_ < IPluginFileMapperWrapper , bpy :: bases < IPlugin > , boost :: noncopyable > ( "IPluginFileMapper" )
2020-09-06 11:44:50 +02:00
. def ( "localizedName" , & MOBase :: IPlugin :: localizedName , & IPluginFileMapperWrapper :: localizedName_Default )
2020-11-11 21:00:47 +01:00
. def ( "master" , & MOBase :: IPlugin :: master , & IPluginToolWrapper :: master_Default )
2020-11-11 11:23:15 +01:00
. def ( "requirements" , & MOBase :: IPlugin :: requirements , & IPluginFileMapperWrapper :: requirements_Default )
2018-07-24 01:51:04 -05:00
. def ( "mappings" , bpy :: pure_virtual ( & MOBase :: IPluginFileMapper :: mappings ))
;
bpy :: enum_ < MOBase :: IPluginGame :: LoadOrderMechanism > ( "LoadOrderMechanism" )
. value ( "FileTime" , MOBase :: IPluginGame :: LoadOrderMechanism :: FileTime )
. value ( "PluginsTxt" , MOBase :: IPluginGame :: LoadOrderMechanism :: PluginsTxt )
2020-05-13 15:55:05 +02:00
. value ( "FILE_TIME" , MOBase :: IPluginGame :: LoadOrderMechanism :: FileTime )
. value ( "PLUGINS_TXT" , MOBase :: IPluginGame :: LoadOrderMechanism :: PluginsTxt )
2018-07-24 01:51:04 -05:00
;
bpy :: enum_ < MOBase :: IPluginGame :: SortMechanism > ( "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 )
;
// This doesn't actually do the conversion, but might be convenient for accessing the names for enum bits
bpy :: enum_ < MOBase :: IPluginGame :: ProfileSetting > ( "ProfileSetting" )
. value ( "mods" , MOBase :: IPluginGame :: MODS )
. value ( "configuration" , MOBase :: IPluginGame :: CONFIGURATION )
. value ( "savegames" , MOBase :: IPluginGame :: SAVEGAMES )
. value ( "preferDefaults" , MOBase :: IPluginGame :: PREFER_DEFAULTS )
2020-05-13 15:55:05 +02:00
. value ( "MODS" , MOBase :: IPluginGame :: MODS )
. value ( "CONFIGURATION" , MOBase :: IPluginGame :: CONFIGURATION )
. value ( "SAVEGAMES" , MOBase :: IPluginGame :: SAVEGAMES )
. value ( "PREFER_DEFAULTS" , MOBase :: IPluginGame :: PREFER_DEFAULTS )
2018-07-24 01:51:04 -05:00
;
2020-05-09 18:19:31 +02:00
bpy :: class_ < IPluginGameWrapper , bpy :: bases < IPlugin > , boost :: noncopyable > ( "IPluginGame" )
2020-09-06 11:44:50 +02:00
. def ( "localizedName" , & MOBase :: IPlugin :: localizedName , & IPluginGameWrapper :: localizedName_Default )
2020-11-11 21:00:47 +01:00
. def ( "master" , & MOBase :: IPlugin :: master , & IPluginToolWrapper :: master_Default )
2020-09-06 11:44:50 +02:00
2020-11-06 18:56:00 +01:00
. def ( "detectGame" , bpy :: pure_virtual ( & MOBase :: IPluginGame :: detectGame ))
2018-07-24 01:51:04 -05:00
. def ( "gameName" , bpy :: pure_virtual ( & MOBase :: IPluginGame :: gameName ))
2020-07-14 13:14:53 +02:00
. def ( "initializeProfile" , bpy :: pure_virtual ( & MOBase :: IPluginGame :: initializeProfile ), ( bpy :: arg ( "directory" ), "settings" ))
2020-11-18 19:23:00 +01:00
. def ( "listSaves" , bpy :: pure_virtual ( & MOBase :: IPluginGame :: listSaves ), bpy :: arg ( "folder" ))
2018-07-24 01:51:04 -05:00
. def ( "isInstalled" , bpy :: pure_virtual ( & MOBase :: IPluginGame :: isInstalled ))
. def ( "gameIcon" , bpy :: pure_virtual ( & MOBase :: IPluginGame :: gameIcon ))
. def ( "gameDirectory" , bpy :: pure_virtual ( & MOBase :: IPluginGame :: gameDirectory ))
. def ( "dataDirectory" , bpy :: pure_virtual ( & MOBase :: IPluginGame :: dataDirectory ))
2020-07-14 13:14:53 +02:00
. def ( "setGamePath" , bpy :: pure_virtual ( & MOBase :: IPluginGame :: setGamePath ), bpy :: arg ( "path" ))
2018-07-24 01:51:04 -05:00
. def ( "documentsDirectory" , bpy :: pure_virtual ( & MOBase :: IPluginGame :: documentsDirectory ))
. def ( "savesDirectory" , bpy :: pure_virtual ( & MOBase :: IPluginGame :: savesDirectory ))
. def ( "executables" , bpy :: pure_virtual ( & MOBase :: IPluginGame :: executables ))
2020-06-14 10:52:45 +02:00
. def ( "executableForcedLoads" , bpy :: pure_virtual ( & MOBase :: IPluginGame :: executableForcedLoads ))
2018-07-24 01:51:04 -05:00
. def ( "steamAPPId" , bpy :: pure_virtual ( & MOBase :: IPluginGame :: steamAPPId ))
. def ( "primaryPlugins" , bpy :: pure_virtual ( & MOBase :: IPluginGame :: primaryPlugins ))
. def ( "gameVariants" , bpy :: pure_virtual ( & MOBase :: IPluginGame :: gameVariants ))
2020-07-14 13:14:53 +02:00
. def ( "setGameVariant" , bpy :: pure_virtual ( & MOBase :: IPluginGame :: setGameVariant ), bpy :: arg ( "variant" ))
2018-07-24 01:51:04 -05:00
. def ( "binaryName" , bpy :: pure_virtual ( & MOBase :: IPluginGame :: binaryName ))
. def ( "gameShortName" , bpy :: pure_virtual ( & MOBase :: IPluginGame :: gameShortName ))
. def ( "primarySources" , bpy :: pure_virtual ( & MOBase :: IPluginGame :: primarySources ))
. def ( "validShortNames" , bpy :: pure_virtual ( & MOBase :: IPluginGame :: validShortNames ))
. def ( "gameNexusName" , bpy :: pure_virtual ( & MOBase :: IPluginGame :: gameNexusName ))
. def ( "iniFiles" , bpy :: pure_virtual ( & MOBase :: IPluginGame :: iniFiles ))
. def ( "DLCPlugins" , bpy :: pure_virtual ( & MOBase :: IPluginGame :: DLCPlugins ))
. def ( "CCPlugins" , bpy :: pure_virtual ( & MOBase :: IPluginGame :: CCPlugins ))
. def ( "loadOrderMechanism" , bpy :: pure_virtual ( & MOBase :: IPluginGame :: loadOrderMechanism ))
. def ( "sortMechanism" , bpy :: pure_virtual ( & MOBase :: IPluginGame :: sortMechanism ))
. def ( "nexusModOrganizerID" , bpy :: pure_virtual ( & MOBase :: IPluginGame :: nexusModOrganizerID ))
. def ( "nexusGameID" , bpy :: pure_virtual ( & MOBase :: IPluginGame :: nexusGameID ))
2020-07-14 13:14:53 +02:00
. def ( "looksValid" , bpy :: pure_virtual ( & MOBase :: IPluginGame :: looksValid ), bpy :: arg ( "directory" ))
2018-07-24 01:51:04 -05:00
. def ( "gameVersion" , bpy :: pure_virtual ( & MOBase :: IPluginGame :: gameVersion ))
. def ( "getLauncherName" , bpy :: pure_virtual ( & MOBase :: IPluginGame :: getLauncherName ))
2020-05-09 18:19:31 +02:00
. def ( "featureList" , + []( MOBase :: IPluginGame * p ) {
// Constructing a dict from class name to actual object:
bpy :: dict dict ;
mp11 :: mp_for_each <
2020-05-16 20:47:41 +02:00
// Must user pointers because mp_for_each construct object:
mp11 :: mp_transform < std :: add_pointer_t , MpGameFeaturesList >
2020-05-09 18:19:31 +02:00
> ([ & ]( auto * pt ) {
using T = std :: remove_pointer_t < decltype ( pt ) > ;
typename bpy :: reference_existing_object :: apply < T *>:: type converter ;
2018-07-24 01:51:04 -05:00
2020-05-09 18:19:31 +02:00
// Retrieve the python class object:
const bpy :: converter :: registration * registration = bpy :: converter :: registry :: query ( bpy :: type_id < T > ());
bpy :: object key = bpy :: object ( bpy :: handle <> ( bpy :: borrowed ( registration -> get_class_object ())));
// Set the object:
dict [ key ] = bpy :: handle <> ( converter ( p -> feature < T > ()));
});
return dict ;
})
2020-05-13 17:35:33 +02:00
. def ( "feature" , + []( MOBase :: IPluginGame * p , bpy :: object clsObj ) {
bpy :: object feature ;
mp11 :: mp_for_each <
// Must user pointers because mp_for_each construct object:
2020-05-16 20:47:41 +02:00
mp11 :: mp_transform < std :: add_pointer_t , MpGameFeaturesList >
2020-05-13 17:35:33 +02:00
> ([ & ]( auto * pt ) {
using T = std :: remove_pointer_t < decltype ( pt ) > ;
typename bpy :: reference_existing_object :: apply < T *>:: type converter ;
// Retrieve the python class object:
const bpy :: converter :: registration * registration = bpy :: converter :: registry :: query ( bpy :: type_id < T > ());
if ( clsObj . ptr () == ( PyObject * ) registration -> get_class_object ()) {
feature = bpy :: object ( bpy :: handle <> ( converter ( p -> feature < T > ())));
}
});
return feature ;
2020-07-14 13:14:53 +02:00
}, bpy :: arg ( "feature_type" ))
2018-07-24 01:51:04 -05:00
;
bpy :: enum_ < MOBase :: IPluginInstaller :: EInstallResult > ( "InstallResult" )
2020-05-02 13:22:55 +02:00
. 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 )
2018-07-24 01:51:04 -05:00
;
2020-05-09 18:19:31 +02:00
bpy :: class_ < IPluginInstaller , bpy :: bases < IPlugin > , boost :: noncopyable > ( "IPluginInstaller" , bpy :: no_init )
2020-07-14 13:14:53 +02:00
. def ( "isArchiveSupported" , & IPluginInstaller :: isArchiveSupported , bpy :: arg ( "tree" ))
2020-05-09 18:19:31 +02:00
. def ( "priority" , & IPluginInstaller :: priority )
2020-09-22 22:02:27 +02:00
. def ( "onInstallationStart" , & IPluginInstaller :: onInstallationStart , ( bpy :: arg ( "archive" ), bpy :: arg ( "reinstallation" ), bpy :: arg ( "current_mod" )))
2020-09-21 21:34:24 +02:00
. def ( "onInstallationEnd" , & IPluginInstaller :: onInstallationEnd , ( bpy :: arg ( "result" ), bpy :: arg ( "new_mod" )))
2020-05-09 18:19:31 +02:00
. def ( "isManualInstaller" , & IPluginInstaller :: isManualInstaller )
2020-07-14 13:14:53 +02:00
. def ( "setParentWidget" , & IPluginInstaller :: setParentWidget , bpy :: arg ( "parent" ))
. def ( "setInstallationManager" , & IPluginInstaller :: setInstallationManager , bpy :: arg ( "manager" ))
2020-05-09 18:19:31 +02:00
;
bpy :: class_ < IPluginInstallerSimpleWrapper , bpy :: bases < IPluginInstaller > , boost :: noncopyable > ( "IPluginInstallerSimple" )
2020-09-22 22:02:27 +02:00
. def ( "onInstallationStart" , & IPluginInstaller :: onInstallationStart , ( bpy :: arg ( "archive" ), bpy :: arg ( "reinstallation" ), bpy :: arg ( "current_mod" )))
2020-09-21 21:34:24 +02:00
. def ( "onInstallationEnd" , & IPluginInstaller :: onInstallationEnd , ( bpy :: arg ( "result" ), bpy :: arg ( "new_mod" )))
2020-09-06 11:44:50 +02:00
. def ( "localizedName" , & MOBase :: IPlugin :: localizedName , & IPluginInstallerSimpleWrapper :: localizedName_Default )
2020-11-11 21:00:47 +01:00
. def ( "master" , & MOBase :: IPlugin :: master , & IPluginToolWrapper :: master_Default )
2020-11-11 11:23:15 +01:00
. def ( "requirements" , & MOBase :: IPlugin :: requirements , & IPluginInstallerSimpleWrapper :: requirements_Default )
2020-09-06 11:44:50 +02:00
2020-05-09 18:19:31 +02:00
// Note: Keeping the variant here even if we always return a tuple to be consistent with the wrapper and
2020-05-04 20:09:24 +02:00
// have proper stubs generation.
. def ( "install" , + []( IPluginInstallerSimple * p , GuessedValue < QString >& modName , std :: shared_ptr < IFileTree >& tree , QString & version , int & nexusID )
-> std :: variant < IPluginInstaller :: EInstallResult , std :: shared_ptr < IFileTree > , std :: tuple < IPluginInstaller :: EInstallResult , std :: shared_ptr < IFileTree > , QString , int >> {
auto result = p -> install ( modName , tree , version , nexusID );
return std :: make_tuple ( result , tree , version , nexusID );
2020-07-14 13:14:53 +02:00
}, ( bpy :: arg ( "name" ), "tree" , "version" , "nexus_id" ))
2020-05-09 21:13:45 +02:00
. def ( "_parentWidget" , & IPluginInstallerSimpleWrapper :: parentWidget , bpy :: return_value_policy < bpy :: return_by_value > ())
. def ( "_manager" , & IPluginInstallerSimpleWrapper :: manager , bpy :: return_value_policy < bpy :: reference_existing_object > ())
2020-05-02 00:24:45 +02:00
;
2020-07-22 21:23:47 +02:00
bpy :: class_ < IPluginInstallerCustomWrapper , bpy :: bases < IPluginInstaller > , boost :: noncopyable > ( "IPluginInstallerCustom" )
2020-09-22 22:02:27 +02:00
. def ( "onInstallationStart" , & IPluginInstaller :: onInstallationStart , ( bpy :: arg ( "archive" ), bpy :: arg ( "reinstallation" ), bpy :: arg ( "current_mod" )))
2020-09-21 21:34:24 +02:00
. def ( "onInstallationEnd" , & IPluginInstaller :: onInstallationEnd , ( bpy :: arg ( "result" ), bpy :: arg ( "new_mod" )))
2020-09-06 11:44:50 +02:00
. def ( "localizedName" , & MOBase :: IPlugin :: localizedName , & IPluginInstallerCustomWrapper :: localizedName_Default )
2020-11-11 21:00:47 +01:00
. def ( "master" , & MOBase :: IPlugin :: master , & IPluginToolWrapper :: master_Default )
2020-11-11 11:23:15 +01:00
. def ( "requirements" , & MOBase :: IPlugin :: requirements , & IPluginInstallerCustomWrapper :: requirements_Default )
2020-09-06 11:44:50 +02:00
2020-11-06 09:06:55 -05:00
// Needs to add both otherwize boost does not understand:
2020-07-14 13:14:53 +02:00
. def ( "isArchiveSupported" , & IPluginInstaller :: isArchiveSupported , bpy :: arg ( "tree" ))
. def ( "isArchiveSupported" , & IPluginInstallerCustom :: isArchiveSupported , bpy :: arg ( "archive_name" ))
2020-05-09 18:19:31 +02:00
. def ( "supportedExtensions" , & IPluginInstallerCustom :: supportedExtensions )
2020-07-14 13:14:53 +02:00
. def ( "install" , & IPluginInstallerCustom :: install , ( bpy :: arg ( "mod_name" ), "game_name" , "archive_name" , "version" , "nexus_id" ))
2020-05-09 21:16:30 +02:00
. def ( "_parentWidget" , & IPluginInstallerSimpleWrapper :: parentWidget , bpy :: return_value_policy < bpy :: return_by_value > ())
. def ( "_manager" , & IPluginInstallerCustomWrapper :: manager , bpy :: return_value_policy < bpy :: reference_existing_object > ())
2020-05-09 18:19:31 +02:00
;
2018-07-24 01:51:04 -05:00
2020-07-22 21:23:47 +02:00
bpy :: class_ < IPluginModPageWrapper , bpy :: bases < IPlugin > , boost :: noncopyable > ( "IPluginModPage" )
2020-09-06 11:44:50 +02:00
. def ( "localizedName" , & MOBase :: IPlugin :: localizedName , & IPluginModPageWrapper :: localizedName_Default )
2020-11-11 21:00:47 +01:00
. def ( "master" , & MOBase :: IPlugin :: master , & IPluginToolWrapper :: master_Default )
2020-11-11 11:23:15 +01:00
. def ( "requirements" , & MOBase :: IPlugin :: requirements , & IPluginModPageWrapper :: requirements_Default )
2020-09-06 11:44:50 +02:00
2020-05-09 21:16:30 +02:00
. def ( "displayName" , bpy :: pure_virtual ( & IPluginModPage :: displayName ))
. def ( "icon" , bpy :: pure_virtual ( & IPluginModPage :: icon ))
. def ( "pageURL" , bpy :: pure_virtual ( & IPluginModPage :: pageURL ))
. def ( "useIntegratedBrowser" , bpy :: pure_virtual ( & IPluginModPage :: useIntegratedBrowser ))
2020-07-14 13:14:53 +02:00
. def ( "handlesDownload" , bpy :: pure_virtual ( & IPluginModPage :: handlesDownload ), ( bpy :: arg ( "page_url" ), "download_url" , "fileinfo" ))
. def ( "setParentWidget" , & IPluginModPage :: setParentWidget , & IPluginModPageWrapper :: setParentWidget_Default , bpy :: arg ( "parent" ))
2020-05-09 21:16:30 +02:00
. def ( "_parentWidget" , & IPluginModPageWrapper :: parentWidget , bpy :: return_value_policy < bpy :: return_by_value > ())
;
2018-07-24 01:51:04 -05:00
2020-05-09 18:19:31 +02:00
bpy :: class_ < IPluginPreviewWrapper , bpy :: bases < IPlugin > , boost :: noncopyable > ( "IPluginPreview" )
2020-09-06 11:44:50 +02:00
. def ( "localizedName" , & MOBase :: IPlugin :: localizedName , & IPluginPreviewWrapper :: localizedName_Default )
2020-11-11 21:00:47 +01:00
. def ( "master" , & MOBase :: IPlugin :: master , & IPluginToolWrapper :: master_Default )
2020-11-11 11:23:15 +01:00
. def ( "requirements" , & MOBase :: IPlugin :: requirements , & IPluginPreviewWrapper :: requirements_Default )
2020-09-06 11:44:50 +02:00
2020-05-09 21:16:30 +02:00
. def ( "supportedExtensions" , bpy :: pure_virtual ( & IPluginPreview :: supportedExtensions ))
2020-11-06 09:06:55 -05:00
. def ( "genFilePreview" , bpy :: pure_virtual ( & IPluginPreview :: genFilePreview ), bpy :: return_value_policy < bpy :: return_by_value > (),
2020-07-14 13:14:53 +02:00
( bpy :: arg ( "filename" ), "max_size" ))
2020-05-09 21:16:30 +02:00
;
2018-07-24 01:51:04 -05:00
bpy :: class_ < IPluginToolWrapper , bpy :: bases < IPlugin > , boost :: noncopyable > ( "IPluginTool" )
2020-09-06 11:44:50 +02:00
. def ( "localizedName" , & MOBase :: IPlugin :: localizedName , & IPluginToolWrapper :: localizedName_Default )
2020-11-11 21:00:47 +01:00
. def ( "master" , & MOBase :: IPlugin :: master , & IPluginToolWrapper :: master_Default )
2020-11-11 11:23:15 +01:00
. def ( "requirements" , & MOBase :: IPlugin :: requirements , & IPluginToolWrapper :: requirements_Default )
2020-09-06 11:44:50 +02:00
2020-05-09 21:16:30 +02:00
. def ( "displayName" , bpy :: pure_virtual ( & IPluginTool :: displayName ))
. def ( "tooltip" , bpy :: pure_virtual ( & IPluginTool :: tooltip ))
. def ( "icon" , bpy :: pure_virtual ( & IPluginTool :: icon ))
2020-05-21 23:11:56 +02:00
. def ( "display" , bpy :: pure_virtual ( & IPluginTool :: display ))
2020-07-14 13:14:53 +02:00
. def ( "setParentWidget" , & IPluginTool :: setParentWidget , & IPluginToolWrapper :: setParentWidget_Default , bpy :: arg ( "parent" ))
2020-05-09 21:16:30 +02:00
. def ( "_parentWidget" , & IPluginToolWrapper :: parentWidget , bpy :: return_value_policy < bpy :: return_by_value > ())
;
2018-07-24 01:51:04 -05:00
registerGameFeaturesPythonConverters ();
2020-06-09 23:31:25 +02:00
2020-07-14 13:14:53 +02:00
bpy :: def ( "getFileVersion" , & MOBase :: getFileVersion , bpy :: arg ( "filepath" ));
bpy :: def ( "getProductVersion" , & MOBase :: getProductVersion , bpy :: arg ( "executable" ));
bpy :: def ( "getIconForExecutable" , & MOBase :: iconForExecutable , bpy :: arg ( "executable" ));
2020-06-16 21:57:31 +02:00
2020-11-06 09:06:55 -05:00
// Expose MoVariant: MoVariant is a fake object whose only purpose is to be used as a type-hint
2020-06-16 22:12:25 +02:00
// on the python side (e.g., def foo(x: mobase.MoVariant)). The real MoVariant is defined in the
// generated stubs, since it's only relevant when doing type-checking, but this needs to be defined,
// otherwise MoVariant is not found when actually running plugins through MO2, making them crash.
2020-06-16 21:57:31 +02:00
bpy :: scope (). attr ( "MoVariant" ) = bpy :: object ();
2018-07-24 01:51:04 -05:00
}
2020-05-11 23:00:29 +02:00
/**
*
*/
class PythonRunner : public IPythonRunner
{
public :
2020-11-06 09:25:01 -05:00
PythonRunner ();
2020-11-19 20:40:05 +01:00
~ PythonRunner ();
2020-05-11 23:00:29 +02:00
bool initPython ( const QString & pythonDir );
QList < QObject *> instantiate ( const QString & pluginName );
bool isPythonInstalled () const ;
bool isPythonVersionSupported () const ;
private :
void initPath ();
2020-05-20 18:32:22 +02:00
/**
* @brief Ensure that the given folder is in sys.path.
*/
void ensureFolderInPath ( QString folder );
2020-05-11 23:00:29 +02:00
/**
* @brief Append the underlying object of the given python object to the
* interface list if it is an instance (pointer) of the given type.
*
* @param obj The object to check.
* @param interfaces The list to append the object to.
*
*/
template < class T >
void appendIfInstance ( bpy :: object const & obj , QList < QObject *>& interfaces );
private :
2020-05-20 20:52:31 +02:00
// List of python objects representing plugins to keep all the bpy::object "alive"
// during the execution.
std :: vector < bpy :: object > m_PythonObjects ;
2020-05-11 23:00:29 +02:00
wchar_t * m_PythonHome ;
};
2020-11-06 09:25:01 -05:00
IPythonRunner * CreatePythonRunner ( const QString & pythonDir )
2020-05-11 23:00:29 +02:00
{
2020-11-06 09:25:01 -05:00
PythonRunner * result = new PythonRunner ;
2020-05-11 23:00:29 +02:00
if ( result -> initPython ( pythonDir )) {
return result ;
}
else {
delete result ;
return nullptr ;
}
}
2018-07-24 01:51:04 -05:00
2020-11-06 09:25:01 -05:00
PythonRunner :: PythonRunner ()
2018-07-24 01:51:04 -05:00
{
m_PythonHome = new wchar_t [ MAX_PATH + 1 ];
}
2020-11-19 20:40:05 +01:00
PythonRunner ::~ PythonRunner () {
// We need the GIL lock when destroying Python objects.
GILock lock ;
m_PythonObjects . clear ();
}
2018-07-24 01:51:04 -05:00
static const char * argv0 = "ModOrganizer.exe" ;
2019-07-15 20:02:18 +01:00
struct PrintWrapper
{
void write ( const char * message )
{
buffer << message ;
if ( buffer . tellp () != 0 && buffer . str (). back () == '\n' )
{
2019-07-22 00:08:35 +01:00
// actually put the string in a variable so it doesn't get destroyed as soon as we get a pointer to its data
std :: string string = buffer . str (). substr ( 0 , buffer . str (). length () - 1 );
qDebug (). nospace (). noquote () << string . c_str ();
2019-07-15 20:02:18 +01:00
buffer = std :: stringstream ();
}
}
std :: stringstream buffer ;
};
2019-07-22 00:08:35 +01:00
// ErrWrapper is in error.h
2019-07-15 20:02:18 +01:00
BOOST_PYTHON_MODULE ( moprivate )
{
bpy :: class_ < PrintWrapper , boost :: noncopyable > ( "PrintWrapper" , bpy :: init <> ())
. def ( "write" , & PrintWrapper :: write );
bpy :: class_ < ErrWrapper , boost :: noncopyable > ( "ErrWrapper" , bpy :: init <> ())
2019-07-22 00:08:35 +01:00
. def ( "instance" , & ErrWrapper :: instance , bpy :: return_value_policy < bpy :: reference_existing_object > ()). staticmethod ( "instance" )
. def ( "write" , & ErrWrapper :: write )
. def ( "startRecordingExceptionMessage" , & ErrWrapper :: startRecordingExceptionMessage )
. def ( "stopRecordingExceptionMessage" , & ErrWrapper :: stopRecordingExceptionMessage )
. def ( "getLastExceptionMessage" , & ErrWrapper :: getLastExceptionMessage );
2020-05-16 17:37:57 +02:00
utils :: register_functor_converter < bool ( QString , bool ) > ();
// Expose a function to create a particular tree, only for debugging purpose, not in mobase.
bpy :: def ( "makeTree" , + []( std :: function < bool ( QString , bool ) > callback ) -> std :: shared_ptr < IFileTree > {
struct FileTree : IFileTree {
using callback_t = std :: function < bool ( QString , bool ) > ;
2020-11-06 09:06:55 -05:00
FileTree ( std :: shared_ptr < const IFileTree > parent , QString name , callback_t callback ) :
2020-05-16 17:37:57 +02:00
FileTreeEntry ( parent , name ), IFileTree (), m_Callback ( callback ){ }
2020-05-30 14:58:50 +02:00
std :: shared_ptr < FileTreeEntry > addFile ( QString name , bool ) override {
2020-05-16 17:37:57 +02:00
if ( m_Callback && ! m_Callback ( name , false )) {
throw UnsupportedOperationException ( "File rejected by callback." );
}
2020-05-23 17:32:01 +02:00
return IFileTree :: addFile ( name );
2020-05-16 17:37:57 +02:00
}
std :: shared_ptr < IFileTree > addDirectory ( QString name ) override {
if ( m_Callback && ! m_Callback ( name , true )) {
throw UnsupportedOperationException ( "Directory rejected by callback." );
}
return IFileTree :: addDirectory ( name );
}
protected :
std :: shared_ptr < IFileTree > makeDirectory ( std :: shared_ptr < const IFileTree > parent , QString name ) const override {
return std :: make_shared < FileTree > ( parent , name , m_Callback );
}
2020-05-23 17:32:01 +02:00
bool doPopulate ( std :: shared_ptr < const IFileTree > parent , std :: vector < std :: shared_ptr < FileTreeEntry >>& entries ) const override { return true ; }
2020-05-16 17:37:57 +02:00
std :: shared_ptr < IFileTree > doClone () const override { return std :: make_shared < FileTree > ( nullptr , name (), m_Callback ); }
private :
callback_t m_Callback ;
};
return std :: make_shared < FileTree > ( nullptr , "" , callback );
}, bpy :: arg ( "callback" ) = bpy :: object {});
2019-07-15 20:02:18 +01:00
}
2018-07-24 01:51:04 -05:00
bool PythonRunner :: initPython ( const QString & pythonPath )
{
2020-04-16 00:53:29 +01:00
if ( Py_IsInitialized ())
return true ;
2018-07-24 01:51:04 -05:00
try {
if ( ! pythonPath . isEmpty () && ! QFile :: exists ( pythonPath + "/python.exe" )) {
return false ;
}
pythonPath . toWCharArray ( m_PythonHome );
if ( ! pythonPath . isEmpty ()) {
Py_SetPythonHome ( m_PythonHome );
}
wchar_t argBuffer [ MAX_PATH ];
const size_t cSize = strlen ( argv0 ) + 1 ;
mbstowcs ( argBuffer , argv0 , MAX_PATH );
Py_SetProgramName ( argBuffer );
PyImport_AppendInittab ( "mobase" , & PyInit_mobase );
2019-07-15 20:02:18 +01:00
PyImport_AppendInittab ( "moprivate" , & PyInit_moprivate );
2018-07-24 01:51:04 -05:00
Py_OptimizeFlag = 2 ;
Py_NoSiteFlag = 1 ;
initPath ();
Py_InitializeEx ( 0 );
if ( ! Py_IsInitialized ()) {
2020-04-15 17:01:28 +01:00
if ( PyGILState_Check ())
PyEval_SaveThread ();
2018-07-24 01:51:04 -05:00
return false ;
}
PySys_SetArgv ( 0 , ( wchar_t ** ) & argBuffer );
2020-11-18 13:37:54 -06:00
auto os = bpy :: import ( "os" );
auto mainModule = bpy :: import ( "__main__" );
auto mainNamespace = mainModule . attr ( "__dict__" );
mainNamespace [ "os" ] = os ;
2018-07-24 01:51:04 -05:00
mainNamespace [ "sys" ] = bpy :: import ( "sys" );
2019-07-15 20:02:18 +01:00
mainNamespace [ "moprivate" ] = bpy :: import ( "moprivate" );
2020-05-20 20:52:31 +02:00
mainNamespace [ "mobase" ] = bpy :: import ( "mobase" );
2018-07-24 01:51:04 -05:00
bpy :: import ( "site" );
2020-11-18 13:37:54 -06:00
bpy :: exec ( "sys.stdout = moprivate.PrintWrapper() \n "
2019-07-22 00:08:35 +01:00
"sys.stderr = moprivate.ErrWrapper.instance() \n "
2020-11-18 14:30:40 -06:00
"sys.excepthook = lambda x, y, z: sys.__excepthook__(x, y, z) \n " ,
2018-07-24 01:51:04 -05:00
mainNamespace );
2019-07-15 20:02:18 +01:00
2020-11-18 13:37:54 -06:00
// add dlls directory
const auto dlls = QCoreApplication :: applicationDirPath (). toStdString () + "/dlls" ;
os . attr ( "add_dll_directory" )( dlls );
2020-11-09 20:08:29 +01:00
configure_python_logging ( mainNamespace [ "mobase" ]);
2020-11-09 18:23:57 +01:00
2020-04-15 17:01:28 +01:00
PyEval_SaveThread ();
2018-07-24 01:51:04 -05:00
return true ;
} catch ( const bpy :: error_already_set & ) {
qDebug ( "failed to init python" );
PyErr_Print ();
if ( PyErr_Occurred ()) {
PyErr_Print ();
} else {
qCritical ( "An unexpected C++ exception was thrown in python code" );
}
2020-04-15 17:01:28 +01:00
if ( PyGILState_Check ())
PyEval_SaveThread ();
2018-07-24 01:51:04 -05:00
return false ;
}
}
bool handled_exec_file ( bpy :: str filename , bpy :: object globals = bpy :: object (), bpy :: object locals = bpy :: object ())
{
return bpy :: handle_exception ( std :: bind < bpy :: object ( & )( bpy :: str , bpy :: object , bpy :: object ) > ( bpy :: exec_file , filename , globals , locals ));
}
void PythonRunner :: initPath ()
{
static QStringList paths = {
2020-11-02 13:46:02 -06:00
QCoreApplication :: applicationDirPath () + "/dlls/pythoncore.zip" ,
QCoreApplication :: applicationDirPath () + "/dlls/pythoncore" ,
2020-11-06 12:36:43 -06:00
IOrganizer :: getPluginDataPath ()
2018-07-24 01:51:04 -05:00
};
Py_SetPath ( paths . join ( ';' ). toStdWString (). c_str ());
}
2020-05-11 23:51:58 +02:00
void PythonRunner :: ensureFolderInPath ( QString folder ) {
bpy :: object sys = bpy :: import ( "sys" );
bpy :: list sysPath = bpy :: extract < bpy :: list > ( sys . attr ( "path" ));
// Converting to QStringList for Qt::CaseInsensitive and because .index()
// raise an exception:
QStringList currentPath = bpy :: extract < QStringList > ( sysPath );
if ( ! currentPath . contains ( folder , Qt :: CaseInsensitive )) {
sysPath . insert ( 0 , folder );
}
}
2020-05-05 17:52:54 +02:00
2020-05-06 12:51:27 +02:00
template < class T >
2020-05-05 17:52:54 +02:00
void PythonRunner :: appendIfInstance ( bpy :: object const & obj , QList < QObject *> & interfaces ) {
2020-05-06 12:51:27 +02:00
bpy :: extract < T *> extr { obj };
if ( extr . check ()) {
interfaces . append ( extr );
}
2020-05-05 17:52:54 +02:00
}
2018-07-24 01:51:04 -05:00
QList < QObject *> PythonRunner :: instantiate ( const QString & pluginName )
{
2020-06-13 19:04:58 +02:00
GILock lock ;
2020-05-20 20:52:31 +02:00
// `pluginName` can either be a python file (single-file plugin or a folder (whole module).
//
2020-11-06 09:06:55 -05:00
// For whole module, we simply add the parent folder to path, then we load the module with a simple
// bpy::import, and we retrieve the associated __dict__ from which we extract either createPlugin or
2020-05-20 20:52:31 +02:00
// createPlugins.
//
// For single file, we need to use bpy::exec_file, and we will use the context (global variables)
// from __main__ (already contains mobase, and other required module). Since the context is shared
// between called of `instantiate`, we need to make sure to remove createPlugin(s) from previous call.
2018-07-24 01:51:04 -05:00
try {
2020-05-20 20:52:31 +02:00
// Dictionary that will contain createPlugin() or createPlugins().
bpy :: dict moduleDict ;
2018-07-24 01:51:04 -05:00
2020-05-11 23:51:58 +02:00
if ( pluginName . endsWith ( ".py" )) {
2020-05-20 20:52:31 +02:00
bpy :: object mainModule = bpy :: import ( "__main__" );
bpy :: dict moduleNamespace = bpy :: extract < bpy :: dict > ( mainModule . attr ( "__dict__" ))();
2020-05-11 23:51:58 +02:00
std :: string temp = ToString ( pluginName );
2020-05-20 20:52:31 +02:00
if ( ! handled_exec_file ( temp . c_str (), moduleNamespace )) {
moduleDict = moduleNamespace ;
2020-05-11 23:51:58 +02:00
}
}
else {
// Retrieve the module name:
QStringList parts = pluginName . split ( "/" );
std :: string moduleName = ToString ( parts . takeLast ());
ensureFolderInPath ( parts . join ( "/" ));
2020-05-20 20:52:31 +02:00
moduleDict = bpy :: dict ( bpy :: import ( moduleName . c_str ()). attr ( "__dict__" ));
2018-07-24 01:51:04 -05:00
}
2020-05-20 20:52:31 +02:00
if ( bpy :: len ( moduleDict ) == 0 ) {
MOBase :: log :: error ( "Failed to import plugin from {}." , pluginName );
throw pyexcept :: PythonError ();
}
2020-05-05 17:52:54 +02:00
2020-05-20 20:52:31 +02:00
// Create the plugins:
std :: vector < bpy :: object > plugins ;
2020-05-05 17:52:54 +02:00
2020-05-20 20:52:31 +02:00
if ( moduleDict . has_key ( "createPlugin" )) {
plugins . push_back ( moduleDict [ "createPlugin" ]());
2018-07-24 01:51:04 -05:00
2020-05-20 20:52:31 +02:00
// Clear for future call
bpy :: delitem ( moduleDict , bpy :: str ( "createPlugin" ));
}
else if ( moduleDict . has_key ( "createPlugins" )) {
bpy :: object pyPlugins = moduleDict [ "createPlugins" ]();
if ( ! PySequence_Check ( pyPlugins . ptr ())) {
MOBase :: log :: error ( "Plugin {}: createPlugins must return a list." , pluginName );
}
else {
bpy :: list pyList ( pyPlugins );
int nPlugins = bpy :: len ( pyList );
for ( int i = 0 ; i < nPlugins ; ++ i ) {
plugins . push_back ( pyList [ i ]);
}
}
// Clear for future call
bpy :: delitem ( moduleDict , bpy :: str ( "createPlugins" ));
}
else {
MOBase :: log :: error ( "Plugin {}: missing a createPlugin(s) function." , pluginName );
}
// If we have no plugins, there was an issue, and we already logged the problem:
if ( plugins . empty ()) {
return QList < QObject *> ();
}
QList < QObject *> allInterfaceList ;
for ( bpy :: object pluginObj : plugins ) {
// Add the plugin to keep it alive:
m_PythonObjects . push_back ( pluginObj );
QList < QObject *> interfaceList ;
appendIfInstance < IPluginGame > ( pluginObj , interfaceList );
// Must try the wrapper because it's only a plugin extension interface in C++, so doesn't extend QObject
appendIfInstance < IPluginDiagnoseWrapper > ( pluginObj , interfaceList );
// Must try the wrapper because it's only a plugin extension interface in C++, so doesn't extend QObject
appendIfInstance < IPluginFileMapperWrapper > ( pluginObj , interfaceList );
appendIfInstance < IPluginInstallerCustom > ( pluginObj , interfaceList );
appendIfInstance < IPluginInstallerSimple > ( pluginObj , interfaceList );
appendIfInstance < IPluginModPage > ( pluginObj , interfaceList );
appendIfInstance < IPluginPreview > ( pluginObj , interfaceList );
appendIfInstance < IPluginTool > ( pluginObj , interfaceList );
if ( interfaceList . isEmpty ()) {
appendIfInstance < IPluginWrapper > ( pluginObj , interfaceList );
}
if ( interfaceList . isEmpty ()) {
MOBase :: log :: error ( "Plugin {}: no plugin interface implemented." , pluginName );
}
// Append the plugins to the main list:
allInterfaceList . append ( interfaceList );
}
return allInterfaceList ;
2020-11-06 09:06:55 -05:00
}
2020-05-20 20:52:31 +02:00
catch ( const bpy :: error_already_set & ) {
MOBase :: log :: error ( "Failed to import plugin from {}." , pluginName );
2020-05-09 21:13:45 +02:00
throw pyexcept :: PythonError ();
2018-07-24 01:51:04 -05:00
}
}
bool PythonRunner :: isPythonInstalled () const
{
return Py_IsInitialized () != 0 ;
}
bool PythonRunner :: isPythonVersionSupported () const
{
const char * version = Py_GetVersion ();
2020-05-14 23:24:38 +02:00
return strstr ( version , "3.8" ) == version ;
2018-07-24 01:51:04 -05:00
}