From 972768eb265d2a95796d63400c10d9e8364076cb Mon Sep 17 00:00:00 2001 From: John McCardle Date: Tue, 12 Mar 2024 21:02:48 -0400 Subject: [PATCH] inital PyCallable work; isolate very well behaved usage of PyObject references behind RAII --- src/GameEngine.cpp | 6 ++--- src/GameEngine.h | 4 +++- src/McRFPy_API.h | 6 ----- src/PyCallable.cpp | 57 ++++++++++++++++++++++++++++++++++++++++++++++ src/PyCallable.h | 26 +++++++++++++++++++++ 5 files changed, 89 insertions(+), 10 deletions(-) create mode 100644 src/PyCallable.cpp create mode 100644 src/PyCallable.h diff --git a/src/GameEngine.cpp b/src/GameEngine.cpp index 554eabf..beb2b31 100644 --- a/src/GameEngine.cpp +++ b/src/GameEngine.cpp @@ -75,7 +75,7 @@ void GameEngine::manageTimer(std::string name, PyObject* target, int interval) { if (target == NULL || target == Py_None) // delete { - Py_DECREF(timers[name].target); + //Py_DECREF(timers[name].target); timers.erase(it); return; } @@ -85,7 +85,7 @@ void GameEngine::manageTimer(std::string name, PyObject* target, int interval) std::cout << "Refusing to initialize timer to None. It's not an error, it's just pointless." << std::endl; return; } - timers[name] = Timer(target, interval, runtime.getElapsedTime().asMilliseconds()); + timers[name] = std::make_shared(target, interval, runtime.getElapsedTime().asMilliseconds()); Py_INCREF(target); } @@ -94,7 +94,7 @@ void GameEngine::testTimers() int now = runtime.getElapsedTime().asMilliseconds(); for (auto& [name, timer]: timers) { - timer.test(now); + timer->test(now); } } diff --git a/src/GameEngine.h b/src/GameEngine.h index 138e74d..8d688b3 100644 --- a/src/GameEngine.h +++ b/src/GameEngine.h @@ -5,6 +5,7 @@ #include "McRFPy_API.h" #include "IndexTexture.h" #include "Timer.h" +#include "PyCallable.h" class GameEngine { @@ -20,7 +21,8 @@ class GameEngine std::string window_title; sf::Clock runtime; - std::map timers; + //std::map timers; + std::map> timers; void testTimers(); public: diff --git a/src/McRFPy_API.h b/src/McRFPy_API.h index 588f897..025706b 100644 --- a/src/McRFPy_API.h +++ b/src/McRFPy_API.h @@ -12,12 +12,6 @@ private: texture_width = 12, texture_height = 11, // w & h sprite/frame count texture_sprite_count = 11 * 12; // t_width * t_height, minus blanks? - // TODO: this is wrong, load resources @ GameEngineSprite sprite; - // sf::Texture texture; - - //std::vector mcrfpyMethodsVector; - //static PyObject* PyInit_mcrfpy(); - McRFPy_API(); public: diff --git a/src/PyCallable.cpp b/src/PyCallable.cpp new file mode 100644 index 0000000..5e16884 --- /dev/null +++ b/src/PyCallable.cpp @@ -0,0 +1,57 @@ +#include "PyCallable.h" + +PyCallable::PyCallable(PyObject* _target) +{ + target = Py_XNewRef(_target); +} + +PyCallable::~PyCallable() +{ + if (target) + Py_DECREF(target); +} + +PyObject* PyCallable::call(PyObject* args, PyObject* kwargs) +{ + return PyObject_Call(target, args, kwargs); +} + +PyTimerCallable::PyTimerCallable(PyObject* _target, int _interval, int now) +: PyCallable(_target), interval(_interval), last_ran(now) +{} + +PyTimerCallable::PyTimerCallable() +: PyCallable(Py_None), interval(0), last_ran(0) +{} + +bool PyTimerCallable::hasElapsed(int now) +{ + return now >= last_ran + interval; +} + +void PyTimerCallable::call(int now) +{ + PyObject* args = Py_BuildValue("(i)", now); + PyObject* retval = PyCallable::call(args, NULL); + if (!retval) + { + std::cout << "timer has raised an exception. It's going to STDERR and being dropped:" << std::endl; + PyErr_Print(); + PyErr_Clear(); + } else if (retval != Py_None) + { + std::cout << "timer returned a non-None value. It's not an error, it's just not being saved or used." << std::endl; + std::cout << PyUnicode_AsUTF8(PyObject_Repr(retval)) << std::endl; + } +} + +bool PyTimerCallable::test(int now) +{ + if(hasElapsed(now)) + { + call(now); + last_ran = now; + return true; + } + return false; +} diff --git a/src/PyCallable.h b/src/PyCallable.h new file mode 100644 index 0000000..fd9257d --- /dev/null +++ b/src/PyCallable.h @@ -0,0 +1,26 @@ +#pragma once +#include "Common.h" +#include "Python.h" + +class PyCallable +{ +private: + PyObject* target; +protected: + PyCallable(PyObject*); + ~PyCallable(); + PyObject* call(PyObject*, PyObject*); +}; + +class PyTimerCallable: public PyCallable +{ +private: + int interval; + int last_ran; + void call(int); +public: + bool hasElapsed(int); + bool test(int); + PyTimerCallable(PyObject*, int, int); + PyTimerCallable(); +};