From 465eb4cf4309a52a224ab578bc1e60d67094cdb1 Mon Sep 17 00:00:00 2001 From: Mikhael Danilov Date: Sun, 26 Jan 2025 17:06:11 +0300 Subject: [PATCH 1/3] Export plugin for Remixed Dungeon --- src/plugins/plugins.qbs | 1 + src/plugins/rpd/plugin.json | 1 + src/plugins/rpd/qjsonparser/json.cpp | 446 +++++++++++++++++ src/plugins/rpd/qjsonparser/json.h | 62 +++ src/plugins/rpd/qjsonparser/jsonparser.cpp | 527 +++++++++++++++++++++ src/plugins/rpd/rpd.qbs | 14 + src/plugins/rpd/rpd_global.h | 12 + src/plugins/rpd/rpdplugin.cpp | 354 ++++++++++++++ src/plugins/rpd/rpdplugin.h | 87 ++++ 9 files changed, 1504 insertions(+) create mode 100644 src/plugins/rpd/plugin.json create mode 100644 src/plugins/rpd/qjsonparser/json.cpp create mode 100644 src/plugins/rpd/qjsonparser/json.h create mode 100644 src/plugins/rpd/qjsonparser/jsonparser.cpp create mode 100644 src/plugins/rpd/rpd.qbs create mode 100644 src/plugins/rpd/rpd_global.h create mode 100644 src/plugins/rpd/rpdplugin.cpp create mode 100644 src/plugins/rpd/rpdplugin.h diff --git a/src/plugins/plugins.qbs b/src/plugins/plugins.qbs index 4d91f06fce..2dcfc17cdc 100644 --- a/src/plugins/plugins.qbs +++ b/src/plugins/plugins.qbs @@ -14,6 +14,7 @@ Project { "python", "replicaisland", "rpmap", + "rpd", "tbin", "tengine", "tscn", diff --git a/src/plugins/rpd/plugin.json b/src/plugins/rpd/plugin.json new file mode 100644 index 0000000000..4aa0842c3b --- /dev/null +++ b/src/plugins/rpd/plugin.json @@ -0,0 +1 @@ +{ "defaultEnable": true } diff --git a/src/plugins/rpd/qjsonparser/json.cpp b/src/plugins/rpd/qjsonparser/json.cpp new file mode 100644 index 0000000000..0b2396f3a1 --- /dev/null +++ b/src/plugins/rpd/qjsonparser/json.cpp @@ -0,0 +1,446 @@ +/**************************************************************************** +** +** Copyright (c) 2010 Girish Ramakrishnan +** +** Use, modification and distribution is allowed without limitation, +** warranty, liability or support of any kind. +** +****************************************************************************/ + +#include "json.h" +#include "jsonparser.cpp" + +#include +#include + +/*! + \class JsonReader + \reentrant + + \brief The JsonReader class provides a fast parser for reading + well-formed JSON into a QVariant. + + The parser converts JSON types into QVariant types. For example, JSON + arrays are translated into QVariantList and JSON objects are translated + into QVariantMap. For example, + \code + JsonReader reader; + if (reader.parse(QString("{ \"id\": 123, \"class\": \"JsonReader\", \"authors\": [\"Denis\",\"Ettrich\",\"Girish\"] }"))) { + QVariant result = reader.result(); + QVariantMap map = result.toMap(); // the JSON object + qDebug() << map.count(); // 3 + qDebug() << map["id"].toInt(); // 123 + qDebug() << map["class"].toString(); // "JsonReader" + QVariantList list = map["authors"].toList(); + qDebug() << list[2].toString(); // "Girish" + } else { + qDebug() << reader.errorString(); + } + \endcode + + As seen above, the reader converts the JSON into a QVariant with arbitrary nesting. + A complete listing of JSON to QVariant conversion is documented at parse(). + + JsonWriter can be used to convert a QVariant into JSON string. +*/ + +/*! + Constructs a JSON reader. + */ +JsonReader::JsonReader() +{ +} + +/*! + Destructor + */ +JsonReader::~JsonReader() +{ +} + +/*! + Parses the JSON \a ba as a QVariant. + + If the parse succeeds, this function returns true and the QVariant can + be accessed using result(). If the parse fails, this function returns + false and the error message can be accessed using errorMessage(). + + The encoding of \ba is auto-detected based on the pattern of nulls in the + initial 4 octets as described in "Section 3. Encoding" of RFC 2647. If an + encoding could not be auto-detected, this function assumes UTF-8. + + The conversion from JSON type into QVariant type is as listed below: + \table + \row + \o false + \o QVariant::Bool with the value false. + \row + \o true + \o QVariant::Bool with the value true. + \row + \o null + \o QVariant::Invalid i.e QVariant() + \row + \o object + \o QVariant::Map i.e QVariantMap + \row + \o array + \o QVariant::List i.e QVariantList + \row + \o string + \o QVariant::String i.e QString + \row + \o number + \o QVariant::Double or QVariant::LongLong. If the JSON number contains a '.' or 'e' + or 'E', QVariant::Double is used. + \endtable + + The byte array \ba may or may not contain a BOM. + */ +bool JsonReader::parse(const QByteArray &ba) +{ + QTextCodec *codec = QTextCodec::codecForUtfText(ba, 0); // try BOM detection + if (!codec) { + int mib = 106; // utf-8 + + if (ba.length() > 3) { // auto-detect + const char *data = ba.constData(); + if (data[0] != 0) { + if (data[1] != 0) + mib = 106; // utf-8 + else if (data[2] != 0) + mib = 1014; // utf16 le + else + mib = 1019; // utf32 le + } else if (data[1] != 0) + mib = 1013; // utf16 be + else + mib = 1018; // utf32 be + } + codec = QTextCodec::codecForMib(mib); + } + QString str = codec->toUnicode(ba); + return parse(str); +} + +/*! + Parses the JSON string \a str as a QVariant. + + If the parse succeeds, this function returns true and the QVariant can + be accessed using result(). If the parse fails, this function returns + false and the error message can be accessed using errorMessage(). + */ +bool JsonReader::parse(const QString &str) +{ + JsonLexer lexer(str); + JsonParser parser; + if (!parser.parse(&lexer)) { + m_errorString = parser.errorMessage(); + m_result = QVariant(); + return false; + } + m_errorString.clear(); + m_result = parser.result(); + return true; +} + +/*! + Returns the result of the last parse() call. + + If parse() failed, this function returns an invalid QVariant. + */ +QVariant JsonReader::result() const +{ + return m_result; +} + +/*! + Returns the error message for the last parse() call. + + If parse() succeeded, this functions return an empty string. The error message + should be used for debugging purposes only. + */ +QString JsonReader::errorString() const +{ + return m_errorString; +} + +/*! + \class JsonWriter + \reentrant + + \brief The JsonWriter class converts a QVariant into a JSON string. + + The writer converts specific supported types stored in a QVariant into JSON. + For example, + \code + QVariantMap map; + map["id"] = 123; + map["class"] = "JsonWriter"; + QVariantList list; + list << "Denis" << "Ettrich" << "Girish"; + map["authors"] = list; + + JsonWriter writer; + if (writer.stringify(map)) { + QString json = writer.result(); + qDebug() << json; // {"authors": ["Denis", "Ettrich", "Girish"], "class": "JsonWriter", "id": 123 } + } else { + qDebug() << "Failed to stringify " << writer.errorString(); + } + \endcode + + The list of QVariant types that the writer supports is listed in stringify(). Note that + custom C++ types registered using Q_DECLARE_METATYPE are not supported. +*/ + +/*! + Creates a JsonWriter. + */ +JsonWriter::JsonWriter() + : m_autoFormatting(false), m_autoFormattingIndent(4, QLatin1Char(' ')) +{ +} + +/*! + Destructor. + */ +JsonWriter::~JsonWriter() +{ +} + +/*! + Enables auto formatting if \a enable is \c true, otherwise + disables it. + + When auto formatting is enabled, the writer automatically inserts + spaces and new lines to make the output more human readable. + + The default value is \c false. + */ +void JsonWriter::setAutoFormatting(bool enable) +{ + m_autoFormatting = enable; +} + +/*! + Returns \c true if auto formattting is enabled, otherwise \c false. + */ +bool JsonWriter::autoFormatting() const +{ + return m_autoFormatting; +} + +/*! + Sets the number of spaces or tabs used for indentation when + auto-formatting is enabled. Positive numbers indicate spaces, + negative numbers tabs. + + The default indentation is 4. + + \sa setAutoFormatting() +*/ +void JsonWriter::setAutoFormattingIndent(int spacesOrTabs) +{ + m_autoFormattingIndent = QString(qAbs(spacesOrTabs), QLatin1Char(spacesOrTabs >= 0 ? ' ' : '\t')); +} + +/*! + Retuns the numbers of spaces or tabs used for indentation when + auto-formatting is enabled. Positive numbers indicate spaces, + negative numbers tabs. + + The default indentation is 4. + + \sa setAutoFormatting() +*/ +int JsonWriter::autoFormattingIndent() const +{ + return m_autoFormattingIndent.count(QLatin1Char(' ')) - m_autoFormattingIndent.count(QLatin1Char('\t')); +} + +/*! \internal + Inserts escape character \ for characters in string as described in JSON specification. + */ +static QString escape(const QVariant &variant) +{ + QString str = variant.toString(); + QString res; + res.reserve(str.length()); + for (int i = 0; i < str.length(); i++) { + if (str[i] == QLatin1Char('\b')) { + res += QLatin1String("\\b"); + } else if (str[i] == QLatin1Char('\f')) { + res += QLatin1String("\\f"); + } else if (str[i] == QLatin1Char('\n')) { + res += QLatin1String("\\n"); + } else if (str[i] == QLatin1Char('\r')) { + res += QLatin1String("\\r"); + } else if (str[i] == QLatin1Char('\t')) { + res += QLatin1String("\\t"); + } else if (str[i] == QLatin1Char('\"')) { + res += QLatin1String("\\\""); + } else if (str[i] == QLatin1Char('\\')) { + res += QLatin1String("\\\\"); + } else if (str[i] == QLatin1Char('/')) { + res += QLatin1String("\\/"); + } else if (str[i].unicode() > 127) { + res += QLatin1String("\\u") + QString::number(str[i].unicode(), 16).rightJustified(4, QLatin1Char('0')); + } else { + res += str[i]; + } + } + return res; +} + +/*! \internal + Stringifies \a variant. + */ +void JsonWriter::stringify(const QVariant &variant, int depth) +{ + if (variant.type() == QVariant::List || variant.type() == QVariant::StringList) { + m_result += QLatin1Char('['); + QVariantList list = variant.toList(); + for (int i = 0; i < list.count(); i++) { + if (i != 0) { + m_result += QLatin1Char(','); + if (m_autoFormatting) + m_result += QLatin1Char(' '); + } + stringify(list[i], depth+1); + } + m_result += QLatin1Char(']'); + } else if (variant.type() == QVariant::Map) { + QString indent = m_autoFormattingIndent.repeated(depth); + QVariantMap map = variant.toMap(); + if (m_autoFormatting && depth != 0) { + m_result += QLatin1Char('\n'); + m_result += indent; + m_result += QLatin1String("{\n"); + } else { + m_result += QLatin1Char('{'); + } + for (QVariantMap::const_iterator it = map.constBegin(); it != map.constEnd(); ++it) { + if (it != map.constBegin()) { + m_result += QLatin1Char(','); + if (m_autoFormatting) + m_result += QLatin1Char('\n'); + } + if (m_autoFormatting) + m_result += indent + QLatin1Char(' '); + m_result += QLatin1Char('\"') + escape(it.key()) + QLatin1String("\":"); + stringify(it.value(), depth+1); + } + if (m_autoFormatting) { + m_result += QLatin1Char('\n'); + m_result += indent; + } + m_result += QLatin1Char('}'); + } else if (variant.type() == QVariant::String || variant.type() == QVariant::ByteArray) { + m_result += QLatin1Char('\"') + escape(variant) + QLatin1Char('\"'); + } else if (variant.type() == QVariant::Double || (int)variant.type() == (int)QMetaType::Float) { + double d = variant.toDouble(); + if (qIsFinite(d)) + m_result += QString::number(variant.toDouble(), 'g', 15); + else + m_result += QLatin1String("null"); + } else if (variant.type() == QVariant::Bool) { + m_result += variant.toBool() ? QLatin1String("true") : QLatin1String("false"); + } else if (variant.type() == QVariant::Invalid) { + m_result += QLatin1String("null"); + } else if (variant.type() == QVariant::ULongLong) { + m_result += QString::number(variant.toULongLong()); + } else if (variant.type() == QVariant::LongLong) { + m_result += QString::number(variant.toLongLong()); + } else if (variant.type() == QVariant::Int) { + m_result += QString::number(variant.toInt()); + } else if (variant.type() == QVariant::UInt) { + m_result += QString::number(variant.toUInt()); + } else if (variant.type() == QVariant::Char) { + QChar c = variant.toChar(); + if (c.unicode() > 127) + m_result += QLatin1String("\"\\u") + QString::number(c.unicode(), 16).rightJustified(4, QLatin1Char('0')) + QLatin1Char('\"'); + else + m_result += QLatin1Char('\"') + c + QLatin1Char('\"'); + } else if (variant.canConvert()) { + m_result += QString::number(variant.toLongLong()); + } else if (variant.canConvert()) { + m_result += QLatin1Char('\"') + escape(variant) + QLatin1Char('\"'); + } else { + if (!m_errorString.isEmpty()) + m_errorString.append(QLatin1Char('\n')); + QString msg = QString::fromLatin1("Unsupported type %1 (id: %2)").arg(QString::fromUtf8(variant.typeName())).arg(variant.userType()); + m_errorString.append(msg); + qWarning() << "JsonWriter::stringify - " << msg; + m_result += QLatin1String("null"); + } +} + +/*! + Converts the variant \a var into a JSON string. + + The stringizer converts \a var into JSON based on the type of it's contents. The supported + types and their conversion into JSON is as listed below: + + \table + \row + \o QVariant::List, QVariant::StringList + \o JSON array [] + \row + \o QVariant::Map + \o JSON object {} + \row + \o QVariant::String, QVariant::ByteArray + \o JSON string encapsulated in double quotes. String contents are escaped using '\' if necessary. + \row + \o QVariant::Double, QMetaType::Float + \o JSON number with a precision 15. Infinity and NaN are converted into null. + \row + \o QVariant::Bool + \o JSON boolean true and false + \row + \o QVariant::Invalid + \o JSON null + \row + \o QVariant::ULongLong, QVariant::LongLong, QVariant::Int, QVariant::UInt, + \o JSON number + \row + \o QVariant::Char + \o JSON string. Non-ASCII characters are converted into the \uXXXX notation. + \endtable + + As a fallback, the writer attempts to convert a type not listed above into a long long or a + QString using QVariant::canConvert. See the QVariant documentation for possible conversions. + + JsonWriter does not support stringizing custom user types stored in the QVariant. Any such + value would be converted into JSON null. + */ +bool JsonWriter::stringify(const QVariant &var) +{ + m_errorString.clear(); + m_result.clear(); + stringify(var, 0 /* depth */); + return m_errorString.isEmpty(); +} + +/*! + Returns the result of the last stringify() call. + + If stringify() failed, this function returns a null QString. + */ +QString JsonWriter::result() const +{ + return m_result; +} + +/*! + Returns the error message for the last stringify() call. + + If stringify() succeeded, this functions return an empty string. The error message + should be used for debugging purposes only. + */ +QString JsonWriter::errorString() const +{ + return m_errorString; +} + diff --git a/src/plugins/rpd/qjsonparser/json.h b/src/plugins/rpd/qjsonparser/json.h new file mode 100644 index 0000000000..114f522bdb --- /dev/null +++ b/src/plugins/rpd/qjsonparser/json.h @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (c) 2010 Girish Ramakrishnan +** +** Use, modification and distribution is allowed without limitation, +** warranty, liability or support of any kind. +** +****************************************************************************/ + +#ifndef JSON_H +#define JSON_H + +#include +#include + +class JsonReader +{ +public: + JsonReader(); + ~JsonReader(); + + bool parse(const QByteArray &ba); + bool parse(const QString &str); + + QVariant result() const; + + QString errorString() const; + +private: + QVariant m_result; + QString m_errorString; +}; + +class JsonWriter +{ +public: + JsonWriter(); + ~JsonWriter(); + + bool stringify(const QVariant &variant); + + QString result() const; + + QString errorString() const; + + void setAutoFormatting(bool autoFormat); + bool autoFormatting() const; + + void setAutoFormattingIndent(int spaceOrTabs); + int autoFormattingIndent() const; + +private: + void stringify(const QVariant &variant, int depth); + + QString m_result; + QString m_errorString; + bool m_autoFormatting; + QString m_autoFormattingIndent; +}; + +#endif // JSON_H + diff --git a/src/plugins/rpd/qjsonparser/jsonparser.cpp b/src/plugins/rpd/qjsonparser/jsonparser.cpp new file mode 100644 index 0000000000..3ca2c11be6 --- /dev/null +++ b/src/plugins/rpd/qjsonparser/jsonparser.cpp @@ -0,0 +1,527 @@ +// This file was generated by qlalr - DO NOT EDIT! +#ifndef JSONPARSER_CPP +#define JSONPARSER_CPP + +class JsonGrammar +{ +public: + enum VariousConstants { + EOF_SYMBOL = 0, + ERROR = 12, + T_COLON = 7, + T_COMMA = 8, + T_FALSE = 9, + T_LCURLYBRACKET = 3, + T_LSQUAREBRACKET = 5, + T_NULL = 11, + T_NUMBER = 2, + T_RCURLYBRACKET = 4, + T_RSQUAREBRACKET = 6, + T_STRING = 1, + T_TRUE = 10, + + ACCEPT_STATE = 12, + RULE_COUNT = 17, + STATE_COUNT = 27, + TERMINAL_COUNT = 13, + NON_TERMINAL_COUNT = 7, + + GOTO_INDEX_OFFSET = 27, + GOTO_INFO_OFFSET = 37, + GOTO_CHECK_OFFSET = 37 + }; + + static const char *const spell []; + static const short lhs []; + static const short rhs []; + +#ifndef QLALR_NO_JSONGRAMMAR_DEBUG_INFO + static const int rule_index []; + static const int rule_info []; +#endif // QLALR_NO_JSONGRAMMAR_DEBUG_INFO + + static const short goto_default []; + static const short action_default []; + static const short action_index []; + static const short action_info []; + static const short action_check []; + + static inline int nt_action (int state, int nt) + { + const int yyn = action_index [GOTO_INDEX_OFFSET + state] + nt; + if (yyn < 0 || action_check [GOTO_CHECK_OFFSET + yyn] != nt) + return goto_default [nt]; + + return action_info [GOTO_INFO_OFFSET + yyn]; + } + + static inline int t_action (int state, int token) + { + const int yyn = action_index [state] + token; + + if (yyn < 0 || action_check [yyn] != token) + return - action_default [state]; + + return action_info [yyn]; + } +}; + + +const char *const JsonGrammar::spell [] = { + "end of file", "string", "number", "{", "}", "[", "]", ":", ",", "false", + "true", "null", "error", +#ifndef QLALR_NO_JSONGRAMMAR_DEBUG_INFO +"Root", "Value", "Object", "Members", "Array", "Values", "$accept" +#endif // QLALR_NO_JSONGRAMMAR_DEBUG_INFO +}; + +const short JsonGrammar::lhs [] = { + 13, 15, 16, 16, 16, 14, 14, 14, 14, 14, + 14, 14, 17, 18, 18, 18, 19}; + +const short JsonGrammar::rhs [] = { + 1, 3, 3, 5, 0, 1, 1, 1, 1, 1, + 1, 1, 3, 1, 3, 0, 2}; + + +#ifndef QLALR_NO_JSONGRAMMAR_DEBUG_INFO +const int JsonGrammar::rule_info [] = { + 13, 14 + , 15, 3, 16, 4 + , 16, 1, 7, 14 + , 16, 16, 8, 1, 7, 14 + , 16 + , 14, 9 + , 14, 10 + , 14, 11 + , 14, 15 + , 14, 17 + , 14, 2 + , 14, 1 + , 17, 5, 18, 6 + , 18, 14 + , 18, 18, 8, 14 + , 18 + , 19, 13, 0}; + +const int JsonGrammar::rule_index [] = { + 0, 2, 6, 10, 16, 17, 19, 21, 23, 25, + 27, 29, 31, 35, 37, 41, 42}; +#endif // QLALR_NO_JSONGRAMMAR_DEBUG_INFO + +const short JsonGrammar::action_default [] = { + 0, 10, 9, 0, 6, 5, 16, 8, 11, 12, + 7, 1, 17, 0, 0, 0, 2, 0, 0, 4, + 0, 3, 14, 0, 0, 13, 15}; + +const short JsonGrammar::goto_default [] = { + 3, 11, 2, 13, 1, 23, 0}; + +const short JsonGrammar::action_index [] = { + 24, -13, -13, 12, -13, -1, 24, -13, -13, -13, + -13, -13, -13, 1, -5, 2, -13, -6, 24, -13, + 24, -13, -13, -2, 24, -13, -13, + + -7, -7, -7, -7, -7, -7, 1, -7, -7, -7, + -7, -7, -7, -7, -7, -7, -7, -7, 0, -7, + -1, -7, -7, -7, 5, -7, -7}; + +const short JsonGrammar::action_info [] = { + 14, 18, 20, 17, 25, 16, 24, 0, 0, 15, + 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 9, 8, 5, 0, 6, + 0, 0, 0, 4, 10, 7, 0, + + 21, 19, 22, 0, 0, 0, 26, 0, 0, 0, + 0, 0}; + +const short JsonGrammar::action_check [] = { + 1, 7, 7, 1, 6, 4, 8, -1, -1, 8, + -1, -1, 0, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 1, 2, 3, -1, 5, + -1, -1, -1, 9, 10, 11, -1, + + 1, 1, 1, -1, -1, -1, 1, -1, -1, -1, + -1, -1}; + + +#line 29 "json.g" + +/**************************************************************************** +** +** Copyright (c) 2010 Girish Ramakrishnan +** Copyright (c) 2011 Denis Dzyubenko +** +** Use, modification and distribution is allowed without limitation, +** warranty, liability or support of any kind. +** +****************************************************************************/ + +#ifndef JSONPARSER_P_H +#define JSONPARSER_P_H + +#include +#include +#include + +class JsonLexer +{ +public: + JsonLexer(const QString &string); + ~JsonLexer(); + + int lex(); + QVariant symbol() const { return m_symbol; } + int lineNumber() const { return m_lineNumber; } + int pos() const { return m_pos; } + +private: + int parseNumber(); + int parseString(); + int parseKeyword(); + + QString m_strdata; + int m_lineNumber; + int m_pos; + QVariant m_symbol; +}; + +class JsonParser : protected JsonGrammar +{ +public: + JsonParser(); + ~JsonParser(); + + bool parse(JsonLexer *lex); + QVariant result() const { return m_result; } + QString errorMessage() const { return QString::fromLatin1("%1 at line %2 pos %3").arg(m_errorMessage).arg(m_errorLineNumber).arg(m_errorPos); } + +private: + void reallocateStack(); + + inline QVariant &sym(int index) + { return m_symStack[m_tos + index - 1]; } + inline QVariantMap &map(int index) + { return m_mapStack[m_tos + index - 1]; } + inline QVariantList &list(int index) + { return m_listStack[m_tos + index - 1]; } + + int m_tos; + QVector m_stateStack; + QVector m_symStack; + QVector m_mapStack; + QVector m_listStack; + QString m_errorMessage; + int m_errorLineNumber; + int m_errorPos; + QVariant m_result; +}; + +#endif // JSONPARSER_P_H + +#line 103 "json.g" + +/**************************************************************************** +** +** Copyright (c) 2010 Girish Ramakrishnan +** Copyright (c) 2011 Denis Dzyubenko +** +** Use, modification and distribution is allowed without limitation, +** warranty, liability or support of any kind. +** +****************************************************************************/ + +#include + +#define L1C(c) ushort(uchar(c)) + +JsonLexer::JsonLexer(const QString &str) + : m_strdata(str), m_lineNumber(1), m_pos(0) +{ +} + + + +JsonLexer::~JsonLexer() +{ +} + +int JsonLexer::parseString() +{ + bool esc = false; + ++m_pos; // skip initial " + int start = m_pos; + + const ushort *uc = m_strdata.utf16(); + const int remaining = m_strdata.length() - m_pos; + int i; + for (i = 0; i < remaining; ++i) { + const ushort c = uc[m_pos + i]; + if (c == L1C('\"')) { + m_symbol = QString((QChar *)uc + m_pos, i); + m_pos += i; + ++m_pos; // eat quote + return JsonGrammar::T_STRING; + } else if (c == L1C('\\')) { + ++m_pos; // eat backslash + esc = true; + break; + } + } + + QString str; + if (i) { + str.resize(i); + memcpy((char *)str.utf16(), uc + start, i * 2); + m_pos += i; + } + + for (; m_pos < m_strdata.length(); ++m_pos) { + const ushort c = uc[m_pos]; + if (esc) { + if (c == L1C('b')) str += QLatin1Char('\b'); + else if (c == L1C('f')) str += QLatin1Char('\f'); + else if (c == L1C('n')) str += QLatin1Char('\n'); + else if (c == L1C('r')) str += QLatin1Char('\r'); + else if (c == L1C('t')) str += QLatin1Char('\t'); + else if (c == L1C('\\')) str += QLatin1Char('\\'); + else if (c == L1C('\"')) str += QLatin1Char('\"'); + else if (c == L1C('u') && m_pos+4= L1C('0') && c <= L1C('9')) { + if (!isDouble) { + value *= 10; + value += c - L1C('0'); + } + continue; + } + break; + } + if (!isDouble) { + m_symbol = value * negative; + } else { + QString number = QString::fromRawData((QChar *)uc+start, m_pos-start); + m_symbol = number.toDouble(); + } + return JsonGrammar::T_NUMBER; +} + +int JsonLexer::parseKeyword() +{ + int start = m_pos; + for (; m_pos < m_strdata.length(); ++m_pos) { + const ushort c = m_strdata.at(m_pos).unicode(); + if (c >= L1C('a') && c <= L1C('z')) + continue; + break; + } + const ushort *k = (const ushort *)m_strdata.constData() + start; + const int l = m_pos-start; + if (l == 4) { + static const ushort true_data[] = { 't', 'r', 'u', 'e' }; + static const ushort null_data[] = { 'n', 'u', 'l', 'l' }; + if (!memcmp(k, true_data, 4 * sizeof(ushort))) + return JsonGrammar::T_TRUE; + if (!memcmp(k, null_data, 4 * sizeof(ushort))) + return JsonGrammar::T_NULL; + } else if (l == 5) { + static const ushort false_data[] = { 'f', 'a', 'l', 's', 'e' }; + if (!memcmp(k, false_data, 5 * sizeof(ushort))) + return JsonGrammar::T_FALSE; + } + return JsonGrammar::ERROR; +} + +int JsonLexer::lex() +{ + m_symbol.clear(); + + const ushort *uc = m_strdata.utf16(); + const int len = m_strdata.length(); + while (m_pos < len) { + const ushort c = uc[m_pos]; + switch (c) { + case L1C('['): ++m_pos; return JsonGrammar::T_LSQUAREBRACKET; + case L1C(']'): ++m_pos; return JsonGrammar::T_RSQUAREBRACKET; + case L1C('{'): ++m_pos; return JsonGrammar::T_LCURLYBRACKET; + case L1C('}'): ++m_pos; return JsonGrammar::T_RCURLYBRACKET; + case L1C(':'): ++m_pos; return JsonGrammar::T_COLON; + case L1C(','): ++m_pos; return JsonGrammar::T_COMMA; + case L1C(' '): case L1C('\r'): case L1C('\t'): ++m_pos; break; + case L1C('\n'): ++m_pos; ++m_lineNumber; break; + case L1C('"'): return parseString(); + default: + if (c == L1C('+') || c == L1C('-') || (c >= L1C('0') && c <= L1C('9'))) { + return parseNumber(); + } + if (c >= L1C('a') && c <= L1C('z')) { + return parseKeyword(); + } + return JsonGrammar::ERROR; + } + } + return JsonGrammar::EOF_SYMBOL; +} +#undef L1C + +JsonParser::JsonParser() + : m_tos(0) + , m_errorLineNumber(-1) + , m_errorPos(-1) +{ +} + +JsonParser::~JsonParser() +{ +} + +void JsonParser::reallocateStack() +{ + int size = m_stateStack.size(); + if (size == 0) + size = 128; + else + size <<= 1; + + m_symStack.resize(size); + m_mapStack.resize(size); + m_listStack.resize(size); + m_stateStack.resize(size); +} + +bool JsonParser::parse(JsonLexer *lexer) +{ + const int INITIAL_STATE = 0; + int yytoken = -1; + reallocateStack(); + m_tos = 0; + m_stateStack[++m_tos] = INITIAL_STATE; + + while (true) { + const int state = m_stateStack[m_tos]; + if (yytoken == -1 && -TERMINAL_COUNT != action_index[state]) { + yytoken = lexer->lex(); + } + int act = t_action(state, yytoken); + if (act == ACCEPT_STATE) + return true; + else if (act > 0) { + if (++m_tos == m_stateStack.size()) + reallocateStack(); + m_stateStack[m_tos] = act; + m_symStack[m_tos] = lexer->symbol(); + yytoken = -1; + } else if (act < 0) { + int r = -act-1; + m_tos -= rhs[r]; + act = m_stateStack.at(m_tos++); + switch (r) { + +#line 334 "json.g" + case 0: { m_result = sym(1); break; } +#line 337 "json.g" + case 1: { sym(1) = map(2); break; } +#line 340 "json.g" + case 2: { QVariantMap m; m.insert(sym(1).toString(), sym(3)); map(1) = m; break; } +#line 343 "json.g" + case 3: { map(1).insert(sym(3).toString(), sym(5)); break; } +#line 346 "json.g" + case 4: { map(1) = QVariantMap(); break; } +#line 349 "json.g" + case 5: { sym(1) = QVariant(false); break; } +#line 352 "json.g" + case 6: { sym(1) = QVariant(true); break; } +#line 361 "json.g" + case 12: { sym(1) = list(2); break; } +#line 364 "json.g" + case 13: { QVariantList l; l.append(sym(1)); list(1) = l; break; } +#line 367 "json.g" + case 14: { list(1).append(sym(3)); break; } +#line 370 "json.g" + case 15: { list(1) = QVariantList(); break; } +#line 372 "json.g" + + } // switch + m_stateStack[m_tos] = nt_action(act, lhs[r] - TERMINAL_COUNT); + } else { + int ers = state; + int shifts = 0; + int reduces = 0; + int expected_tokens[3]; + for (int tk = 0; tk < TERMINAL_COUNT; ++tk) { + int k = t_action(ers, tk); + + if (! k) + continue; + else if (k < 0) + ++reduces; + else if (spell[tk]) { + if (shifts < 3) + expected_tokens[shifts] = tk; + ++shifts; + } + } + + m_errorLineNumber = lexer->lineNumber(); + m_errorPos = lexer->pos(); + m_errorMessage.clear(); + if (shifts && shifts < 3) { + bool first = true; + + for (int s = 0; s < shifts; ++s) { + if (first) + m_errorMessage += QLatin1String("Expected "); + else + m_errorMessage += QLatin1String(", "); + + first = false; + m_errorMessage += QLatin1String("'"); + m_errorMessage += QLatin1String(spell[expected_tokens[s]]); + m_errorMessage += QLatin1String("'"); + } + } + return false; + } + } + + return false; +} + + +#endif // JSONPARSER_CPP + diff --git a/src/plugins/rpd/rpd.qbs b/src/plugins/rpd/rpd.qbs new file mode 100644 index 0000000000..ab573bc0ec --- /dev/null +++ b/src/plugins/rpd/rpd.qbs @@ -0,0 +1,14 @@ +import qbs 1.0 + +TiledPlugin { + cpp.defines: ["RPD_LIBRARY"] + + files: [ + "rpd_global.h", + "rpdplugin.cpp", + "rpdplugin.h", + "plugin.json", + "qjsonparser/json.cpp", + "qjsonparser/json.h", + ] +} diff --git a/src/plugins/rpd/rpd_global.h b/src/plugins/rpd/rpd_global.h new file mode 100644 index 0000000000..103989ef02 --- /dev/null +++ b/src/plugins/rpd/rpd_global.h @@ -0,0 +1,12 @@ +#ifndef RPD_GLOBAL_H +#define RPD_GLOBAL_H + +#include + +#if defined(RPD_LIBRARY) +# define RPDSHARED_EXPORT Q_DECL_EXPORT +#else +# define RPDSHARED_EXPORT Q_DECL_IMPORT +#endif + +#endif // RPD_GLOBAL_H diff --git a/src/plugins/rpd/rpdplugin.cpp b/src/plugins/rpd/rpdplugin.cpp new file mode 100644 index 0000000000..5eb8179c26 --- /dev/null +++ b/src/plugins/rpd/rpdplugin.cpp @@ -0,0 +1,354 @@ +#include "rpdplugin.h" + +#include "maptovariantconverter.h" +#include "varianttomapconverter.h" +#include "savefile.h" +#include "objectgroup.h" + +#include "qjsonparser/json.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace Rpd { + +void RpdPlugin::initialize() +{ + addObject(new RpdMapFormat(RpdMapFormat::Rpd, this)); + addObject(new RpdTilesetFormat(this)); +} + + +RpdMapFormat::RpdMapFormat(SubFormat subFormat, QObject *parent) + : mSubFormat(subFormat) +{ + (void)parent; +} + +QString RpdMapFormat::shortName(void) const +{ + return "RPD"; +} + +QJsonArray packMapData(Tiled::Layer *layer) +{ + QJsonArray map; + for(int j=0;jmap()->height();++j){ + for(int i=0;imap()->width();++i){ + map.append(layer->asTileLayer()->cellAt(i,j).tileId()); + } + } + return map; +} + +bool RpdMapFormat::insertTilesetFile(Tiled::Layer &layer, const QString &tiles_name, QJsonObject &mapJson) +{ + auto tilesets = layer.asTileLayer()->usedTilesets(); + + if(tilesets.size()==0) { + QString msg = QString("You have ")+layer.name()+" layer please fill it"; + mError = tr(msg.toUtf8()); + return false; + } + + if(tilesets.size()>1) { + QString msg = QString("Only one tileset per layer supported (")+layer.name()+" layer) ->\n"; + for(auto tileset: tilesets) { + msg += "[" + tileset->name() + "]\n"; + } + mError = tr(msg.toUtf8()); + return false; + } + + mapJson.insert(tiles_name,tilesets.begin()->data()->name()+".png"); + return true; +} + + + + +bool RpdMapFormat::write(const Tiled::Map *map, const QString &fileName, Options options) +{ + (void)fileName; + (void)options; + Tiled::SaveFile file(fileName); + + if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { + mError = tr("Could not open file for writing."); + return false; + } + + QJsonObject mapJson; + + for(const auto& property : map->properties().toStdMap()) { + QVariant value = property.second; + if(value.canConvert()) { + mapJson.insert(property.first, value.toDouble()); + continue; + } + + if(value.canConvert()) { + mapJson.insert(property.first, value.toString()); + continue; + } + + mError = tr("Dont know what to do with property (%1)").arg(property.first); + return false; + } + + for(Tiled::Layer *layer: map->layers()) { + + if(layer->layerType()==Tiled::Layer::TileLayerType && !insertTilesetFile(*layer,QString("tiles_")+layer->name(),mapJson)) { + return false; + } + + if(layer->name()=="logic") { + + QJsonArray entrance; + QJsonArray multiexit; + + mapJson.insert("width",layer->map()->width()); + mapJson.insert("height",layer->map()->height()); + + mapJson.insert("map",packMapData(layer)); + + for(int i=0;imap()->width();++i){ + for(int j=0;jmap()->height();++j){ + int tileId = layer->asTileLayer()->cellAt(i,j).tileId(); + + if(tileId<0) { + mError = tr("Hole in logic layer at (%1, %2)").arg(i).arg(j); + return false; + } + + switch (tileId) { + case TileId::ENTRANCE: + entrance.append(i); + entrance.append(j); + break; + case TileId::EXIT: + case TileId::LOCKED_EXIT: + case TileId::UNLOCKED_EXIT: + { + QJsonArray exit; + exit.append(i); + exit.append(j); + multiexit.append(exit); + } + break; + } + } + } + + mapJson.insert("entrance",entrance); + mapJson.insert("multiexit",multiexit); + } + + if(layer->name() == "base") { + mapJson.insert("baseTileVar",packMapData(layer)); + } + + if(layer->name() == "deco2") { + mapJson.insert("deco2TileVar",packMapData(layer)); + } + + if(layer->name() == "roof_base") { + mapJson.insert("roofBaseTileVar",packMapData(layer)); + } + + if(layer->name() == "roof_deco") { + mapJson.insert("roofDecoTileVar",packMapData(layer)); + } + + if(layer->name() == "deco") { + mapJson.insert("decoTileVar",packMapData(layer)); + mapJson.insert("customTiles",true); + + if(!insertTilesetFile(*layer,"tiles",mapJson)) { + return false; + } + + QJsonArray decoDesc; + QJsonArray decoName; + + auto tilesets = layer->asTileLayer()->usedTilesets(); + + auto decoTileset = tilesets.begin()->data(); + + auto it = decoTileset->tiles().begin(); + auto end = decoTileset->tiles().end(); + + while (it != end) { + decoDesc.append(((*it)->properties())["deco_desc"].toString()); + decoName.append(((*it)->properties())["deco_name"].toString()); + ++it; + } + + mapJson.insert("decoName",decoName); + mapJson.insert("decoDesc",decoDesc); + } + + if(layer->name()=="objects") { + + QMap objects; + + for (auto object : layer->asObjectGroup()->objects()) { + + QJsonObject desc; + + desc.insert("kind",object->name()); + + desc.insert("x",qFloor(object->x()/16.)); + desc.insert("y",qFloor(object->y()/16.)); + + auto properties = object->properties(); + for (auto i = properties.begin(); i != properties.end(); ++i) { + + auto jsonCandidate = QJsonDocument::fromJson(i.value().toString().toUtf8()); + + if(jsonCandidate.isObject()) { + desc.insert(i.key(),jsonCandidate.object()); + continue; + } + + desc.insert(i.key(),i.value().toJsonValue()); + } + + objects[object->type()].append(desc); + } + + for (auto key : objects.keys() ) { + mapJson.insert(key + "s", objects[key]); + } + } + } + + if(!mapJson.contains("tiles")){ + mapJson.insert("tiles","tiles0_x.png"); + } + + mapJson.insert("water","water0.png"); + + QJsonDocument mapDoc; + mapDoc.setObject(mapJson); + + QVariant variant = mapDoc.toVariant(); + + JsonWriter writer; + writer.setAutoFormatting(true); + + if (!writer.stringify(variant)) { + // This can only happen due to coding error + mError = writer.errorString(); + return false; + } + + QTextStream out(file.device()); + out << writer.result(); + + out.flush(); + + if (file.error() != QFileDevice::NoError) { + mError = tr("Error while writing file:\n%1").arg(file.errorString()); + return false; + } + + if (!file.commit()) { + mError = file.errorString(); + return false; + } + + return true; +} + +QString RpdMapFormat::nameFilter() const +{ + return tr("Remixed Pixel Dungeon levels (*.json)"); +} + +QString RpdMapFormat::errorString() const +{ + return mError; +} + + +RpdTilesetFormat::RpdTilesetFormat(QObject *parent) + : Tiled::TilesetFormat(parent) +{ +} + +Tiled::SharedTileset RpdTilesetFormat::read(const QString &fileName) +{ + (void)fileName; + return Tiled::SharedTileset(); +} + +bool RpdTilesetFormat::supportsFile(const QString &fileName) const +{ + (void)fileName; + return false; +} + +bool RpdTilesetFormat::write(const Tiled::Tileset &tileset, + const QString &fileName, + Options options) +{ + (void)fileName; + (void)options; + Tiled::SaveFile file(fileName); + + if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { + mError = tr("Could not open file for writing."); + return false; + } + + Tiled::MapToVariantConverter converter; + QVariant variant = converter.toVariant(tileset, QFileInfo(fileName).dir()); + + JsonWriter writer; + writer.setAutoFormatting(true); + + if (!writer.stringify(variant)) { + // This can only happen due to coding error + mError = writer.errorString(); + return false; + } + + QTextStream out(file.device()); + out << writer.result(); + out.flush(); + + if (file.error() != QFileDevice::NoError) { + mError = tr("Error while writing file:\n%1").arg(file.errorString()); + return false; + } + + if (!file.commit()) { + mError = file.errorString(); + return false; + } + + return true; +} + +QString RpdTilesetFormat::nameFilter() const +{ + return tr("Json tileset files (*.json)"); +} + +QString RpdTilesetFormat::errorString() const +{ + return mError; +} + +QString RpdTilesetFormat::shortName(void) const +{ + return "RPD"; +} + +} // namespace Rpd diff --git a/src/plugins/rpd/rpdplugin.h b/src/plugins/rpd/rpdplugin.h new file mode 100644 index 0000000000..bfc1fdc312 --- /dev/null +++ b/src/plugins/rpd/rpdplugin.h @@ -0,0 +1,87 @@ +#ifndef RPDPLUGIN_H +#define RPDPLUGIN_H + +#include "rpd_global.h" + +#include "layer.h" +#include "mapformat.h" +#include "plugin.h" +#include "tilesetformat.h" + +#include + +namespace Tiled { +class Map; +} + +namespace Rpd { + +class RPDSHARED_EXPORT RpdPlugin : public Tiled::Plugin +{ + Q_OBJECT + Q_INTERFACES(Tiled::Plugin) + Q_PLUGIN_METADATA(IID "org.mapeditor.Plugin" FILE "plugin.json") + +public: + void initialize() override; +}; + + +class RPDSHARED_EXPORT RpdMapFormat : public Tiled::WritableMapFormat +{ + Q_OBJECT + Q_INTERFACES(Tiled::MapFormat) + +public: + enum SubFormat { + Rpd + }; + + enum TileId { + ENTRANCE = 7, + EXIT = 8, + LOCKED_EXIT = 25, + UNLOCKED_EXIT = 26 + }; + + explicit RpdMapFormat(SubFormat subFormat, QObject *parent = nullptr); + + + bool write(const Tiled::Map *map, const QString &fileName, Options options = Options()) override; + QString shortName(void) const override; + QString nameFilter() const override; + QString errorString() const override; + +protected: + QString mError; + SubFormat mSubFormat; +private: + bool insertTilesetFile(Tiled::Layer &layer, const QString &tiles_name, QJsonObject &mapJson); + +}; + + +class RPDSHARED_EXPORT RpdTilesetFormat : public Tiled::TilesetFormat +{ + Q_OBJECT + Q_INTERFACES(Tiled::TilesetFormat) + +public: + explicit RpdTilesetFormat(QObject *parent = nullptr); + + Tiled::SharedTileset read(const QString &fileName) override; + bool supportsFile(const QString &fileName) const override; + + bool write(const Tiled::Tileset &tileset, const QString &fileName, Options options = Options()) override; + + QString shortName(void) const override; + QString nameFilter() const override; + QString errorString() const override; + +protected: + QString mError; +}; + +} // namespace Rpd + +#endif // RPDPLUGIN_H From a4b55c955dd28d471c3f06907c36dafeddd3b24b Mon Sep 17 00:00:00 2001 From: Mikhael Danilov Date: Sun, 26 Jan 2025 18:47:38 +0300 Subject: [PATCH 2/3] Export plugin for Remixed Dungeon: (will it fix Qt6 build?) --- src/plugins/rpd/qjsonparser/json.cpp | 187 +------- src/plugins/rpd/qjsonparser/json.h | 29 +- src/plugins/rpd/qjsonparser/jsonparser.cpp | 527 --------------------- 3 files changed, 29 insertions(+), 714 deletions(-) delete mode 100644 src/plugins/rpd/qjsonparser/jsonparser.cpp diff --git a/src/plugins/rpd/qjsonparser/json.cpp b/src/plugins/rpd/qjsonparser/json.cpp index 0b2396f3a1..6dce74c35b 100644 --- a/src/plugins/rpd/qjsonparser/json.cpp +++ b/src/plugins/rpd/qjsonparser/json.cpp @@ -8,163 +8,10 @@ ****************************************************************************/ #include "json.h" -#include "jsonparser.cpp" -#include +#include #include -/*! - \class JsonReader - \reentrant - - \brief The JsonReader class provides a fast parser for reading - well-formed JSON into a QVariant. - - The parser converts JSON types into QVariant types. For example, JSON - arrays are translated into QVariantList and JSON objects are translated - into QVariantMap. For example, - \code - JsonReader reader; - if (reader.parse(QString("{ \"id\": 123, \"class\": \"JsonReader\", \"authors\": [\"Denis\",\"Ettrich\",\"Girish\"] }"))) { - QVariant result = reader.result(); - QVariantMap map = result.toMap(); // the JSON object - qDebug() << map.count(); // 3 - qDebug() << map["id"].toInt(); // 123 - qDebug() << map["class"].toString(); // "JsonReader" - QVariantList list = map["authors"].toList(); - qDebug() << list[2].toString(); // "Girish" - } else { - qDebug() << reader.errorString(); - } - \endcode - - As seen above, the reader converts the JSON into a QVariant with arbitrary nesting. - A complete listing of JSON to QVariant conversion is documented at parse(). - - JsonWriter can be used to convert a QVariant into JSON string. -*/ - -/*! - Constructs a JSON reader. - */ -JsonReader::JsonReader() -{ -} - -/*! - Destructor - */ -JsonReader::~JsonReader() -{ -} - -/*! - Parses the JSON \a ba as a QVariant. - - If the parse succeeds, this function returns true and the QVariant can - be accessed using result(). If the parse fails, this function returns - false and the error message can be accessed using errorMessage(). - - The encoding of \ba is auto-detected based on the pattern of nulls in the - initial 4 octets as described in "Section 3. Encoding" of RFC 2647. If an - encoding could not be auto-detected, this function assumes UTF-8. - - The conversion from JSON type into QVariant type is as listed below: - \table - \row - \o false - \o QVariant::Bool with the value false. - \row - \o true - \o QVariant::Bool with the value true. - \row - \o null - \o QVariant::Invalid i.e QVariant() - \row - \o object - \o QVariant::Map i.e QVariantMap - \row - \o array - \o QVariant::List i.e QVariantList - \row - \o string - \o QVariant::String i.e QString - \row - \o number - \o QVariant::Double or QVariant::LongLong. If the JSON number contains a '.' or 'e' - or 'E', QVariant::Double is used. - \endtable - - The byte array \ba may or may not contain a BOM. - */ -bool JsonReader::parse(const QByteArray &ba) -{ - QTextCodec *codec = QTextCodec::codecForUtfText(ba, 0); // try BOM detection - if (!codec) { - int mib = 106; // utf-8 - - if (ba.length() > 3) { // auto-detect - const char *data = ba.constData(); - if (data[0] != 0) { - if (data[1] != 0) - mib = 106; // utf-8 - else if (data[2] != 0) - mib = 1014; // utf16 le - else - mib = 1019; // utf32 le - } else if (data[1] != 0) - mib = 1013; // utf16 be - else - mib = 1018; // utf32 be - } - codec = QTextCodec::codecForMib(mib); - } - QString str = codec->toUnicode(ba); - return parse(str); -} - -/*! - Parses the JSON string \a str as a QVariant. - - If the parse succeeds, this function returns true and the QVariant can - be accessed using result(). If the parse fails, this function returns - false and the error message can be accessed using errorMessage(). - */ -bool JsonReader::parse(const QString &str) -{ - JsonLexer lexer(str); - JsonParser parser; - if (!parser.parse(&lexer)) { - m_errorString = parser.errorMessage(); - m_result = QVariant(); - return false; - } - m_errorString.clear(); - m_result = parser.result(); - return true; -} - -/*! - Returns the result of the last parse() call. - - If parse() failed, this function returns an invalid QVariant. - */ -QVariant JsonReader::result() const -{ - return m_result; -} - -/*! - Returns the error message for the last parse() call. - - If parse() succeeded, this functions return an empty string. The error message - should be used for debugging purposes only. - */ -QString JsonReader::errorString() const -{ - return m_errorString; -} - /*! \class JsonWriter \reentrant @@ -198,7 +45,7 @@ QString JsonReader::errorString() const Creates a JsonWriter. */ JsonWriter::JsonWriter() - : m_autoFormatting(false), m_autoFormattingIndent(4, QLatin1Char(' ')) + : m_autoFormattingIndent(4, QLatin1Char(' ')) { } @@ -212,10 +59,10 @@ JsonWriter::~JsonWriter() /*! Enables auto formatting if \a enable is \c true, otherwise disables it. - + When auto formatting is enabled, the writer automatically inserts spaces and new lines to make the output more human readable. - + The default value is \c false. */ void JsonWriter::setAutoFormatting(bool enable) @@ -259,6 +106,14 @@ int JsonWriter::autoFormattingIndent() const return m_autoFormattingIndent.count(QLatin1Char(' ')) - m_autoFormattingIndent.count(QLatin1Char('\t')); } +/*! + Will insert a newline while writing out arrays after every \a count elements. + */ +void JsonWriter::setAutoFormattingWrapArrayCount(int count) +{ + m_autoFormattingWrapArrayCount = count; +} + /*! \internal Inserts escape character \ for characters in string as described in JSON specification. */ @@ -299,19 +154,26 @@ static QString escape(const QVariant &variant) void JsonWriter::stringify(const QVariant &variant, int depth) { if (variant.type() == QVariant::List || variant.type() == QVariant::StringList) { + const QString indent = m_autoFormattingIndent.repeated(depth); m_result += QLatin1Char('['); QVariantList list = variant.toList(); for (int i = 0; i < list.count(); i++) { if (i != 0) { m_result += QLatin1Char(','); - if (m_autoFormatting) - m_result += QLatin1Char(' '); + if (m_autoFormatting) { + if (m_autoFormattingWrapArrayCount && i % m_autoFormattingWrapArrayCount == 0) { + m_result += QLatin1Char('\n'); + m_result += indent; + } else { + m_result += QLatin1Char(' '); + } + } } stringify(list[i], depth+1); } m_result += QLatin1Char(']'); } else if (variant.type() == QVariant::Map) { - QString indent = m_autoFormattingIndent.repeated(depth); + const QString indent = m_autoFormattingIndent.repeated(depth); QVariantMap map = variant.toMap(); if (m_autoFormatting && depth != 0) { m_result += QLatin1Char('\n'); @@ -369,7 +231,7 @@ void JsonWriter::stringify(const QVariant &variant, int depth) } else { if (!m_errorString.isEmpty()) m_errorString.append(QLatin1Char('\n')); - QString msg = QString::fromLatin1("Unsupported type %1 (id: %2)").arg(QString::fromUtf8(variant.typeName())).arg(variant.userType()); + QString msg = QStringLiteral("Unsupported type %1 (id: %2)").arg(QString::fromUtf8(variant.typeName())).arg(variant.userType()); m_errorString.append(msg); qWarning() << "JsonWriter::stringify - " << msg; m_result += QLatin1String("null"); @@ -402,7 +264,7 @@ void JsonWriter::stringify(const QVariant &variant, int depth) \o QVariant::Invalid \o JSON null \row - \o QVariant::ULongLong, QVariant::LongLong, QVariant::Int, QVariant::UInt, + \o QVariant::ULongLong, QVariant::LongLong, QVariant::Int, QVariant::UInt, \o JSON number \row \o QVariant::Char @@ -443,4 +305,3 @@ QString JsonWriter::errorString() const { return m_errorString; } - diff --git a/src/plugins/rpd/qjsonparser/json.h b/src/plugins/rpd/qjsonparser/json.h index 114f522bdb..09b96d373a 100644 --- a/src/plugins/rpd/qjsonparser/json.h +++ b/src/plugins/rpd/qjsonparser/json.h @@ -7,30 +7,11 @@ ** ****************************************************************************/ -#ifndef JSON_H -#define JSON_H +#pragma once #include #include -class JsonReader -{ -public: - JsonReader(); - ~JsonReader(); - - bool parse(const QByteArray &ba); - bool parse(const QString &str); - - QVariant result() const; - - QString errorString() const; - -private: - QVariant m_result; - QString m_errorString; -}; - class JsonWriter { public: @@ -49,14 +30,14 @@ class JsonWriter void setAutoFormattingIndent(int spaceOrTabs); int autoFormattingIndent() const; + void setAutoFormattingWrapArrayCount(int count); + private: void stringify(const QVariant &variant, int depth); QString m_result; QString m_errorString; - bool m_autoFormatting; + bool m_autoFormatting = false; QString m_autoFormattingIndent; + int m_autoFormattingWrapArrayCount = 0; }; - -#endif // JSON_H - diff --git a/src/plugins/rpd/qjsonparser/jsonparser.cpp b/src/plugins/rpd/qjsonparser/jsonparser.cpp deleted file mode 100644 index 3ca2c11be6..0000000000 --- a/src/plugins/rpd/qjsonparser/jsonparser.cpp +++ /dev/null @@ -1,527 +0,0 @@ -// This file was generated by qlalr - DO NOT EDIT! -#ifndef JSONPARSER_CPP -#define JSONPARSER_CPP - -class JsonGrammar -{ -public: - enum VariousConstants { - EOF_SYMBOL = 0, - ERROR = 12, - T_COLON = 7, - T_COMMA = 8, - T_FALSE = 9, - T_LCURLYBRACKET = 3, - T_LSQUAREBRACKET = 5, - T_NULL = 11, - T_NUMBER = 2, - T_RCURLYBRACKET = 4, - T_RSQUAREBRACKET = 6, - T_STRING = 1, - T_TRUE = 10, - - ACCEPT_STATE = 12, - RULE_COUNT = 17, - STATE_COUNT = 27, - TERMINAL_COUNT = 13, - NON_TERMINAL_COUNT = 7, - - GOTO_INDEX_OFFSET = 27, - GOTO_INFO_OFFSET = 37, - GOTO_CHECK_OFFSET = 37 - }; - - static const char *const spell []; - static const short lhs []; - static const short rhs []; - -#ifndef QLALR_NO_JSONGRAMMAR_DEBUG_INFO - static const int rule_index []; - static const int rule_info []; -#endif // QLALR_NO_JSONGRAMMAR_DEBUG_INFO - - static const short goto_default []; - static const short action_default []; - static const short action_index []; - static const short action_info []; - static const short action_check []; - - static inline int nt_action (int state, int nt) - { - const int yyn = action_index [GOTO_INDEX_OFFSET + state] + nt; - if (yyn < 0 || action_check [GOTO_CHECK_OFFSET + yyn] != nt) - return goto_default [nt]; - - return action_info [GOTO_INFO_OFFSET + yyn]; - } - - static inline int t_action (int state, int token) - { - const int yyn = action_index [state] + token; - - if (yyn < 0 || action_check [yyn] != token) - return - action_default [state]; - - return action_info [yyn]; - } -}; - - -const char *const JsonGrammar::spell [] = { - "end of file", "string", "number", "{", "}", "[", "]", ":", ",", "false", - "true", "null", "error", -#ifndef QLALR_NO_JSONGRAMMAR_DEBUG_INFO -"Root", "Value", "Object", "Members", "Array", "Values", "$accept" -#endif // QLALR_NO_JSONGRAMMAR_DEBUG_INFO -}; - -const short JsonGrammar::lhs [] = { - 13, 15, 16, 16, 16, 14, 14, 14, 14, 14, - 14, 14, 17, 18, 18, 18, 19}; - -const short JsonGrammar::rhs [] = { - 1, 3, 3, 5, 0, 1, 1, 1, 1, 1, - 1, 1, 3, 1, 3, 0, 2}; - - -#ifndef QLALR_NO_JSONGRAMMAR_DEBUG_INFO -const int JsonGrammar::rule_info [] = { - 13, 14 - , 15, 3, 16, 4 - , 16, 1, 7, 14 - , 16, 16, 8, 1, 7, 14 - , 16 - , 14, 9 - , 14, 10 - , 14, 11 - , 14, 15 - , 14, 17 - , 14, 2 - , 14, 1 - , 17, 5, 18, 6 - , 18, 14 - , 18, 18, 8, 14 - , 18 - , 19, 13, 0}; - -const int JsonGrammar::rule_index [] = { - 0, 2, 6, 10, 16, 17, 19, 21, 23, 25, - 27, 29, 31, 35, 37, 41, 42}; -#endif // QLALR_NO_JSONGRAMMAR_DEBUG_INFO - -const short JsonGrammar::action_default [] = { - 0, 10, 9, 0, 6, 5, 16, 8, 11, 12, - 7, 1, 17, 0, 0, 0, 2, 0, 0, 4, - 0, 3, 14, 0, 0, 13, 15}; - -const short JsonGrammar::goto_default [] = { - 3, 11, 2, 13, 1, 23, 0}; - -const short JsonGrammar::action_index [] = { - 24, -13, -13, 12, -13, -1, 24, -13, -13, -13, - -13, -13, -13, 1, -5, 2, -13, -6, 24, -13, - 24, -13, -13, -2, 24, -13, -13, - - -7, -7, -7, -7, -7, -7, 1, -7, -7, -7, - -7, -7, -7, -7, -7, -7, -7, -7, 0, -7, - -1, -7, -7, -7, 5, -7, -7}; - -const short JsonGrammar::action_info [] = { - 14, 18, 20, 17, 25, 16, 24, 0, 0, 15, - 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 9, 8, 5, 0, 6, - 0, 0, 0, 4, 10, 7, 0, - - 21, 19, 22, 0, 0, 0, 26, 0, 0, 0, - 0, 0}; - -const short JsonGrammar::action_check [] = { - 1, 7, 7, 1, 6, 4, 8, -1, -1, 8, - -1, -1, 0, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 1, 2, 3, -1, 5, - -1, -1, -1, 9, 10, 11, -1, - - 1, 1, 1, -1, -1, -1, 1, -1, -1, -1, - -1, -1}; - - -#line 29 "json.g" - -/**************************************************************************** -** -** Copyright (c) 2010 Girish Ramakrishnan -** Copyright (c) 2011 Denis Dzyubenko -** -** Use, modification and distribution is allowed without limitation, -** warranty, liability or support of any kind. -** -****************************************************************************/ - -#ifndef JSONPARSER_P_H -#define JSONPARSER_P_H - -#include -#include -#include - -class JsonLexer -{ -public: - JsonLexer(const QString &string); - ~JsonLexer(); - - int lex(); - QVariant symbol() const { return m_symbol; } - int lineNumber() const { return m_lineNumber; } - int pos() const { return m_pos; } - -private: - int parseNumber(); - int parseString(); - int parseKeyword(); - - QString m_strdata; - int m_lineNumber; - int m_pos; - QVariant m_symbol; -}; - -class JsonParser : protected JsonGrammar -{ -public: - JsonParser(); - ~JsonParser(); - - bool parse(JsonLexer *lex); - QVariant result() const { return m_result; } - QString errorMessage() const { return QString::fromLatin1("%1 at line %2 pos %3").arg(m_errorMessage).arg(m_errorLineNumber).arg(m_errorPos); } - -private: - void reallocateStack(); - - inline QVariant &sym(int index) - { return m_symStack[m_tos + index - 1]; } - inline QVariantMap &map(int index) - { return m_mapStack[m_tos + index - 1]; } - inline QVariantList &list(int index) - { return m_listStack[m_tos + index - 1]; } - - int m_tos; - QVector m_stateStack; - QVector m_symStack; - QVector m_mapStack; - QVector m_listStack; - QString m_errorMessage; - int m_errorLineNumber; - int m_errorPos; - QVariant m_result; -}; - -#endif // JSONPARSER_P_H - -#line 103 "json.g" - -/**************************************************************************** -** -** Copyright (c) 2010 Girish Ramakrishnan -** Copyright (c) 2011 Denis Dzyubenko -** -** Use, modification and distribution is allowed without limitation, -** warranty, liability or support of any kind. -** -****************************************************************************/ - -#include - -#define L1C(c) ushort(uchar(c)) - -JsonLexer::JsonLexer(const QString &str) - : m_strdata(str), m_lineNumber(1), m_pos(0) -{ -} - - - -JsonLexer::~JsonLexer() -{ -} - -int JsonLexer::parseString() -{ - bool esc = false; - ++m_pos; // skip initial " - int start = m_pos; - - const ushort *uc = m_strdata.utf16(); - const int remaining = m_strdata.length() - m_pos; - int i; - for (i = 0; i < remaining; ++i) { - const ushort c = uc[m_pos + i]; - if (c == L1C('\"')) { - m_symbol = QString((QChar *)uc + m_pos, i); - m_pos += i; - ++m_pos; // eat quote - return JsonGrammar::T_STRING; - } else if (c == L1C('\\')) { - ++m_pos; // eat backslash - esc = true; - break; - } - } - - QString str; - if (i) { - str.resize(i); - memcpy((char *)str.utf16(), uc + start, i * 2); - m_pos += i; - } - - for (; m_pos < m_strdata.length(); ++m_pos) { - const ushort c = uc[m_pos]; - if (esc) { - if (c == L1C('b')) str += QLatin1Char('\b'); - else if (c == L1C('f')) str += QLatin1Char('\f'); - else if (c == L1C('n')) str += QLatin1Char('\n'); - else if (c == L1C('r')) str += QLatin1Char('\r'); - else if (c == L1C('t')) str += QLatin1Char('\t'); - else if (c == L1C('\\')) str += QLatin1Char('\\'); - else if (c == L1C('\"')) str += QLatin1Char('\"'); - else if (c == L1C('u') && m_pos+4= L1C('0') && c <= L1C('9')) { - if (!isDouble) { - value *= 10; - value += c - L1C('0'); - } - continue; - } - break; - } - if (!isDouble) { - m_symbol = value * negative; - } else { - QString number = QString::fromRawData((QChar *)uc+start, m_pos-start); - m_symbol = number.toDouble(); - } - return JsonGrammar::T_NUMBER; -} - -int JsonLexer::parseKeyword() -{ - int start = m_pos; - for (; m_pos < m_strdata.length(); ++m_pos) { - const ushort c = m_strdata.at(m_pos).unicode(); - if (c >= L1C('a') && c <= L1C('z')) - continue; - break; - } - const ushort *k = (const ushort *)m_strdata.constData() + start; - const int l = m_pos-start; - if (l == 4) { - static const ushort true_data[] = { 't', 'r', 'u', 'e' }; - static const ushort null_data[] = { 'n', 'u', 'l', 'l' }; - if (!memcmp(k, true_data, 4 * sizeof(ushort))) - return JsonGrammar::T_TRUE; - if (!memcmp(k, null_data, 4 * sizeof(ushort))) - return JsonGrammar::T_NULL; - } else if (l == 5) { - static const ushort false_data[] = { 'f', 'a', 'l', 's', 'e' }; - if (!memcmp(k, false_data, 5 * sizeof(ushort))) - return JsonGrammar::T_FALSE; - } - return JsonGrammar::ERROR; -} - -int JsonLexer::lex() -{ - m_symbol.clear(); - - const ushort *uc = m_strdata.utf16(); - const int len = m_strdata.length(); - while (m_pos < len) { - const ushort c = uc[m_pos]; - switch (c) { - case L1C('['): ++m_pos; return JsonGrammar::T_LSQUAREBRACKET; - case L1C(']'): ++m_pos; return JsonGrammar::T_RSQUAREBRACKET; - case L1C('{'): ++m_pos; return JsonGrammar::T_LCURLYBRACKET; - case L1C('}'): ++m_pos; return JsonGrammar::T_RCURLYBRACKET; - case L1C(':'): ++m_pos; return JsonGrammar::T_COLON; - case L1C(','): ++m_pos; return JsonGrammar::T_COMMA; - case L1C(' '): case L1C('\r'): case L1C('\t'): ++m_pos; break; - case L1C('\n'): ++m_pos; ++m_lineNumber; break; - case L1C('"'): return parseString(); - default: - if (c == L1C('+') || c == L1C('-') || (c >= L1C('0') && c <= L1C('9'))) { - return parseNumber(); - } - if (c >= L1C('a') && c <= L1C('z')) { - return parseKeyword(); - } - return JsonGrammar::ERROR; - } - } - return JsonGrammar::EOF_SYMBOL; -} -#undef L1C - -JsonParser::JsonParser() - : m_tos(0) - , m_errorLineNumber(-1) - , m_errorPos(-1) -{ -} - -JsonParser::~JsonParser() -{ -} - -void JsonParser::reallocateStack() -{ - int size = m_stateStack.size(); - if (size == 0) - size = 128; - else - size <<= 1; - - m_symStack.resize(size); - m_mapStack.resize(size); - m_listStack.resize(size); - m_stateStack.resize(size); -} - -bool JsonParser::parse(JsonLexer *lexer) -{ - const int INITIAL_STATE = 0; - int yytoken = -1; - reallocateStack(); - m_tos = 0; - m_stateStack[++m_tos] = INITIAL_STATE; - - while (true) { - const int state = m_stateStack[m_tos]; - if (yytoken == -1 && -TERMINAL_COUNT != action_index[state]) { - yytoken = lexer->lex(); - } - int act = t_action(state, yytoken); - if (act == ACCEPT_STATE) - return true; - else if (act > 0) { - if (++m_tos == m_stateStack.size()) - reallocateStack(); - m_stateStack[m_tos] = act; - m_symStack[m_tos] = lexer->symbol(); - yytoken = -1; - } else if (act < 0) { - int r = -act-1; - m_tos -= rhs[r]; - act = m_stateStack.at(m_tos++); - switch (r) { - -#line 334 "json.g" - case 0: { m_result = sym(1); break; } -#line 337 "json.g" - case 1: { sym(1) = map(2); break; } -#line 340 "json.g" - case 2: { QVariantMap m; m.insert(sym(1).toString(), sym(3)); map(1) = m; break; } -#line 343 "json.g" - case 3: { map(1).insert(sym(3).toString(), sym(5)); break; } -#line 346 "json.g" - case 4: { map(1) = QVariantMap(); break; } -#line 349 "json.g" - case 5: { sym(1) = QVariant(false); break; } -#line 352 "json.g" - case 6: { sym(1) = QVariant(true); break; } -#line 361 "json.g" - case 12: { sym(1) = list(2); break; } -#line 364 "json.g" - case 13: { QVariantList l; l.append(sym(1)); list(1) = l; break; } -#line 367 "json.g" - case 14: { list(1).append(sym(3)); break; } -#line 370 "json.g" - case 15: { list(1) = QVariantList(); break; } -#line 372 "json.g" - - } // switch - m_stateStack[m_tos] = nt_action(act, lhs[r] - TERMINAL_COUNT); - } else { - int ers = state; - int shifts = 0; - int reduces = 0; - int expected_tokens[3]; - for (int tk = 0; tk < TERMINAL_COUNT; ++tk) { - int k = t_action(ers, tk); - - if (! k) - continue; - else if (k < 0) - ++reduces; - else if (spell[tk]) { - if (shifts < 3) - expected_tokens[shifts] = tk; - ++shifts; - } - } - - m_errorLineNumber = lexer->lineNumber(); - m_errorPos = lexer->pos(); - m_errorMessage.clear(); - if (shifts && shifts < 3) { - bool first = true; - - for (int s = 0; s < shifts; ++s) { - if (first) - m_errorMessage += QLatin1String("Expected "); - else - m_errorMessage += QLatin1String(", "); - - first = false; - m_errorMessage += QLatin1String("'"); - m_errorMessage += QLatin1String(spell[expected_tokens[s]]); - m_errorMessage += QLatin1String("'"); - } - } - return false; - } - } - - return false; -} - - -#endif // JSONPARSER_CPP - From 796fc5bb8cdb3d26fe229ee0391d0119a75a7a76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorbj=C3=B8rn=20Lindeijer?= Date: Wed, 12 Feb 2025 10:22:37 +0100 Subject: [PATCH 3/3] Code style tweaks Actual changes: * Make sure 'parent' is forwarded to superclass * Take 'WriteMinimized' option into account * Fixed some translatable strings with parameters --- src/plugins/rpd/rpdplugin.cpp | 189 ++++++++++++++-------------------- src/plugins/rpd/rpdplugin.h | 7 +- 2 files changed, 80 insertions(+), 116 deletions(-) diff --git a/src/plugins/rpd/rpdplugin.cpp b/src/plugins/rpd/rpdplugin.cpp index 5eb8179c26..b2e7fec5be 100644 --- a/src/plugins/rpd/rpdplugin.cpp +++ b/src/plugins/rpd/rpdplugin.cpp @@ -1,17 +1,17 @@ #include "rpdplugin.h" #include "maptovariantconverter.h" -#include "varianttomapconverter.h" -#include "savefile.h" #include "objectgroup.h" +#include "savefile.h" +#include "varianttomapconverter.h" #include "qjsonparser/json.h" #include #include +#include #include #include -#include #include #include @@ -23,59 +23,49 @@ void RpdPlugin::initialize() addObject(new RpdTilesetFormat(this)); } - RpdMapFormat::RpdMapFormat(SubFormat subFormat, QObject *parent) - : mSubFormat(subFormat) -{ - (void)parent; -} + : Tiled::WritableMapFormat(parent) + , mSubFormat(subFormat) +{} -QString RpdMapFormat::shortName(void) const +QString RpdMapFormat::shortName() const { return "RPD"; } -QJsonArray packMapData(Tiled::Layer *layer) +static QJsonArray packMapData(Tiled::TileLayer *layer) { QJsonArray map; - for(int j=0;jmap()->height();++j){ - for(int i=0;imap()->width();++i){ - map.append(layer->asTileLayer()->cellAt(i,j).tileId()); - } - } + for (int j = 0; j < layer->map()->height(); ++j) + for (int i = 0; i < layer->map()->width(); ++i) + map.append(layer->cellAt(i, j).tileId()); return map; } -bool RpdMapFormat::insertTilesetFile(Tiled::Layer &layer, const QString &tiles_name, QJsonObject &mapJson) +bool RpdMapFormat::insertTilesetFile(Tiled::Layer &layer, + const QString &tiles_name, + QJsonObject &mapJson) { - auto tilesets = layer.asTileLayer()->usedTilesets(); + const auto tilesets = layer.usedTilesets(); - if(tilesets.size()==0) { - QString msg = QString("You have ")+layer.name()+" layer please fill it"; - mError = tr(msg.toUtf8()); + if (tilesets.isEmpty()) { + mError = tr("You have an empty %1 layer, please fill it").arg(layer.name()); return false; } - if(tilesets.size()>1) { - QString msg = QString("Only one tileset per layer supported (")+layer.name()+" layer) ->\n"; - for(auto tileset: tilesets) { - msg += "[" + tileset->name() + "]\n"; - } - mError = tr(msg.toUtf8()); + if (tilesets.size() > 1) { + mError = tr("Only one tileset per layer supported (%1 layer) ->\n").arg(layer.name()); + for (const auto &tileset : tilesets) + mError += "[" + tileset->name() + "]\n"; return false; } - mapJson.insert(tiles_name,tilesets.begin()->data()->name()+".png"); + mapJson.insert(tiles_name, tilesets.begin()->data()->name() + ".png"); return true; } - - - bool RpdMapFormat::write(const Tiled::Map *map, const QString &fileName, Options options) { - (void)fileName; - (void)options; Tiled::SaveFile file(fileName); if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { @@ -85,43 +75,41 @@ bool RpdMapFormat::write(const Tiled::Map *map, const QString &fileName, Options QJsonObject mapJson; - for(const auto& property : map->properties().toStdMap()) { - QVariant value = property.second; - if(value.canConvert()) { - mapJson.insert(property.first, value.toDouble()); - continue; + for (const auto &[key, value] : map->properties().toStdMap()) { + if (value.canConvert()) { + mapJson.insert(key, value.toDouble()); + continue; } - if(value.canConvert()) { - mapJson.insert(property.first, value.toString()); + if (value.canConvert()) { + mapJson.insert(key, value.toString()); continue; } - mError = tr("Dont know what to do with property (%1)").arg(property.first); + mError = tr("Dont know what to do with property (%1)").arg(key); return false; } - for(Tiled::Layer *layer: map->layers()) { - - if(layer->layerType()==Tiled::Layer::TileLayerType && !insertTilesetFile(*layer,QString("tiles_")+layer->name(),mapJson)) { + for (Tiled::Layer *layer : map->layers()) { + if (layer->layerType() == Tiled::Layer::TileLayerType + && !insertTilesetFile(*layer, QString("tiles_") + layer->name(), mapJson)) { return false; } - if(layer->name()=="logic") { - + if (layer->name() == "logic") { QJsonArray entrance; QJsonArray multiexit; - mapJson.insert("width",layer->map()->width()); - mapJson.insert("height",layer->map()->height()); + mapJson.insert("width", layer->map()->width()); + mapJson.insert("height", layer->map()->height()); - mapJson.insert("map",packMapData(layer)); + mapJson.insert("map", packMapData(layer->asTileLayer())); - for(int i=0;imap()->width();++i){ - for(int j=0;jmap()->height();++j){ - int tileId = layer->asTileLayer()->cellAt(i,j).tileId(); + for (int i = 0; i < layer->map()->width(); ++i) { + for (int j = 0; j < layer->map()->height(); ++j) { + int tileId = layer->asTileLayer()->cellAt(i, j).tileId(); - if(tileId<0) { + if (tileId < 0) { mError = tr("Hole in logic layer at (%1, %2)").arg(i).arg(j); return false; } @@ -133,45 +121,38 @@ bool RpdMapFormat::write(const Tiled::Map *map, const QString &fileName, Options break; case TileId::EXIT: case TileId::LOCKED_EXIT: - case TileId::UNLOCKED_EXIT: - { + case TileId::UNLOCKED_EXIT: { QJsonArray exit; exit.append(i); exit.append(j); multiexit.append(exit); - } - break; + } break; } } } - mapJson.insert("entrance",entrance); - mapJson.insert("multiexit",multiexit); + mapJson.insert("entrance", entrance); + mapJson.insert("multiexit", multiexit); } - if(layer->name() == "base") { - mapJson.insert("baseTileVar",packMapData(layer)); - } + if (layer->name() == "base") + mapJson.insert("baseTileVar", packMapData(layer->asTileLayer())); - if(layer->name() == "deco2") { - mapJson.insert("deco2TileVar",packMapData(layer)); - } + if (layer->name() == "deco2") + mapJson.insert("deco2TileVar", packMapData(layer->asTileLayer())); - if(layer->name() == "roof_base") { - mapJson.insert("roofBaseTileVar",packMapData(layer)); - } + if (layer->name() == "roof_base") + mapJson.insert("roofBaseTileVar", packMapData(layer->asTileLayer())); - if(layer->name() == "roof_deco") { - mapJson.insert("roofDecoTileVar",packMapData(layer)); - } + if (layer->name() == "roof_deco") + mapJson.insert("roofDecoTileVar", packMapData(layer->asTileLayer())); - if(layer->name() == "deco") { - mapJson.insert("decoTileVar",packMapData(layer)); - mapJson.insert("customTiles",true); + if (layer->name() == "deco") { + mapJson.insert("decoTileVar", packMapData(layer->asTileLayer())); + mapJson.insert("customTiles", true); - if(!insertTilesetFile(*layer,"tiles",mapJson)) { + if (!insertTilesetFile(*layer, "tiles", mapJson)) return false; - } QJsonArray decoDesc; QJsonArray decoName; @@ -189,60 +170,50 @@ bool RpdMapFormat::write(const Tiled::Map *map, const QString &fileName, Options ++it; } - mapJson.insert("decoName",decoName); - mapJson.insert("decoDesc",decoDesc); + mapJson.insert("decoName", decoName); + mapJson.insert("decoDesc", decoDesc); } - if(layer->name()=="objects") { - + if (layer->name() == "objects") { QMap objects; for (auto object : layer->asObjectGroup()->objects()) { - QJsonObject desc; - desc.insert("kind",object->name()); + desc.insert("kind", object->name()); - desc.insert("x",qFloor(object->x()/16.)); - desc.insert("y",qFloor(object->y()/16.)); + desc.insert("x", qFloor(object->x() / 16.)); + desc.insert("y", qFloor(object->y() / 16.)); auto properties = object->properties(); for (auto i = properties.begin(); i != properties.end(); ++i) { - auto jsonCandidate = QJsonDocument::fromJson(i.value().toString().toUtf8()); - if(jsonCandidate.isObject()) { - desc.insert(i.key(),jsonCandidate.object()); + if (jsonCandidate.isObject()) { + desc.insert(i.key(), jsonCandidate.object()); continue; } - desc.insert(i.key(),i.value().toJsonValue()); + desc.insert(i.key(), i.value().toJsonValue()); } objects[object->type()].append(desc); } - for (auto key : objects.keys() ) { + for (auto key : objects.keys()) mapJson.insert(key + "s", objects[key]); - } } } - if(!mapJson.contains("tiles")){ - mapJson.insert("tiles","tiles0_x.png"); - } - - mapJson.insert("water","water0.png"); - - QJsonDocument mapDoc; - mapDoc.setObject(mapJson); + if (!mapJson.contains("tiles")) + mapJson.insert("tiles", "tiles0_x.png"); - QVariant variant = mapDoc.toVariant(); + mapJson.insert("water", "water0.png"); JsonWriter writer; - writer.setAutoFormatting(true); + writer.setAutoFormatting(!options.testFlag(WriteMinimized)); - if (!writer.stringify(variant)) { + if (!writer.stringify(QJsonDocument(mapJson).toVariant())) { // This can only happen due to coding error mError = writer.errorString(); return false; @@ -276,30 +247,24 @@ QString RpdMapFormat::errorString() const return mError; } - RpdTilesetFormat::RpdTilesetFormat(QObject *parent) : Tiled::TilesetFormat(parent) -{ -} +{} Tiled::SharedTileset RpdTilesetFormat::read(const QString &fileName) { - (void)fileName; + Q_UNUSED(fileName) return Tiled::SharedTileset(); } bool RpdTilesetFormat::supportsFile(const QString &fileName) const { - (void)fileName; + Q_UNUSED(fileName) return false; } -bool RpdTilesetFormat::write(const Tiled::Tileset &tileset, - const QString &fileName, - Options options) +bool RpdTilesetFormat::write(const Tiled::Tileset &tileset, const QString &fileName, Options options) { - (void)fileName; - (void)options; Tiled::SaveFile file(fileName); if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { @@ -311,7 +276,7 @@ bool RpdTilesetFormat::write(const Tiled::Tileset &tileset, QVariant variant = converter.toVariant(tileset, QFileInfo(fileName).dir()); JsonWriter writer; - writer.setAutoFormatting(true); + writer.setAutoFormatting(!options.testFlag(WriteMinimized)); if (!writer.stringify(variant)) { // This can only happen due to coding error @@ -346,7 +311,7 @@ QString RpdTilesetFormat::errorString() const return mError; } -QString RpdTilesetFormat::shortName(void) const +QString RpdTilesetFormat::shortName() const { return "RPD"; } diff --git a/src/plugins/rpd/rpdplugin.h b/src/plugins/rpd/rpdplugin.h index bfc1fdc312..1511c39c91 100644 --- a/src/plugins/rpd/rpdplugin.h +++ b/src/plugins/rpd/rpdplugin.h @@ -46,18 +46,17 @@ class RPDSHARED_EXPORT RpdMapFormat : public Tiled::WritableMapFormat explicit RpdMapFormat(SubFormat subFormat, QObject *parent = nullptr); - bool write(const Tiled::Map *map, const QString &fileName, Options options = Options()) override; - QString shortName(void) const override; + QString shortName() const override; QString nameFilter() const override; QString errorString() const override; protected: QString mError; SubFormat mSubFormat; + private: bool insertTilesetFile(Tiled::Layer &layer, const QString &tiles_name, QJsonObject &mapJson); - }; @@ -74,7 +73,7 @@ class RPDSHARED_EXPORT RpdTilesetFormat : public Tiled::TilesetFormat bool write(const Tiled::Tileset &tileset, const QString &fileName, Options options = Options()) override; - QString shortName(void) const override; + QString shortName() const override; QString nameFilter() const override; QString errorString() const override;