Skip to content

Commit

Permalink
Addressed some issues
Browse files Browse the repository at this point in the history
* Un-duplicated setPythonClass function

* Removed unused pluginmanager.h include

* Fixed cleanup code related to reloading plugins in case a plugin
  changes from defining a map format to a tileset format or vice versa.

* Allow a Python plugin to include both a map and a tileset format
  (though only one of each).
  • Loading branch information
bjorn committed Apr 19, 2024
1 parent fc6b3c3 commit 8499992
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 90 deletions.
2 changes: 1 addition & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,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 (#3857)
* 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)
* tmxrasterizer: Fixed --hide/show-layer to work on group layers (#3899)
Expand All @@ -33,7 +34,6 @@
* Fixed alignment of shortcuts in action search
* AppImage: Fixed ability to open paths with spaces from the CLI (#3914)
* AppImage: Updated to Sentry 0.6.7
* Python plugin: Added support for implementing tileset formats (#3857)

### Tiled 1.10.2 (4 August 2023)

Expand Down
4 changes: 4 additions & 0 deletions docs/manual/python.rst
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,10 @@ 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
---------------

Expand Down
116 changes: 46 additions & 70 deletions src/plugins/python/pythonplugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
*/

#include "pythonplugin.h"
#include "pluginmanager.h"

#include "logginginterface.h"
#include "map.h"
Expand Down Expand Up @@ -70,12 +69,12 @@ PythonPlugin::~PythonPlugin()
{
for (const ScriptEntry &script : mScripts) {
Py_DECREF(script.module);
if (script.mapFormat) {

if (script.mapFormat)
Py_DECREF(script.mapFormat->pythonClass());
}
if (script.tilesetFormat) {

if (script.tilesetFormat)
Py_DECREF(script.tilesetFormat->pythonClass());
}
}

Py_XDECREF(mPluginClass);
Expand Down Expand Up @@ -207,15 +206,6 @@ void PythonPlugin::reloadModules()
PyErr_Print();
PyErr_Clear();
}

if (script.mapFormat) {
removeObject(script.mapFormat);
delete script.mapFormat;
}
if (script.tilesetFormat) {
removeObject(script.tilesetFormat);
delete script.tilesetFormat;
}
}
}

Expand All @@ -231,6 +221,11 @@ PyObject *PythonPlugin::findPluginSubclass(PyObject *module, PyObject *pluginCla
PyObject *dir = PyObject_Dir(module);
PyObject *result = nullptr;

if (!dir) {
handleError();
return result;
}

for (int i = 0; i < PyList_Size(dir); i++) {
PyObject *value = PyObject_GetAttr(module, PyList_GetItem(dir, i));

Expand Down Expand Up @@ -269,38 +264,46 @@ bool PythonPlugin::loadOrReloadModule(ScriptEntry &script)
script.module = PyImport_ImportModule(name.constData());
}

if (!script.module)
return false;
PyObject *pluginClass = nullptr;
PyObject *tilesetPluginClass = nullptr;

PyObject *pluginClass = findPluginSubclass(script.module, mTilesetPluginClass);
if (script.module) {
pluginClass = findPluginSubclass(script.module, mPluginClass);
tilesetPluginClass = findPluginSubclass(script.module, mTilesetPluginClass);
}

if (pluginClass) {
if (script.tilesetFormat) {
script.tilesetFormat->setPythonClass(pluginClass);
} else {
PySys_WriteStdout("---- Tileset plugin\n");
script.tilesetFormat = new PythonTilesetFormat(name, pluginClass, this);
addObject(script.tilesetFormat);
}
} else {
PyObject *module = PyImport_ImportModule(name.constData());
Py_DECREF(script.module);
script.module = module;
pluginClass = findPluginSubclass(script.module, mPluginClass);
if (!pluginClass) {
PySys_WriteStderr("No extension of tiled.Plugin or tiled.TilesetPlugin defined in "
"script: %s\n", name.constData());
return false;
}

if (script.mapFormat) {
script.mapFormat->setPythonClass(pluginClass);
} else {
PySys_WriteStdout("---- Map plugin\n");
script.mapFormat = new PythonMapFormat(name, pluginClass, this);
addObject(script.mapFormat);
}
if (script.mapFormat) {
script.mapFormat->setPythonClass(pluginClass);
} else {
PySys_WriteStdout("---- Map plugin\n");
script.mapFormat = new PythonMapFormat(name, pluginClass, this);
addObject(script.mapFormat);
}
} else if (script.mapFormat) {
removeObject(script.mapFormat);
delete script.mapFormat;
}

if (tilesetPluginClass) {
if (script.tilesetFormat) {
script.tilesetFormat->setPythonClass(tilesetPluginClass);
} else {
PySys_WriteStdout("---- Tileset plugin\n");
script.tilesetFormat = new PythonTilesetFormat(name, tilesetPluginClass, this);
addObject(script.tilesetFormat);
}
} else if (script.tilesetFormat) {
removeObject(script.tilesetFormat);
delete script.tilesetFormat;
}

if (!pluginClass && !tilesetPluginClass) {
PySys_WriteStderr("No extension of tiled.Plugin or tiled.TilesetPlugin defined in "
"script: %s\n", name.constData());
return false;
}

return true;
}

Expand All @@ -318,7 +321,6 @@ PythonMapFormat::PythonMapFormat(const QString &scriptFile,
: MapFormat(parent)
, PythonFormat(scriptFile, class_)
{
setPythonClass(class_); // again as super class has no virtual dispatch in constructor
}

std::unique_ptr<Tiled::Map> PythonMapFormat::read(const QString &fileName)
Expand Down Expand Up @@ -463,12 +465,8 @@ QString PythonFormat::_errorString() const
void PythonFormat::setPythonClass(PyObject *class_)
{
mClass = class_;
}

void PythonMapFormat::setPythonClass(PyObject *class_)
{
PythonFormat::setPythonClass(class_);
mCapabilities = NoCapability;
mCapabilities = Tiled::FileFormat::NoCapability;
// @classmethod nameFilter(cls)
if (PyObject_HasAttrString(mClass, "nameFilter")) {
// @classmethod write(cls, map, filename)
Expand All @@ -492,7 +490,6 @@ PythonTilesetFormat::PythonTilesetFormat(const QString &scriptFile,
: TilesetFormat(parent)
, PythonFormat(scriptFile, class_)
{
setPythonClass(class_); // again as super class has no virtual dispatch in constructor
}

Tiled::SharedTileset PythonTilesetFormat::read(const QString &fileName)
Expand Down Expand Up @@ -552,25 +549,4 @@ bool PythonTilesetFormat::write(const Tiled::Tileset &tileset, const QString &fi
return false;
}


void PythonTilesetFormat::setPythonClass(PyObject *class_)
{
PythonFormat::setPythonClass(class_);
mCapabilities = NoCapability;
// @classmethod nameFilter(cls)
if (PyObject_HasAttrString(mClass, "nameFilter")) {
// @classmethod write(cls, map, filename)
if (PyObject_HasAttrString(mClass, "write")) {
mCapabilities |= Tiled::TilesetFormat::Write;
}

// @classmethod read(cls, filename)
// @classmethod supportsFile(cls, filename)
if (PyObject_HasAttrString(mClass, "read") &&
PyObject_HasAttrString(mClass, "supportsFile")) {
mCapabilities |= Tiled::TilesetFormat::Read;
}
}
}

} // namespace Python
25 changes: 6 additions & 19 deletions src/plugins/python/pythonplugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,16 +46,10 @@ class PythonTilesetFormat;

struct ScriptEntry
{
ScriptEntry()
: module(nullptr)
, mapFormat(nullptr)
, tilesetFormat(nullptr)
{}

QString name;
PyObject *module;
PythonMapFormat *mapFormat;
PythonTilesetFormat *tilesetFormat;
PyObject *module = nullptr;
PythonMapFormat *mapFormat = nullptr;
PythonTilesetFormat *tilesetFormat = nullptr;
};

class Q_DECL_EXPORT PythonPlugin : public Tiled::Plugin
Expand Down Expand Up @@ -109,8 +103,8 @@ class PythonTilesetScript {
class PythonFormat {
public:
PyObject *pythonClass() const { return mClass; }
virtual void setPythonClass(PyObject *class_);
void setPythonClass(PyObject *class_);

protected:
PythonFormat(const QString &scriptFile, PyObject *class_);

Expand All @@ -123,6 +117,7 @@ class PythonFormat {
PyObject *mClass;
QString mScriptFile;
QString mError;
Tiled::FileFormat::Capabilities mCapabilities;
};

class PythonMapFormat : public Tiled::MapFormat, public PythonFormat
Expand All @@ -135,7 +130,6 @@ class PythonMapFormat : public Tiled::MapFormat, public PythonFormat
PyObject *class_,
QObject *parent = nullptr);

void setPythonClass(PyObject *class_) override;
Capabilities capabilities() const override { return mCapabilities; };

std::unique_ptr<Tiled::Map> read(const QString &fileName) override;
Expand All @@ -146,9 +140,6 @@ class PythonMapFormat : public Tiled::MapFormat, public PythonFormat
QString nameFilter() const override { return _nameFilter(); }
QString shortName() const override { return _shortName(); }
QString errorString() const override { return _errorString(); }

private:
Capabilities mCapabilities;
};

class PythonTilesetFormat : public Tiled::TilesetFormat, public PythonFormat
Expand All @@ -161,7 +152,6 @@ class PythonTilesetFormat : public Tiled::TilesetFormat, public PythonFormat
PyObject *class_,
QObject *parent = nullptr);

void setPythonClass(PyObject *class_) override;
Capabilities capabilities() const override { return mCapabilities; };

Tiled::SharedTileset read(const QString &fileName) override;
Expand All @@ -172,9 +162,6 @@ class PythonTilesetFormat : public Tiled::TilesetFormat, public PythonFormat
QString nameFilter() const override { return _nameFilter(); }
QString shortName() const override { return _shortName(); }
QString errorString() const override { return _errorString(); }

private:
Capabilities mCapabilities;
};

} // namespace Python

0 comments on commit 8499992

Please sign in to comment.