From a19781b56a87b68309e63c88e4eb68d22523267d Mon Sep 17 00:00:00 2001 From: John McCardle Date: Sun, 7 Apr 2024 15:21:17 -0400 Subject: [PATCH] Many hours of pain & research behind this small commit. Safe object building by not messing with types before interpreter is fully initialized --- src/McRFPy_API.cpp | 23 +++++++++++++++++++--- src/McRFPy_API.h | 1 + src/PyTexture.cpp | 47 +++++++++++++++++++++++++++++++++++++++++++-- src/PyTexture.h | 5 ++++- src/scripts/game.py | 4 ++++ 5 files changed, 74 insertions(+), 6 deletions(-) diff --git a/src/McRFPy_API.cpp b/src/McRFPy_API.cpp index a4b419d..a1aa1d4 100644 --- a/src/McRFPy_API.cpp +++ b/src/McRFPy_API.cpp @@ -11,6 +11,8 @@ sf::Sound McRFPy_API::sfx; std::shared_ptr McRFPy_API::default_font; std::shared_ptr McRFPy_API::default_texture; +PyObject* McRFPy_API::mcrf_module; + static PyMethodDef mcrfpyMethods[] = { {"registerPyAction", McRFPy_API::_registerPyAction, METH_VARARGS, @@ -82,7 +84,7 @@ PyObject* PyInit_mcrfpy() auto t = pytypes[i]; while (t != nullptr) { - PyType_Ready(t); + /*std::cout << */ PyType_Ready(t); /*<< std::endl; */ PyModule_AddType(m, t); t = pytypes[i++]; } @@ -90,8 +92,11 @@ PyObject* PyInit_mcrfpy() // Add default_font and default_texture to module McRFPy_API::default_font = std::make_shared("assets/JetbrainsMono.ttf"); McRFPy_API::default_texture = std::make_shared("assets/kenney_tinydungeon.png", 16, 16); - PyModule_AddObject(m, "default_font", McRFPy_API::default_font->pyObject()); - PyModule_AddObject(m, "default_texture", McRFPy_API::default_texture->pyObject()); + //PyModule_AddObject(m, "default_font", McRFPy_API::default_font->pyObject()); + //PyModule_AddObject(m, "default_texture", McRFPy_API::default_texture->pyObject()); + PyModule_AddObject(m, "default_font", Py_None); + PyModule_AddObject(m, "default_texture", Py_None); + //McRFPy_API::mcrf_module = m; return m; } @@ -143,6 +148,9 @@ PyStatus init_python(const char *program_name) #endif status = Py_InitializeFromConfig(&config); + + PyConfig_Clear(&config); + return status; } @@ -172,6 +180,15 @@ void McRFPy_API::api_init() { //texture_sprite_count = texture_width * texture_height; //texture.setSmooth(false); + // Add default_font and default_texture to module + McRFPy_API::mcrf_module = PyImport_ImportModule("mcrfpy"); + std::cout << PyUnicode_AsUTF8(PyObject_Repr(McRFPy_API::mcrf_module)) << std::endl; + + //PyModule_AddObject(McRFPy_API::mcrf_module, "default_font", McRFPy_API::default_font->pyObject()); + PyObject_SetAttrString(McRFPy_API::mcrf_module, "default_font", McRFPy_API::default_font->pyObject()); + //PyModule_AddObject(McRFPy_API::mcrf_module, "default_texture", McRFPy_API::default_texture->pyObject()); + PyObject_SetAttrString(McRFPy_API::mcrf_module, "default_texture", McRFPy_API::default_texture->pyObject()); + //sprite.setTexture(texture); //sprite.setScale(sf::Vector2f(4.0f, 4.0f)); //setSpriteTexture(0); diff --git a/src/McRFPy_API.h b/src/McRFPy_API.h index a04cd11..08d034e 100644 --- a/src/McRFPy_API.h +++ b/src/McRFPy_API.h @@ -19,6 +19,7 @@ private: public: + static PyObject* mcrf_module; static std::shared_ptr default_font; static std::shared_ptr default_texture; //inline static sf::Sprite sprite; diff --git a/src/PyTexture.cpp b/src/PyTexture.cpp index 7ce1b7b..8f8d4df 100644 --- a/src/PyTexture.cpp +++ b/src/PyTexture.cpp @@ -1,5 +1,5 @@ #include "PyTexture.h" - +#include "McRFPy_API.h" PyTexture::PyTexture(std::string filename, int sprite_w, int sprite_h) : source(filename), sprite_width(sprite_w), sprite_height(sprite_h) @@ -28,9 +28,36 @@ sf::Sprite PyTexture::sprite(int index, sf::Vector2f pos, sf::Vector2f s) PyObject* PyTexture::pyObject() { - PyObject* obj = PyType_GenericAlloc(&mcrfpydef::PyTextureType, 0); + // method 1: works but with type weirdness + //PyObject* obj = PyType_GenericAlloc(&mcrfpydef::PyTextureType, 0); + //Py_SET_TYPE(obj, &mcrfpydef::PyTextureType); + + // method 2: does not work (segfault on use of the mcrfpy.Texture object) + //PyObject* obj = PyTexture::pynew(&mcrfpydef::PyTextureType, Py_None, Py_None); + + // method 3: does not work (segfault on use of the mcrfpy.Texture object) + std::cout << "Find type" << std::endl; + auto type = (PyTypeObject*)PyObject_GetAttrString(McRFPy_API::mcrf_module, "Texture"); + //auto type = obj->ob_type; + //auto type = &mcrfpydef::PyTextureType; + //std::cout << "assigned value 0x" << std::hex << reinterpret_cast(type) << std::endl; + //std::cout << "Found PyTextureType: " << PyUnicode_AsUTF8(PyObject_Repr((PyObject*)type)) << std::endl; + //std::cout << "PyTextureType metatype: " << PyUnicode_AsUTF8(PyObject_Repr((PyObject_Type((PyObject*)type)))) << std::endl; + //std::cout << "tp_alloc: 0x" << std::hex << reinterpret_cast (type->tp_alloc) << std::endl << + // "tp_new: 0x" << std::hex << reinterpret_cast(type->tp_new) << std::endl; + //PyObject* obj = ((PyTypeObject*)type)->tp_new((PyTypeObject*)type, Py_None, Py_None); + PyObject* obj = PyTexture::pynew(type, Py_None, Py_None); + //Py_SET_TYPE(obj, type); + + // method 4: call the type object? + + std::cout << "Instantiated" << std::endl; + //Py_SET_TYPE(obj, &mcrfpydef::PyTextureType); + + //PyObject_CallFunction(&mcrfpydef::PyTextureType, try { ((PyTextureObject*)obj)->data = shared_from_this(); + std::cout << "Sideloaded texture: " << PyUnicode_AsUTF8(PyObject_Repr(obj)) << std::endl; } catch (std::bad_weak_ptr& e) { @@ -40,6 +67,22 @@ PyObject* PyTexture::pyObject() return obj; } +PyObject* PyTexture::repr(PyObject* obj) +{ + PyTextureObject* self = (PyTextureObject*)obj; + std::ostringstream ss; + if (!self->data) + { + ss << ""; + std::string repr_str = ss.str(); + return PyUnicode_DecodeUTF8(repr_str.c_str(), repr_str.size(), "replace"); + } + auto& ptex = *(self->data); + ss << ""; + std::string repr_str = ss.str(); + return PyUnicode_DecodeUTF8(repr_str.c_str(), repr_str.size(), "replace"); +} + Py_hash_t PyTexture::hash(PyObject* obj) { auto self = (PyTextureObject*)obj; diff --git a/src/PyTexture.h b/src/PyTexture.h index eea1838..df7b3c7 100644 --- a/src/PyTexture.h +++ b/src/PyTexture.h @@ -21,6 +21,7 @@ public: sf::Sprite sprite(int index, sf::Vector2f pos = sf::Vector2f(0, 0), sf::Vector2f s = sf::Vector2f(1.0, 1.0)); PyObject* pyObject(); + static PyObject* repr(PyObject*); static Py_hash_t hash(PyObject*); static int init(PyTextureObject*, PyObject*, PyObject*); static PyObject* pynew(PyTypeObject* type, PyObject* args=NULL, PyObject* kwds=NULL); @@ -31,10 +32,12 @@ namespace mcrfpydef { .tp_name = "mcrfpy.Texture", .tp_basicsize = sizeof(PyTextureObject), .tp_itemsize = 0, + .tp_repr = PyTexture::repr, .tp_hash = PyTexture::hash, .tp_flags = Py_TPFLAGS_DEFAULT, .tp_doc = PyDoc_STR("SFML Texture Object"), + //.tp_base = &PyBaseObject_Type, .tp_init = (initproc)PyTexture::init, - .tp_new = PyTexture::pynew, + .tp_new = PyType_GenericNew, //PyTexture::pynew, }; } diff --git a/src/scripts/game.py b/src/scripts/game.py index 8e28bc3..87eaf5a 100644 --- a/src/scripts/game.py +++ b/src/scripts/game.py @@ -2,6 +2,10 @@ import mcrfpy font = mcrfpy.Font("assets/JetbrainsMono.ttf") texture = mcrfpy.Texture("assets/kenney_tinydungeon.png", 16, 16) +print("[game.py] Default texture:") +print(mcrfpy.default_texture) +print(type(mcrfpy.default_texture)) + # build test widgets mcrfpy.createScene("pytest")