Skip to content

Commit

Permalink
Python plugin: Support custom Tileset formats (#3857)
Browse files Browse the repository at this point in the history
Extended the Python plugin to support custom tileset exporters and 
readers written in Python. One Python script can implement both a map
and a tileset format (though only one of each).

Also fixed Python include path not recognized in Qt Creator (required 
setting cpp.includePaths instead of relying on cpp.cxxFlags).

Fixes #1865

Co-authored-by: Thorbjørn Lindeijer <[email protected]>
  • Loading branch information
DrDub and bjorn authored May 24, 2024
1 parent c82539e commit f6d6d4e
Show file tree
Hide file tree
Showing 8 changed files with 512 additions and 126 deletions.
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
* Godot 4 plugin: Use Godot 4.2 tile transformation flags (by Rick Yorgason, #3895)
* Godot 4 plugin: Fixed positioning of tile collision shapes (by Ryan Petrie, #3862)
* GameMaker 2 plugin: Fixed positioning of objects on isometric maps
* Python plugin: Added support for implementing tileset formats (with Pablo Duboue, #3857)
* Python plugin: Raised minimum Python version to 3.8
* tmxrasterizer: Added --hide-object and --show-object arguments (by Lars Luz, #3819)
* tmxrasterizer: Added --frames and --frame-duration arguments to export animated maps as multiple images (#3868)
Expand Down
10 changes: 10 additions & 0 deletions docs/manual/python.rst
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,16 @@ above script.

This example does not support the use of group layers.

.. raw:: html

<div class="new">New in Tiled 1.11</div>

Tileset Plugins
---------------

To write tileset plugins, extend your class from ``tiled.TilesetPlugin``
instead of ``tiled.Plugin``.

Debugging Your Script
---------------------

Expand Down
4 changes: 3 additions & 1 deletion src/plugins/python/python.qbs
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,10 @@ TiledPlugin {

Properties {
condition: pkgConfigPython3.found
cpp.cxxFlags: outer.concat(pkgConfigPython3.cflags)
cpp.cxxFlags: outer.concat(pkgConfigPython3.compilerFlags)
cpp.defines: pkgConfigPython3.defines
cpp.dynamicLibraries: pkgConfigPython3.libraries
cpp.includePaths: pkgConfigPython3.includePaths
cpp.libraryPaths: pkgConfigPython3.libraryPaths
cpp.linkerFlags: pkgConfigPython3.linkerFlags
}
Expand Down
143 changes: 143 additions & 0 deletions src/plugins/python/pythonbind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,17 @@ typedef struct {

extern PyTypeObject PyPythonPythonScript_Type;


typedef struct {
PyObject_HEAD
Python::PythonTilesetScript *obj;
PyObject *inst_dict;
PyBindGenWrapperFlags flags:8;
} PyPythonPythonTilesetScript;


extern PyTypeObject PyPythonPythonTilesetScript_Type;

/* --- forward declarations --- */


Expand Down Expand Up @@ -7996,6 +8007,102 @@ PyTypeObject PyPythonPythonScript_Type = {
};




static int
_wrap_PyPythonPythonTilesetScript__tp_init(void)
{
PyErr_SetString(PyExc_TypeError, "class 'PythonTilesetScript' cannot be constructed ()");
return -1;
}

static PyMethodDef PyPythonPythonTilesetScript_methods[] = {
{NULL, NULL, 0, NULL}
};

static void
PyPythonPythonTilesetScript__tp_clear(PyPythonPythonTilesetScript *self)
{
Py_CLEAR(self->inst_dict);
Python::PythonTilesetScript *tmp = self->obj;
self->obj = NULL;
if (!(self->flags&PYBINDGEN_WRAPPER_FLAG_OBJECT_NOT_OWNED)) {
delete tmp;
}
}


static int
PyPythonPythonTilesetScript__tp_traverse(PyPythonPythonTilesetScript *self, visitproc visit, void *arg)
{
Py_VISIT(self->inst_dict);

return 0;
}


static void
_wrap_PyPythonPythonTilesetScript__tp_dealloc(PyPythonPythonTilesetScript *self)
{
PyPythonPythonTilesetScript__tp_clear(self);
Py_TYPE(self)->tp_free((PyObject*)self);
}

PyTypeObject PyPythonPythonTilesetScript_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
(char *) "tiled.PythonTilesetScript", /* tp_name */
sizeof(PyPythonPythonTilesetScript), /* tp_basicsize */
0, /* tp_itemsize */
/* methods */
(destructor)_wrap_PyPythonPythonTilesetScript__tp_dealloc, /* tp_dealloc */
(printfunc)0, /* tp_print */
(getattrfunc)NULL, /* tp_getattr */
(setattrfunc)NULL, /* tp_setattr */
#if PY_MAJOR_VERSION >= 3
NULL,
#else
(cmpfunc)NULL, /* tp_compare */
#endif
(reprfunc)NULL, /* tp_repr */
(PyNumberMethods*)NULL, /* tp_as_number */
(PySequenceMethods*)NULL, /* tp_as_sequence */
(PyMappingMethods*)NULL, /* tp_as_mapping */
(hashfunc)NULL, /* tp_hash */
(ternaryfunc)NULL, /* tp_call */
(reprfunc)NULL, /* tp_str */
(getattrofunc)NULL, /* tp_getattro */
(setattrofunc)NULL, /* tp_setattro */
(PyBufferProcs*)NULL, /* tp_as_buffer */
Py_TPFLAGS_BASETYPE|Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_GC, /* tp_flags */
"", /* Documentation string */
(traverseproc)PyPythonPythonTilesetScript__tp_traverse, /* tp_traverse */
(inquiry)PyPythonPythonTilesetScript__tp_clear, /* tp_clear */
(richcmpfunc)NULL, /* tp_richcompare */
0, /* tp_weaklistoffset */
(getiterfunc)NULL, /* tp_iter */
(iternextfunc)NULL, /* tp_iternext */
(struct PyMethodDef*)PyPythonPythonTilesetScript_methods, /* tp_methods */
(struct PyMemberDef*)0, /* tp_members */
0, /* tp_getset */
NULL, /* tp_base */
NULL, /* tp_dict */
(descrgetfunc)NULL, /* tp_descr_get */
(descrsetfunc)NULL, /* tp_descr_set */
offsetof(PyPythonPythonTilesetScript, inst_dict), /* tp_dictoffset */
(initproc)_wrap_PyPythonPythonTilesetScript__tp_init, /* tp_init */
(allocfunc)PyType_GenericAlloc, /* tp_alloc */
(newfunc)PyType_GenericNew, /* tp_new */
(freefunc)0, /* tp_free */
(inquiry)NULL, /* tp_is_gc */
NULL, /* tp_bases */
NULL, /* tp_mro */
NULL, /* tp_cache */
NULL, /* tp_subclasses */
NULL, /* tp_weaklist */
(destructor) NULL /* tp_del */
};


#if PY_VERSION_HEX >= 0x03000000
static struct PyModuleDef tiled_moduledef = {
PyModuleDef_HEAD_INIT,
Expand Down Expand Up @@ -8041,6 +8148,11 @@ MOD_INIT(tiled)
return MOD_ERROR;
}
PyModule_AddObject(m, (char *) "Plugin", (PyObject *) &PyPythonPythonScript_Type);
/* Register the 'Python::PythonTilesetScript' class */
if (PyType_Ready(&PyPythonPythonTilesetScript_Type)) {
return MOD_ERROR;
}
PyModule_AddObject(m, (char *) "TilesetPlugin", (PyObject *) &PyPythonPythonTilesetScript_Type);
submodule = inittiled_qt();
if (submodule == NULL) {
return MOD_ERROR;
Expand Down Expand Up @@ -8083,6 +8195,37 @@ int _wrap_convert_py2c__Tiled__Map___star__(PyObject *value, Tiled::Map * *addre
return 1;
}

int _wrap_convert_py2c__Tiled__SharedTileset___star__(PyObject *value, Tiled::SharedTileset * *address)
{
PyObject *py_retval;
PyTiledSharedTileset *tmp_SharedTileset;

py_retval = Py_BuildValue((char *) "(O)", value);
if (!PyArg_ParseTuple(py_retval, (char *) "O!", &PyTiledSharedTileset_Type, &tmp_SharedTileset)) {
Py_DECREF(py_retval);
return 0;
}
*address = new Tiled::SharedTileset(*tmp_SharedTileset->obj);
Py_DECREF(py_retval);
return 1;
}

PyObject* _wrap_convert_c2py__Tiled__Tileset_const(Tiled::Tileset const *cvalue)
{
PyObject *py_retval;
PyTiledTileset *py_Tileset;

if (!cvalue) {
Py_INCREF(Py_None);
return Py_None;
}
py_Tileset = PyObject_New(PyTiledTileset, &PyTiledTileset_Type);
py_Tileset->obj = (Tiled::Tileset *) cvalue;
py_Tileset->flags = PYBINDGEN_WRAPPER_FLAG_OBJECT_NOT_OWNED;
py_retval = Py_BuildValue((char *) "N", py_Tileset);
return py_retval;
}


PyObject* _wrap_convert_c2py__Tiled__Map_const___star__(Tiled::Map const * *cvalue)
{
Expand Down
Loading

0 comments on commit f6d6d4e

Please sign in to comment.