mirror of
https://github.com/ModOrganizer2/modorganizer-plugin_python.git
synced 2026-07-27 14:03:33 -07:00
Merge pull request #24 from ModOrganizer2/Develop
Stage for Release 2.2.0
This commit is contained in:
@@ -11,12 +11,6 @@ SET(DEPENDENCIES_DIR CACHE PATH "")
|
||||
# hint to find qt in dependencies path
|
||||
LIST(APPEND CMAKE_PREFIX_PATH ${QT_ROOT}/lib/cmake)
|
||||
|
||||
FILE(GLOB_RECURSE PYTHON_ROOT ${DEPENDENCIES_DIR}/Python*/pyconfig.h.in)
|
||||
GET_FILENAME_COMPONENT(PYTHON_ROOT ${PYTHON_ROOT} DIRECTORY)
|
||||
|
||||
FILE(GLOB_RECURSE SIP_ROOT ${DEPENDENCIES_DIR}/sip-*/siplib/sip.h)
|
||||
GET_FILENAME_COMPONENT(SIP_ROOT ${SIP_ROOT} DIRECTORY)
|
||||
|
||||
# need to install python
|
||||
IF(EXISTS "${PYTHON_ROOT}/PCbuild/python27.dll")
|
||||
INSTALL(FILES ${PYTHON_ROOT}/PCbuild/python27.dll DESTINATION bin)
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
version: 1.0.{build}
|
||||
skip_branch_with_pr: true
|
||||
image: Visual Studio 2017
|
||||
environment:
|
||||
WEBHOOK_URL:
|
||||
secure: gOKbXaZM9ImtMD5XrYITvdyZUW/az082G9OIN1EC1Vbg57wBaeLhi49uGjxPw5GVujHku6kxN6ab89zhbS5GVeluR76GM83IbKV4Sh7udXzoYZZdg6YudtYHzdhCgUeiedpswbuczTq9ceIkkfSEWZuh/lMAAVVwvcGsJAnoPFw=
|
||||
build_script:
|
||||
- cmd: >-
|
||||
git clone --depth=1 --branch=%APPVEYOR_REPO_BRANCH% https://github.com/ModOrganizer2/modorganizer-umbrella.git c:\projects\modorganizer-umbrella 2> $null
|
||||
|
||||
mkdir c:\projects\modorganizer-build -type directory
|
||||
|
||||
cd c:\projects\modorganizer-umbrella
|
||||
|
||||
C:\Python37-x64\python.exe unimake.py -d c:\projects\modorganizer-build -s Appveyor_Build=True %APPVEYOR_PROJECT_NAME%
|
||||
artifacts:
|
||||
- path: vsbuild\src\proxy\RelWithDebInfo\plugin_python.dll
|
||||
name: plugin_python_dll
|
||||
- path: vsbuild\src\proxy\RelWithDebInfo\plugin_python.pdb
|
||||
name: plugin_python_pdb
|
||||
- path: vsbuild\src\proxy\RelWithDebInfo\plugin_python.lib
|
||||
name: plugin_python_lib
|
||||
- path: vsbuild\src\runner\RelWithDebInfo\pythonrunner.dll
|
||||
name: pythonrunner_dll
|
||||
- path: vsbuild\src\runner\RelWithDebInfo\pythonrunner.pdb
|
||||
name: pythonrunner_pdb
|
||||
- path: vsbuild\src\runner\RelWithDebInfo\pythonrunner.lib
|
||||
name: pythonrunner_lib
|
||||
on_success:
|
||||
- ps: Set-Location -Path $env:APPVEYOR_BUILD_FOLDER
|
||||
- ps: Invoke-RestMethod https://raw.githubusercontent.com/DiscordHooks/appveyor-discord-webhook/master/send.ps1 -o send.ps1
|
||||
- ps: ./send.ps1 success $env:WEBHOOK_URL
|
||||
on_failure:
|
||||
- ps: Set-Location -Path $env:APPVEYOR_BUILD_FOLDER
|
||||
- ps: Invoke-RestMethod https://raw.githubusercontent.com/DiscordHooks/appveyor-discord-webhook/master/send.ps1 -o send.ps1
|
||||
- ps: ./send.ps1 failure $env:WEBHOOK_URL
|
||||
@@ -13,6 +13,7 @@ SET(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
SET(CMAKE_AUTOMOC ON)
|
||||
SET(CMAKE_AUTOUIC ON)
|
||||
FIND_PACKAGE(Qt5Widgets REQUIRED)
|
||||
FIND_PACKAGE(Qt5Network REQUIRED)
|
||||
#QT5_WRAP_UI(${PROJ_NAME}_UIHDRS ${${PROJ_NAME}_FORMS})
|
||||
|
||||
SET(Boost_USE_STATIC_LIBS ON)
|
||||
@@ -24,7 +25,7 @@ IF (Boost_FOUND)
|
||||
INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS})
|
||||
ENDIF (Boost_FOUND)
|
||||
|
||||
SET(default_project_path "${CMAKE_SOURCE_DIR}/../..")
|
||||
SET(default_project_path "${DEPENDENCIES_DIR}/modorganizer_super")
|
||||
GET_FILENAME_COMPONENT(${default_project_path} ${default_project_path} REALPATH)
|
||||
|
||||
SET(project_path "${default_project_path}" CACHE PATH "path to the other mo projects")
|
||||
@@ -33,15 +34,15 @@ SET(lib_path "${project_path}/../../install/libs")
|
||||
ADD_DEFINITIONS(-DUNICODE -D_UNICODE)
|
||||
|
||||
INCLUDE_DIRECTORIES(${project_path}/uibase/src
|
||||
${project_path}/plugin_python/src/runner/
|
||||
${PYTHON_ROOT}/Include
|
||||
${PYTHON_ROOT}/PC)
|
||||
${CMAKE_SOURCE_DIR}/src/runner/
|
||||
${PYTHON_ROOT}/Include)
|
||||
LINK_DIRECTORIES(${lib_path})
|
||||
|
||||
|
||||
ADD_LIBRARY(${PROJ_NAME} SHARED ${${PROJ_NAME}_HDRS} ${${PROJ_NAME}_SRCS} ${${PROJ_NAME}_UIHDRS})
|
||||
TARGET_LINK_LIBRARIES(${PROJ_NAME}
|
||||
Qt5::Widgets
|
||||
Qt5::Network
|
||||
${Boost_LIBRARIES}
|
||||
uibase)
|
||||
|
||||
|
||||
@@ -171,7 +171,7 @@ bool ProxyPython::init(IOrganizer *moInfo)
|
||||
return true;
|
||||
} else {
|
||||
DWORD error = ::GetLastError();
|
||||
qCritical("Failed to load python runner (%s): %s", qPrintable(m_TempRunnerFile), qPrintable(windowsErrorString(error)));
|
||||
qCritical("Failed to load python runner (%s): %s", qUtf8Printable(m_TempRunnerFile), qUtf8Printable(windowsErrorString(error)));
|
||||
if (error == ERROR_MOD_NOT_FOUND) {
|
||||
m_LoadFailure = FAIL_MISSINGDEPENDENCIES;
|
||||
}
|
||||
@@ -196,7 +196,7 @@ QString ProxyPython::description() const
|
||||
|
||||
VersionInfo ProxyPython::version() const
|
||||
{
|
||||
return VersionInfo(2, 0, 0, VersionInfo::RELEASE_FINAL);
|
||||
return VersionInfo(2, 0, 1, VersionInfo::RELEASE_FINAL);
|
||||
}
|
||||
|
||||
bool ProxyPython::isActive() const
|
||||
|
||||
@@ -15,6 +15,7 @@ SET(CMAKE_AUTOMOC ON)
|
||||
SET(CMAKE_AUTOUIC ON)
|
||||
ADD_DEFINITIONS(-DQT_NO_KEYWORDS)
|
||||
FIND_PACKAGE(Qt5Widgets REQUIRED)
|
||||
FIND_PACKAGE(Qt5Network REQUIRED)
|
||||
#QT5_WRAP_UI(${PROJ_NAME}_UIHDRS ${${PROJ_NAME}_FORMS})
|
||||
FIND_PACKAGE(Qt5LinguistTools)
|
||||
QT5_CREATE_TRANSLATION(${PROJ_NAME}_translations_qm ${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/src/${PROJ_NAME}_en.ts)
|
||||
@@ -28,7 +29,7 @@ IF (Boost_FOUND)
|
||||
INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS})
|
||||
ENDIF (Boost_FOUND)
|
||||
|
||||
SET(default_project_path "${CMAKE_SOURCE_DIR}/..")
|
||||
SET(default_project_path "${DEPENDENCIES_DIR}/modorganizer_super")
|
||||
GET_FILENAME_COMPONENT(${default_project_path} ${default_project_path} REALPATH)
|
||||
|
||||
SET(project_path "${default_project_path}" CACHE PATH "path to the other mo projects")
|
||||
@@ -37,17 +38,16 @@ SET(lib_path "${project_path}/../../install/libs")
|
||||
INCLUDE_DIRECTORIES(${project_path}/uibase/src
|
||||
${project_path}/game_features/src
|
||||
${PYTHON_ROOT}/Include
|
||||
${SIP_ROOT}
|
||||
${PYTHON_ROOT}/PC)
|
||||
|
||||
LINK_DIRECTORIES(${lib_path}
|
||||
${PYTHON_ROOT}/PCbuild
|
||||
${Boost_LIBRARY_DIRS}
|
||||
${SIP_ROOT})
|
||||
${Boost_LIBRARY_DIRS})
|
||||
|
||||
ADD_LIBRARY(${PROJ_NAME} SHARED ${${PROJ_NAME}_HDRS} ${${PROJ_NAME}_SRCS} ${${PROJ_NAME}_translations_qm})
|
||||
TARGET_LINK_LIBRARIES(${PROJ_NAME}
|
||||
Qt5::Widgets
|
||||
Qt5::Network
|
||||
uibase)
|
||||
|
||||
ADD_DEFINITIONS(-DPYTHONRUNNER_LIBRARY)
|
||||
|
||||
@@ -178,6 +178,11 @@ QList<MOBase::ExecutableInfo> IPluginGameWrapper::executables() const
|
||||
return basicWrapperFunctionImplementation<IPluginGameWrapper, QList<MOBase::ExecutableInfo>>(this, "executables");
|
||||
}
|
||||
|
||||
QList<MOBase::ExecutableForcedLoadSetting> IPluginGameWrapper::executableForcedLoads() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<IPluginGameWrapper, QList<MOBase::ExecutableForcedLoadSetting>>(this, "executableForcedLoads");
|
||||
}
|
||||
|
||||
QString IPluginGameWrapper::steamAPPId() const
|
||||
{
|
||||
return basicWrapperFunctionImplementation<IPluginGameWrapper, QString>(this, "steamAPPId");
|
||||
|
||||
@@ -101,6 +101,7 @@ public:
|
||||
virtual QDir documentsDirectory() const override;
|
||||
virtual QDir savesDirectory() const override;
|
||||
virtual QList<MOBase::ExecutableInfo> executables() const override;
|
||||
virtual QList<MOBase::ExecutableForcedLoadSetting> executableForcedLoads() const override;
|
||||
virtual QString steamAPPId() const override;
|
||||
virtual QStringList primaryPlugins() const override;
|
||||
virtual QStringList gameVariants() const override;
|
||||
|
||||
@@ -73,7 +73,7 @@ struct QString_to_python_str
|
||||
{
|
||||
static PyObject *convert(const QString &str) {
|
||||
// It's safer to explicitly convert to unicode as if we don't, this can return either str or unicode without it being easy to know which to expect
|
||||
bpy::object pyStr = bpy::object(str.toUtf8().constData());
|
||||
bpy::object pyStr = bpy::object(qUtf8Printable(str));
|
||||
if (SIPBytes_Check(pyStr.ptr()))
|
||||
pyStr = pyStr.attr("decode")("utf-8");
|
||||
return bpy::incref(pyStr.ptr());
|
||||
@@ -960,6 +960,7 @@ BOOST_PYTHON_MODULE(mobase)
|
||||
.def("downloadsPath", bpy::pure_virtual(&IOrganizer::downloadsPath))
|
||||
.def("overwritePath", bpy::pure_virtual(&IOrganizer::overwritePath))
|
||||
.def("basePath", bpy::pure_virtual(&IOrganizer::basePath))
|
||||
.def("modsPath", bpy::pure_virtual(&IOrganizer::modsPath))
|
||||
.def("appVersion", bpy::pure_virtual(&IOrganizer::appVersion))
|
||||
.def("getMod", bpy::pure_virtual(&IOrganizer::getMod), bpy::return_value_policy<bpy::reference_existing_object>())
|
||||
.def("createMod", bpy::pure_virtual(&IOrganizer::createMod), bpy::return_value_policy<bpy::reference_existing_object>())
|
||||
@@ -981,7 +982,7 @@ BOOST_PYTHON_MODULE(mobase)
|
||||
.def("pluginList", bpy::pure_virtual(&IOrganizer::pluginList), bpy::return_value_policy<bpy::reference_existing_object>())
|
||||
.def("modList", bpy::pure_virtual(&IOrganizer::modList), bpy::return_value_policy<bpy::reference_existing_object>())
|
||||
.def("profile", bpy::pure_virtual(&IOrganizer::profile), bpy::return_value_policy<bpy::reference_existing_object>())
|
||||
.def("startApplication", bpy::pure_virtual(&IOrganizer::startApplication), ((bpy::arg("args")=QStringList()), (bpy::arg("cwd")=""), (bpy::arg("profile")="")), bpy::return_value_policy<bpy::return_by_value>())
|
||||
.def("startApplication", bpy::pure_virtual(&IOrganizer::startApplication), ((bpy::arg("args")=QStringList()), (bpy::arg("cwd")=""), (bpy::arg("profile")=""), (bpy::arg("forcedCustomOverwrite")=""), (bpy::arg("ignoreCustomOverwrite")=false)), bpy::return_value_policy<bpy::return_by_value>())
|
||||
//.def("waitForApplication", bpy::pure_virtual(&IOrganizer::waitForApplication), (bpy::arg("exitCode")=nullptr), bpy::return_value_policy<bpy::return_by_value>())
|
||||
// Use wrapped version
|
||||
.def("waitForApplication", waitForApplication)
|
||||
@@ -1069,6 +1070,7 @@ BOOST_PYTHON_MODULE(mobase)
|
||||
.def("addCategory", bpy::pure_virtual(&IModInterface::addCategory))
|
||||
.def("removeCategory", bpy::pure_virtual(&IModInterface::removeCategory))
|
||||
.def("categories", bpy::pure_virtual(&IModInterface::categories))
|
||||
.def("setGameName", bpy::pure_virtual(&IModInterface::setGameName))
|
||||
.def("setName", bpy::pure_virtual(&IModInterface::setName))
|
||||
.def("remove", bpy::pure_virtual(&IModInterface::remove))
|
||||
;
|
||||
@@ -1093,6 +1095,12 @@ BOOST_PYTHON_MODULE(mobase)
|
||||
QFlags_from_python_obj<IPluginList::PluginState>();
|
||||
Functor0_converter<void>(); // converter for the onRefreshed-callback
|
||||
|
||||
bpy::enum_<IPluginList::PluginState>("PluginState")
|
||||
.value("missing", IPluginList::STATE_MISSING)
|
||||
.value("inactive", IPluginList::STATE_INACTIVE)
|
||||
.value("active", IPluginList::STATE_ACTIVE)
|
||||
;
|
||||
|
||||
bpy::class_<IPluginListWrapper, boost::noncopyable>("IPluginList")
|
||||
.def("state", bpy::pure_virtual(&MOBase::IPluginList::state))
|
||||
.def("priority", bpy::pure_virtual(&MOBase::IPluginList::priority))
|
||||
@@ -1111,6 +1119,16 @@ BOOST_PYTHON_MODULE(mobase)
|
||||
QFlags_from_python_obj<IModList::ModState>();
|
||||
Functor2_converter<void, const QString&, IModList::ModStates>(); // converter for the onModStateChanged-callback
|
||||
|
||||
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)
|
||||
;
|
||||
|
||||
bpy::class_<IModListWrapper, boost::noncopyable>("IModList")
|
||||
.def("displayName", bpy::pure_virtual(&MOBase::IModList::displayName))
|
||||
.def("allMods", bpy::pure_virtual(&MOBase::IModList::allMods))
|
||||
@@ -1392,7 +1410,7 @@ QList<QObject*> PythonRunner::instantiate(const QString &pluginName)
|
||||
|
||||
return interfaceList;
|
||||
} catch (const bpy::error_already_set&) {
|
||||
qWarning("failed to run python script \"%s\"", qPrintable(pluginName));
|
||||
qWarning("failed to run python script \"%s\"", qUtf8Printable(pluginName));
|
||||
reportPythonError();
|
||||
}
|
||||
return QList<QObject*>();
|
||||
|
||||
@@ -63,8 +63,8 @@ public:
|
||||
{ m_Wrapped->requestFiles(gameName, modID, userData); }
|
||||
void requestFileInfo(QString gameName, int modID, int fileID, QVariant userData)
|
||||
{ m_Wrapped->requestFileInfo(gameName, modID, fileID, userData); }
|
||||
void requestToggleEndorsement(QString gameName, int modID, bool endorse, QVariant userData)
|
||||
{ m_Wrapped->requestToggleEndorsement(gameName, modID, endorse, userData); }
|
||||
void requestToggleEndorsement(QString gameName, int modID, QString modVersion, bool endorse, QVariant userData)
|
||||
{ m_Wrapped->requestToggleEndorsement(gameName, modID, modVersion, endorse, userData); }
|
||||
|
||||
void onFilesAvailable(boost::python::object callback) {
|
||||
m_FilesAvailableHandler = callback;
|
||||
@@ -94,6 +94,14 @@ public:
|
||||
Qt::UniqueConnection);
|
||||
}
|
||||
|
||||
void onTrackingToggled(boost::python::object callback) {
|
||||
m_TrackingToggledHandler = callback;
|
||||
connect(m_Wrapped, SIGNAL(trackingToggled(int,QVariant,bool)),
|
||||
this, SLOT(trackingToggled(int,QVariant,bool)),
|
||||
Qt::UniqueConnection);
|
||||
|
||||
}
|
||||
|
||||
void onRequestFailed(boost::python::object callback) {
|
||||
m_FailedHandler = callback;
|
||||
connect(m_Wrapped, SIGNAL(requestFailed(int,int,QVariant,QString)),
|
||||
@@ -180,6 +188,26 @@ private Q_SLOTS:
|
||||
}
|
||||
}
|
||||
|
||||
void trackingToggled(int modID, QVariant userData, bool tracked)
|
||||
{
|
||||
try {
|
||||
if (m_TrackingToggledHandler.is_none()) {
|
||||
qCritical("no handler connected");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
GILock lock;
|
||||
m_TrackingToggledHandler(modID, userData, tracked);
|
||||
} catch (const boost::python::error_already_set&) {
|
||||
reportPythonError();
|
||||
}
|
||||
} catch (const std::exception &e) {
|
||||
qCritical("failed to report event: %s", e.what());
|
||||
} catch (...) {
|
||||
qCritical("failed to report event");
|
||||
}
|
||||
}
|
||||
|
||||
void requestFailed(int modID, int fileID, QVariant userData, const QString &errorMessage)
|
||||
{
|
||||
try {
|
||||
@@ -197,6 +225,7 @@ private:
|
||||
boost::python::object m_DescriptionAvailableHandler;
|
||||
boost::python::object m_FileInfoHandler;
|
||||
boost::python::object m_EndorsementToggledHandler;
|
||||
boost::python::object m_TrackingToggledHandler;
|
||||
boost::python::object m_FailedHandler;
|
||||
|
||||
};
|
||||
@@ -228,6 +257,10 @@ struct IOrganizerWrapper : MOBase::IOrganizer,
|
||||
{
|
||||
return this->get_override("basePath")();
|
||||
}
|
||||
virtual QString modsPath() const override
|
||||
{
|
||||
return this->get_override("modsPath")();
|
||||
}
|
||||
virtual MOBase::VersionInfo appVersion() const override
|
||||
{
|
||||
return this->get_override("appVersion")();
|
||||
@@ -323,9 +356,11 @@ struct IOrganizerWrapper : MOBase::IOrganizer,
|
||||
virtual HANDLE startApplication(const QString &executable,
|
||||
const QStringList &args = QStringList(),
|
||||
const QString &cwd = "",
|
||||
const QString &profile = "") override
|
||||
const QString &profile = "",
|
||||
const QString &forcedCustomOverwrite = "",
|
||||
bool ignoreCustomOverwrite = false) override
|
||||
{
|
||||
return reinterpret_cast<HANDLE>(this->get_override("startApplication")(executable, args, cwd, profile).as<size_t>());
|
||||
return reinterpret_cast<HANDLE>(this->get_override("startApplication")(executable, args, cwd, profile, forcedCustomOverwrite, ignoreCustomOverwrite).as<size_t>());
|
||||
}
|
||||
virtual bool waitForApplication(HANDLE handle,
|
||||
LPDWORD exitCode = nullptr) const override
|
||||
@@ -387,7 +422,7 @@ struct IModRepositoryBridgeWrapper: MOBase::IModRepositoryBridge, boost::python:
|
||||
virtual void requestFiles(QString gameName, int modID, QVariant userData) { this->get_override("requestFiles")(gameName, modID, userData); }
|
||||
virtual void requestFileInfo(QString gameName, int modID, int fileID, QVariant userData) { this->get_override("requestFileInfo")(gameName, modID, fileID, userData); }
|
||||
virtual void requestDownloadURL(QString gameName, int modID, int fileID, QVariant userData) { this->get_override("requestDownloadURL")(gameName, modID, fileID, userData); }
|
||||
virtual void requestToggleEndorsement(QString gameName, int modID, bool endorse, QVariant userData) { this->get_override("requestToggleEndorsement")(gameName, modID, endorse, userData); }
|
||||
virtual void requestToggleEndorsement(QString gameName, int modID, QString modVersion, bool endorse, QVariant userData) { this->get_override("requestToggleEndorsement")(gameName, modID, endorse, userData); }
|
||||
};
|
||||
|
||||
struct IInstallationManagerWrapper: MOBase::IInstallationManager, boost::python::wrapper<MOBase::IInstallationManager>
|
||||
@@ -408,6 +443,7 @@ struct IModInterfaceWrapper: MOBase::IModInterface, boost::python::wrapper<MOBas
|
||||
virtual void setNexusID(int nexusID) override { this->get_override("setNexusID")(nexusID); }
|
||||
virtual void setInstallationFile(const QString &fileName) override { this->get_override("setInstallationFile")(fileName); }
|
||||
virtual void addNexusCategory(int categoryID) override { this->get_override("addNexusCategory")(categoryID); }
|
||||
virtual void setGameName(const QString &gameName) override { this->get_override("setGameName")(gameName); }
|
||||
virtual bool setName(const QString &name) override { return this->get_override("setName")(name); }
|
||||
virtual bool remove() override { return this->get_override("remove")(); }
|
||||
virtual void addCategory(const QString &categoryName) override { this->get_override("addCategory")(categoryName); }
|
||||
|
||||
Reference in New Issue
Block a user