timer fixes: timers managed by engine can run in the background. Closes #180

This commit is contained in:
John McCardle 2026-01-06 20:13:51 -05:00
commit b0b17f4633
4 changed files with 57 additions and 22 deletions

View file

@ -911,6 +911,32 @@ PyObject* McRFPy_API::_setScene(PyObject* self, PyObject* args) {
return Py_None;
}
// #180: Create a Python wrapper for an existing C++ Timer (for orphaned timers)
static PyObject* createTimerWrapper(std::shared_ptr<Timer> timer)
{
// Allocate new PyTimerObject
PyTypeObject* type = &mcrfpydef::PyTimerType;
PyTimerObject* obj = (PyTimerObject*)type->tp_alloc(type, 0);
if (!obj) return nullptr;
// Initialize - use placement new for std::string
new(&obj->name) std::string(timer->name);
obj->data = timer; // Share the existing C++ Timer
obj->weakreflist = nullptr;
// Register in cache for future lookups
if (timer->serial_number == 0) {
timer->serial_number = PythonObjectCache::getInstance().assignSerial();
}
PyObject* weakref = PyWeakref_NewRef((PyObject*)obj, NULL);
if (weakref) {
PythonObjectCache::getInstance().registerObject(timer->serial_number, weakref);
Py_DECREF(weakref);
}
return (PyObject*)obj;
}
// #173: Get all timers as a tuple of Python Timer objects
PyObject* McRFPy_API::api_get_timers()
{
@ -918,15 +944,25 @@ PyObject* McRFPy_API::api_get_timers()
return PyTuple_New(0);
}
// Count timers that have Python wrappers
std::vector<PyObject*> timer_objs;
for (auto& pair : game->timers) {
auto& timer = pair.second;
if (timer && timer->serial_number != 0) {
PyObject* timer_obj = PythonObjectCache::getInstance().lookup(timer->serial_number);
if (timer_obj && timer_obj != Py_None) {
timer_objs.push_back(timer_obj);
}
if (!timer) continue;
PyObject* timer_obj = nullptr;
// Try to find existing Python wrapper
if (timer->serial_number != 0) {
timer_obj = PythonObjectCache::getInstance().lookup(timer->serial_number);
}
// #180: If no wrapper exists (orphaned timer), create a new one
if (!timer_obj || timer_obj == Py_None) {
timer_obj = createTimerWrapper(timer);
}
if (timer_obj && timer_obj != Py_None) {
timer_objs.push_back(timer_obj);
}
}
@ -934,7 +970,8 @@ PyObject* McRFPy_API::api_get_timers()
if (!tuple) return NULL;
for (Py_ssize_t i = 0; i < static_cast<Py_ssize_t>(timer_objs.size()); i++) {
Py_INCREF(timer_objs[i]);
// timer_objs already has a reference from lookup() or createTimerWrapper()
// PyTuple_SET_ITEM steals that reference, so no additional INCREF needed
PyTuple_SET_ITEM(tuple, i, timer_objs[i]);
}