From 0da4cda3e621dd1cac4a6487a60fc768ffe40784 Mon Sep 17 00:00:00 2001 From: panzergame Date: Fri, 30 Nov 2018 21:02:22 +0100 Subject: [PATCH] UPBGE: Allow KX_LibLoadStatus.onFinish to call python method. (#896) Previously KX_LibLoadStatus finish callback was only permitted to be python function not method. To allow calling a method, work from EXP_RunPythonCallBackList is reused and the calling of a python function is moved into new function EXP_RunPythonCallback. This function is in charge of checking that the python object is callable and construct a tuple of the arguments. EXP_RunPythonCallback is now called into KX_LibLoadStatus::RunFinishCallback. --- .../Expressions/EXP_PythonCallBack.h | 8 +++++ .../Expressions/intern/PythonCallBack.cpp | 30 ++++++++----------- source/gameengine/Ketsji/KX_LibLoadStatus.cpp | 12 ++++---- 3 files changed, 27 insertions(+), 23 deletions(-) diff --git a/source/gameengine/Expressions/EXP_PythonCallBack.h b/source/gameengine/Expressions/EXP_PythonCallBack.h index 04e5f75b3fc8..f79295c3e6f9 100644 --- a/source/gameengine/Expressions/EXP_PythonCallBack.h +++ b/source/gameengine/Expressions/EXP_PythonCallBack.h @@ -29,6 +29,14 @@ #include "EXP_Python.h" +/** Check and call a python callable object. + * \param value Callable object candidate. + * \param arglist The first item in the tuple to execute callbacks (can be nullptr for no arguments). + * \param minargcount The minimum of arguments possible. + * \param maxargcount The maximum of arguments possible. + */ +void EXP_RunPythonCallback(PyObject *value, PyObject **arglist, unsigned int minargcount, unsigned int maxargcount); + /** Execute each functions with at least one argument * \param functionlist The python list which contains callbacks. * \param arglist The first item in the tuple to execute callbacks (can be nullptr for no arguments). diff --git a/source/gameengine/Expressions/intern/PythonCallBack.cpp b/source/gameengine/Expressions/intern/PythonCallBack.cpp index e00d56d7a6ce..8d0f87fcbe6a 100644 --- a/source/gameengine/Expressions/intern/PythonCallBack.cpp +++ b/source/gameengine/Expressions/intern/PythonCallBack.cpp @@ -84,29 +84,20 @@ static PyObject *CreatePythonTuple(unsigned int argcount, PyObject **arglist) return tuple; } -void EXP_RunPythonCallBackList(PyObject *functionlist, PyObject **arglist, unsigned int minargcount, unsigned int maxargcount) +void EXP_RunPythonCallback(PyObject *value, PyObject **arglist, unsigned int minargcount, unsigned int maxargcount) { - unsigned int size = PyList_Size(functionlist); - PyObject **argTuples = (PyObject **)BLI_array_alloca(argTuples, maxargcount - minargcount + 1); - memset(argTuples, 0, sizeof(PyObject *) * (maxargcount - minargcount + 1)); - - for (unsigned int i = 0; i < size; ++i) { unsigned int funcargcount = 0; - PyObject *item = PyList_GET_ITEM(functionlist, i); - PyObject *func = CheckPythonFunction(item, minargcount, maxargcount, funcargcount); - // This item fails the check. + PyObject *func = CheckPythonFunction(value, minargcount, maxargcount, funcargcount); + // This value fails the check. if (!func) { PyErr_Print(); PyErr_Clear(); - continue; + return; } // Get correct argument tuple. - PyObject *tuple = argTuples[funcargcount - minargcount]; - if (!tuple) { - argTuples[funcargcount - minargcount] = tuple = CreatePythonTuple(funcargcount, arglist); - } + PyObject *tuple = CreatePythonTuple(funcargcount, arglist); PyObject *ret = PyObject_Call(func, tuple, nullptr); if (!ret) { // If ret is nullptr this seems that the function doesn't work. @@ -116,9 +107,14 @@ void EXP_RunPythonCallBackList(PyObject *functionlist, PyObject **arglist, unsig else { Py_DECREF(ret); } - } +} + +void EXP_RunPythonCallBackList(PyObject *functionlist, PyObject **arglist, unsigned int minargcount, unsigned int maxargcount) +{ + const unsigned int size = PyList_Size(functionlist); - for (unsigned int i = 0; i <= (maxargcount - minargcount); ++i) { - Py_XDECREF(argTuples[i]); + for (unsigned int i = 0; i < size; ++i) { + PyObject *item = PyList_GET_ITEM(functionlist, i); + EXP_RunPythonCallback(item, arglist, minargcount, maxargcount); } } diff --git a/source/gameengine/Ketsji/KX_LibLoadStatus.cpp b/source/gameengine/Ketsji/KX_LibLoadStatus.cpp index 73b097aeff35..dca8f19ff905 100644 --- a/source/gameengine/Ketsji/KX_LibLoadStatus.cpp +++ b/source/gameengine/Ketsji/KX_LibLoadStatus.cpp @@ -25,6 +25,9 @@ */ #include "KX_LibLoadStatus.h" + +#include "EXP_PythonCallBack.h" + #include "PIL_time.h" KX_LibLoadStatus::KX_LibLoadStatus(BL_Converter *converter, KX_KetsjiEngine *engine, KX_Scene *merge_scene, const std::string& path) @@ -57,14 +60,11 @@ void KX_LibLoadStatus::RunFinishCallback() { #ifdef WITH_PYTHON if (m_finish_cb) { - PyObject *args = Py_BuildValue("(O)", GetProxy()); + PyObject *args[] = {GetProxy()}; - if (!PyObject_Call(m_finish_cb, args, nullptr)) { - PyErr_Print(); - PyErr_Clear(); - } + EXP_RunPythonCallback(m_finish_cb, args, 0, 1); - Py_DECREF(args); + Py_DECREF(args[0]); } #endif }