diff --git a/include/core/events.h b/include/core/events.h index fc0b90d8..22b76434 100644 --- a/include/core/events.h +++ b/include/core/events.h @@ -10,6 +10,7 @@ #include #include "orderedjson.h" +#include "parseutil.h" class Project; @@ -139,15 +140,14 @@ public: Event::Type getEventType() const { return this->eventType; } virtual OrderedJson::object buildEventJson(Project *project) = 0; - virtual bool loadFromJson(const QJsonObject &json, Project *project) = 0; + virtual bool loadFromJson(QJsonObject json, Project *project) = 0; virtual void setDefaultValues(Project *project); virtual QSet getExpectedFields() = 0; - void readCustomAttributes(const QJsonObject &json); - void addCustomAttributesTo(OrderedJson::object *obj) const; - const QMap getCustomAttributes() const { return this->customAttributes; } - void setCustomAttributes(const QMap newCustomAttributes) { this->customAttributes = newCustomAttributes; } + + QJsonObject getCustomAttributes() const { return this->customAttributes; } + void setCustomAttributes(const QJsonObject &newCustomAttributes) { this->customAttributes = newCustomAttributes; } virtual void loadPixmap(Project *project); @@ -190,12 +190,16 @@ protected: // When deleting events like this we want to warn the user that the #define may also be deleted. QString idName; - QMap customAttributes; + QJsonObject customAttributes; QPixmap pixmap; DraggablePixmapItem *pixmapItem = nullptr; QPointer eventFrame; + + static QString readString(QJsonObject *object, const QString &key) { return ParseUtil::jsonToQString(object->take(key)); } + static int readInt(QJsonObject *object, const QString &key) { return ParseUtil::jsonToInt(object->take(key)); } + static bool readBool(QJsonObject *object, const QString &key) { return ParseUtil::jsonToBool(object->take(key)); } }; @@ -218,7 +222,7 @@ public: virtual EventFrame *createEventFrame() override; virtual OrderedJson::object buildEventJson(Project *project) override; - virtual bool loadFromJson(const QJsonObject &json, Project *project) override; + virtual bool loadFromJson(QJsonObject json, Project *project) override; virtual void setDefaultValues(Project *project) override; @@ -285,7 +289,7 @@ public: virtual EventFrame *createEventFrame() override; virtual OrderedJson::object buildEventJson(Project *project) override; - virtual bool loadFromJson(const QJsonObject &json, Project *project) override; + virtual bool loadFromJson(QJsonObject json, Project *project) override; virtual void setDefaultValues(Project *project) override; @@ -323,7 +327,7 @@ public: virtual EventFrame *createEventFrame() override; virtual OrderedJson::object buildEventJson(Project *project) override; - virtual bool loadFromJson(const QJsonObject &json, Project *project) override; + virtual bool loadFromJson(QJsonObject json, Project *project) override; virtual void setDefaultValues(Project *project) override; @@ -358,7 +362,7 @@ public: virtual EventFrame *createEventFrame() override = 0; virtual OrderedJson::object buildEventJson(Project *project) override = 0; - virtual bool loadFromJson(const QJsonObject &json, Project *project) override = 0; + virtual bool loadFromJson(QJsonObject json, Project *project) override = 0; virtual void setDefaultValues(Project *project) override = 0; @@ -386,7 +390,7 @@ public: virtual EventFrame *createEventFrame() override; virtual OrderedJson::object buildEventJson(Project *project) override; - virtual bool loadFromJson(const QJsonObject &json, Project *project) override; + virtual bool loadFromJson(QJsonObject json, Project *project) override; virtual void setDefaultValues(Project *project) override; @@ -426,7 +430,7 @@ public: virtual EventFrame *createEventFrame() override; virtual OrderedJson::object buildEventJson(Project *project) override; - virtual bool loadFromJson(const QJsonObject &json, Project *project) override; + virtual bool loadFromJson(QJsonObject json, Project *project) override; virtual void setDefaultValues(Project *project) override; @@ -457,7 +461,7 @@ public: virtual EventFrame *createEventFrame() override = 0; virtual OrderedJson::object buildEventJson(Project *project) override = 0; - virtual bool loadFromJson(const QJsonObject &json, Project *project) override = 0; + virtual bool loadFromJson(QJsonObject json, Project *project) override = 0; virtual void setDefaultValues(Project *project) override = 0; @@ -484,7 +488,7 @@ public: virtual EventFrame *createEventFrame() override; virtual OrderedJson::object buildEventJson(Project *project) override; - virtual bool loadFromJson(const QJsonObject &json, Project *project) override; + virtual bool loadFromJson(QJsonObject json, Project *project) override; virtual void setDefaultValues(Project *project) override; @@ -519,7 +523,7 @@ public: virtual EventFrame *createEventFrame() override; virtual OrderedJson::object buildEventJson(Project *project) override; - virtual bool loadFromJson(const QJsonObject &json, Project *project) override; + virtual bool loadFromJson(QJsonObject json, Project *project) override; virtual void setDefaultValues(Project *project) override; @@ -564,7 +568,7 @@ public: virtual EventFrame *createEventFrame() override; virtual OrderedJson::object buildEventJson(Project *project) override; - virtual bool loadFromJson(const QJsonObject &json, Project *project) override; + virtual bool loadFromJson(QJsonObject json, Project *project) override; virtual void setDefaultValues(Project *project) override; @@ -596,12 +600,15 @@ public: virtual EventFrame *createEventFrame() override; virtual OrderedJson::object buildEventJson(Project *project) override; - virtual bool loadFromJson(const QJsonObject &, Project *) override; + virtual bool loadFromJson(QJsonObject json, Project *project) override; virtual void setDefaultValues(Project *project) override; virtual QSet getExpectedFields() override; + void setHostMapName(QString newHostMapName) { this->hostMapName = newHostMapName; } + QString getHostMapName() const; + void setRespawnMapName(QString newRespawnMapName) { this->respawnMapName = newRespawnMapName; } QString getRespawnMapName() const { return this->respawnMapName; } @@ -611,6 +618,7 @@ public: private: QString respawnMapName; QString respawnNPC; + QString hostMapName; // Only needed if the host map fails to load. }; diff --git a/include/core/map.h b/include/core/map.h index c1a14b04..c2078134 100644 --- a/include/core/map.h +++ b/include/core/map.h @@ -100,8 +100,8 @@ public: bool hasUnsavedChanges() const; void pruneEditHistory(); - void setCustomAttributes(const QMap &attributes) { m_customAttributes = attributes; } - QMap customAttributes() const { return m_customAttributes; } + void setCustomAttributes(const QJsonObject &attributes) { m_customAttributes = attributes; } + QJsonObject customAttributes() const { return m_customAttributes; } private: QString m_name; @@ -110,7 +110,7 @@ private: QString m_sharedScriptsMap = ""; QStringList m_scriptsFileLabels; - QMap m_customAttributes; + QJsonObject m_customAttributes; MapHeader *m_header = nullptr; Layout *m_layout = nullptr; diff --git a/include/lib/orderedjson.h b/include/lib/orderedjson.h index 544112f1..73422a2b 100644 --- a/include/lib/orderedjson.h +++ b/include/lib/orderedjson.h @@ -132,7 +132,9 @@ public: int>::type = 0> Json(const V & v) : Json(array(v.begin(), v.end())) {} - static const Json fromQJsonValue(QJsonValue value); + static Json fromQJsonValue(const QJsonValue &value); + static void append(Json::array *array, const QJsonArray &qArray); + static void append(Json::object *object, const QJsonObject &qObject); // This prevents Json(some_pointer) from accidentally producing a bool. Use // Json(bool(some_pointer)) if that behavior is desired. diff --git a/include/project.h b/include/project.h index 44094aaa..5f37c5e7 100644 --- a/include/project.h +++ b/include/project.h @@ -164,7 +164,7 @@ public: void initTopLevelMapFields(); bool readMapJson(const QString &mapName, QJsonDocument * out); - bool loadMapEvent(Map *map, const QJsonObject &json, Event::Type defaultType = Event::Type::None); + bool loadMapEvent(Map *map, QJsonObject json, Event::Type defaultType = Event::Type::None); bool loadMapData(Map*); bool readMapLayouts(); Layout *loadLayout(QString layoutId); diff --git a/include/ui/customattributestable.h b/include/ui/customattributestable.h index 21cac4de..780f441d 100644 --- a/include/ui/customattributestable.h +++ b/include/ui/customattributestable.h @@ -13,8 +13,8 @@ public: explicit CustomAttributesTable(QWidget *parent = nullptr); ~CustomAttributesTable() {}; - QMap getAttributes() const; - void setAttributes(const QMap &attributes); + QJsonObject getAttributes() const; + void setAttributes(const QJsonObject &attributes); void addNewAttribute(const QString &key, const QJsonValue &value); bool deleteSelectedAttributes(); diff --git a/src/core/events.cpp b/src/core/events.cpp index f9828dc1..ebb1ac49 100644 --- a/src/core/events.cpp +++ b/src/core/events.cpp @@ -51,24 +51,6 @@ void Event::setDefaultValues(Project *) { this->setElevation(projectConfig.defaultElevation); } -void Event::readCustomAttributes(const QJsonObject &json) { - this->customAttributes.clear(); - const QSet expectedFields = this->getExpectedFields(); - for (auto i = json.constBegin(); i != json.constEnd(); i++) { - if (!expectedFields.contains(i.key())) { - this->customAttributes[i.key()] = i.value(); - } - } -} - -void Event::addCustomAttributesTo(OrderedJson::object *obj) const { - for (auto i = this->customAttributes.constBegin(); i != this->customAttributes.constEnd(); i++) { - if (!obj->contains(i.key())) { - (*obj)[i.key()] = OrderedJson::fromQJsonValue(i.value()); - } - } -} - void Event::modify() { this->map->modify(); } @@ -181,27 +163,26 @@ OrderedJson::object ObjectEvent::buildEventJson(Project *) { objectJson["trainer_sight_or_berry_tree_id"] = this->getSightRadiusBerryTreeID(); objectJson["script"] = this->getScript(); objectJson["flag"] = this->getFlag(); - this->addCustomAttributesTo(&objectJson); + OrderedJson::append(&objectJson, this->getCustomAttributes()); return objectJson; } -bool ObjectEvent::loadFromJson(const QJsonObject &json, Project *) { - this->setX(ParseUtil::jsonToInt(json["x"])); - this->setY(ParseUtil::jsonToInt(json["y"])); - this->setElevation(ParseUtil::jsonToInt(json["elevation"])); - this->setIdName(ParseUtil::jsonToQString(json["local_id"])); - this->setGfx(ParseUtil::jsonToQString(json["graphics_id"])); - this->setMovement(ParseUtil::jsonToQString(json["movement_type"])); - this->setRadiusX(ParseUtil::jsonToInt(json["movement_range_x"])); - this->setRadiusY(ParseUtil::jsonToInt(json["movement_range_y"])); - this->setTrainerType(ParseUtil::jsonToQString(json["trainer_type"])); - this->setSightRadiusBerryTreeID(ParseUtil::jsonToQString(json["trainer_sight_or_berry_tree_id"])); - this->setScript(ParseUtil::jsonToQString(json["script"])); - this->setFlag(ParseUtil::jsonToQString(json["flag"])); +bool ObjectEvent::loadFromJson(QJsonObject json, Project *) { + this->setX(readInt(&json, "x")); + this->setY(readInt(&json, "y")); + this->setElevation(readInt(&json, "elevation")); + this->setIdName(readString(&json, "local_id")); + this->setGfx(readString(&json, "graphics_id")); + this->setMovement(readString(&json, "movement_type")); + this->setRadiusX(readInt(&json, "movement_range_x")); + this->setRadiusY(readInt(&json, "movement_range_y")); + this->setTrainerType(readString(&json, "trainer_type")); + this->setSightRadiusBerryTreeID(readString(&json, "trainer_sight_or_berry_tree_id")); + this->setScript(readString(&json, "script")); + this->setFlag(readString(&json, "flag")); - this->readCustomAttributes(json); - + this->setCustomAttributes(json); return true; } @@ -216,26 +197,24 @@ void ObjectEvent::setDefaultValues(Project *project) { this->setSightRadiusBerryTreeID("0"); } -const QSet expectedObjectFields = { - "local_id", - "graphics_id", - "elevation", - "movement_type", - "movement_range_x", - "movement_range_y", - "trainer_type", - "trainer_sight_or_berry_tree_id", - "script", - "flag", -}; - QSet ObjectEvent::getExpectedFields() { - QSet expectedFields = QSet(); - expectedFields = expectedObjectFields; + QSet expectedFields = { + "x", + "y", + "local_id", + "graphics_id", + "elevation", + "movement_type", + "movement_range_x", + "movement_range_y", + "trainer_type", + "trainer_sight_or_berry_tree_id", + "script", + "flag", + }; if (projectConfig.eventCloneObjectEnabled) { expectedFields.insert("type"); } - expectedFields << "x" << "y"; return expectedFields; } @@ -286,26 +265,25 @@ OrderedJson::object CloneObjectEvent::buildEventJson(Project *project) { cloneJson["target_local_id"] = this->getTargetID(); const QString mapName = this->getTargetMap(); cloneJson["target_map"] = project->getMapConstant(mapName, mapName); - this->addCustomAttributesTo(&cloneJson); + OrderedJson::append(&cloneJson, this->getCustomAttributes()); return cloneJson; } -bool CloneObjectEvent::loadFromJson(const QJsonObject &json, Project *project) { - this->setX(ParseUtil::jsonToInt(json["x"])); - this->setY(ParseUtil::jsonToInt(json["y"])); - this->setIdName(ParseUtil::jsonToQString(json["local_id"])); - this->setGfx(ParseUtil::jsonToQString(json["graphics_id"])); - this->setTargetID(ParseUtil::jsonToInt(json["target_local_id"])); +bool CloneObjectEvent::loadFromJson(QJsonObject json, Project *project) { + this->setX(readInt(&json, "x")); + this->setY(readInt(&json, "y")); + this->setIdName(readString(&json, "local_id")); + this->setGfx(readString(&json, "graphics_id")); + this->setTargetID(readInt(&json, "target_local_id")); // Log a warning if "target_map" isn't a known map ID, but don't overwrite user data. - const QString mapConstant = ParseUtil::jsonToQString(json["target_map"]); + const QString mapConstant = readString(&json, "target_map"); if (!project->mapConstantsToMapNames.contains(mapConstant)) logWarn(QString("Unknown Target Map constant '%1'.").arg(mapConstant)); this->setTargetMap(project->mapConstantsToMapNames.value(mapConstant, mapConstant)); - this->readCustomAttributes(json); - + this->setCustomAttributes(json); return true; } @@ -315,18 +293,16 @@ void CloneObjectEvent::setDefaultValues(Project *project) { if (this->getMap()) this->setTargetMap(this->getMap()->name()); } -const QSet expectedCloneObjectFields = { - "type", - "local_id", - "graphics_id", - "target_local_id", - "target_map", -}; - QSet CloneObjectEvent::getExpectedFields() { - QSet expectedFields = QSet(); - expectedFields = expectedCloneObjectFields; - expectedFields << "x" << "y"; + static const QSet expectedFields = { + "x", + "y", + "type", + "local_id", + "graphics_id", + "target_local_id", + "target_map", + }; return expectedFields; } @@ -383,25 +359,23 @@ OrderedJson::object WarpEvent::buildEventJson(Project *project) { warpJson["dest_map"] = project->getMapConstant(mapName, mapName); warpJson["dest_warp_id"] = this->getDestinationWarpID(); - this->addCustomAttributesTo(&warpJson); - + OrderedJson::append(&warpJson, this->getCustomAttributes()); return warpJson; } -bool WarpEvent::loadFromJson(const QJsonObject &json, Project *project) { - this->setX(ParseUtil::jsonToInt(json["x"])); - this->setY(ParseUtil::jsonToInt(json["y"])); - this->setElevation(ParseUtil::jsonToInt(json["elevation"])); - this->setDestinationWarpID(ParseUtil::jsonToQString(json["dest_warp_id"])); +bool WarpEvent::loadFromJson(QJsonObject json, Project *project) { + this->setX(readInt(&json, "x")); + this->setY(readInt(&json, "y")); + this->setElevation(readInt(&json, "elevation")); + this->setDestinationWarpID(readString(&json, "dest_warp_id")); // Log a warning if "dest_map" isn't a known map ID, but don't overwrite user data. - const QString mapConstant = ParseUtil::jsonToQString(json["dest_map"]); + const QString mapConstant = readString(&json, "dest_map"); if (!project->mapConstantsToMapNames.contains(mapConstant)) logWarn(QString("Unknown Destination Map constant '%1'.").arg(mapConstant)); this->setDestinationMap(project->mapConstantsToMapNames.value(mapConstant, mapConstant)); - this->readCustomAttributes(json); - + this->setCustomAttributes(json); return true; } @@ -411,16 +385,14 @@ void WarpEvent::setDefaultValues(Project *) { this->setElevation(0); } -const QSet expectedWarpFields = { - "elevation", - "dest_map", - "dest_warp_id", -}; - QSet WarpEvent::getExpectedFields() { - QSet expectedFields = QSet(); - expectedFields = expectedWarpFields; - expectedFields << "x" << "y"; + static const QSet expectedFields = { + "x", + "y", + "elevation", + "dest_map", + "dest_warp_id", + }; return expectedFields; } @@ -466,21 +438,19 @@ OrderedJson::object TriggerEvent::buildEventJson(Project *) { triggerJson["var_value"] = this->getScriptVarValue(); triggerJson["script"] = this->getScriptLabel(); - this->addCustomAttributesTo(&triggerJson); - + OrderedJson::append(&triggerJson, this->getCustomAttributes()); return triggerJson; } -bool TriggerEvent::loadFromJson(const QJsonObject &json, Project *) { - this->setX(ParseUtil::jsonToInt(json["x"])); - this->setY(ParseUtil::jsonToInt(json["y"])); - this->setElevation(ParseUtil::jsonToInt(json["elevation"])); - this->setScriptVar(ParseUtil::jsonToQString(json["var"])); - this->setScriptVarValue(ParseUtil::jsonToQString(json["var_value"])); - this->setScriptLabel(ParseUtil::jsonToQString(json["script"])); - - this->readCustomAttributes(json); +bool TriggerEvent::loadFromJson(QJsonObject json, Project *) { + this->setX(readInt(&json, "x")); + this->setY(readInt(&json, "y")); + this->setElevation(readInt(&json, "elevation")); + this->setScriptVar(readString(&json, "var")); + this->setScriptVarValue(readString(&json, "var_value")); + this->setScriptLabel(readString(&json, "script")); + this->setCustomAttributes(json); return true; } @@ -491,18 +461,16 @@ void TriggerEvent::setDefaultValues(Project *project) { this->setElevation(0); } -const QSet expectedTriggerFields = { - "type", - "elevation", - "var", - "var_value", - "script", -}; - QSet TriggerEvent::getExpectedFields() { - QSet expectedFields = QSet(); - expectedFields = expectedTriggerFields; - expectedFields << "x" << "y"; + static const QSet expectedFields = { + "x", + "y", + "type", + "elevation", + "var", + "var_value", + "script", + }; return expectedFields; } @@ -538,19 +506,17 @@ OrderedJson::object WeatherTriggerEvent::buildEventJson(Project *) { weatherJson["elevation"] = this->getElevation(); weatherJson["weather"] = this->getWeather(); - this->addCustomAttributesTo(&weatherJson); - + OrderedJson::append(&weatherJson, this->getCustomAttributes()); return weatherJson; } -bool WeatherTriggerEvent::loadFromJson(const QJsonObject &json, Project *) { - this->setX(ParseUtil::jsonToInt(json["x"])); - this->setY(ParseUtil::jsonToInt(json["y"])); - this->setElevation(ParseUtil::jsonToInt(json["elevation"])); - this->setWeather(ParseUtil::jsonToQString(json["weather"])); - - this->readCustomAttributes(json); +bool WeatherTriggerEvent::loadFromJson(QJsonObject json, Project *) { + this->setX(readInt(&json, "x")); + this->setY(readInt(&json, "y")); + this->setElevation(readInt(&json, "elevation")); + this->setWeather(readString(&json, "weather")); + this->setCustomAttributes(json); return true; } @@ -559,16 +525,14 @@ void WeatherTriggerEvent::setDefaultValues(Project *project) { this->setElevation(0); } -const QSet expectedWeatherTriggerFields = { - "type", - "elevation", - "weather", -}; - QSet WeatherTriggerEvent::getExpectedFields() { - QSet expectedFields = QSet(); - expectedFields = expectedWeatherTriggerFields; - expectedFields << "x" << "y"; + static const QSet expectedFields = { + "x", + "y", + "type", + "elevation", + "weather", + }; return expectedFields; } @@ -606,20 +570,18 @@ OrderedJson::object SignEvent::buildEventJson(Project *) { signJson["player_facing_dir"] = this->getFacingDirection(); signJson["script"] = this->getScriptLabel(); - this->addCustomAttributesTo(&signJson); - + OrderedJson::append(&signJson, this->getCustomAttributes()); return signJson; } -bool SignEvent::loadFromJson(const QJsonObject &json, Project *) { - this->setX(ParseUtil::jsonToInt(json["x"])); - this->setY(ParseUtil::jsonToInt(json["y"])); - this->setElevation(ParseUtil::jsonToInt(json["elevation"])); - this->setFacingDirection(ParseUtil::jsonToQString(json["player_facing_dir"])); - this->setScriptLabel(ParseUtil::jsonToQString(json["script"])); - - this->readCustomAttributes(json); +bool SignEvent::loadFromJson(QJsonObject json, Project *) { + this->setX(readInt(&json, "x")); + this->setY(readInt(&json, "y")); + this->setElevation(readInt(&json, "elevation")); + this->setFacingDirection(readString(&json, "player_facing_dir")); + this->setScriptLabel(readString(&json, "script")); + this->setCustomAttributes(json); return true; } @@ -629,17 +591,15 @@ void SignEvent::setDefaultValues(Project *project) { this->setElevation(0); } -const QSet expectedSignFields = { - "type", - "elevation", - "player_facing_dir", - "script", -}; - QSet SignEvent::getExpectedFields() { - QSet expectedFields = QSet(); - expectedFields = expectedSignFields; - expectedFields << "x" << "y"; + static const QSet expectedFields = { + "x", + "y", + "type", + "elevation", + "player_facing_dir", + "script", + }; return expectedFields; } @@ -685,26 +645,24 @@ OrderedJson::object HiddenItemEvent::buildEventJson(Project *) { hiddenItemJson["underfoot"] = this->getUnderfoot(); } - this->addCustomAttributesTo(&hiddenItemJson); - + OrderedJson::append(&hiddenItemJson, this->getCustomAttributes()); return hiddenItemJson; } -bool HiddenItemEvent::loadFromJson(const QJsonObject &json, Project *) { - this->setX(ParseUtil::jsonToInt(json["x"])); - this->setY(ParseUtil::jsonToInt(json["y"])); - this->setElevation(ParseUtil::jsonToInt(json["elevation"])); - this->setItem(ParseUtil::jsonToQString(json["item"])); - this->setFlag(ParseUtil::jsonToQString(json["flag"])); +bool HiddenItemEvent::loadFromJson(QJsonObject json, Project *) { + this->setX(readInt(&json, "x")); + this->setY(readInt(&json, "y")); + this->setElevation(readInt(&json, "elevation")); + this->setItem(readString(&json, "item")); + this->setFlag(readString(&json, "flag")); if (projectConfig.hiddenItemQuantityEnabled) { - this->setQuantity(ParseUtil::jsonToInt(json["quantity"])); + this->setQuantity(readInt(&json, "quantity")); } if (projectConfig.hiddenItemRequiresItemfinderEnabled) { - this->setUnderfoot(ParseUtil::jsonToBool(json["underfoot"])); + this->setUnderfoot(readBool(&json, "underfoot")); } - this->readCustomAttributes(json); - + this->setCustomAttributes(json); return true; } @@ -719,23 +677,21 @@ void HiddenItemEvent::setDefaultValues(Project *project) { } } -const QSet expectedHiddenItemFields = { - "type", - "elevation", - "item", - "flag", -}; - QSet HiddenItemEvent::getExpectedFields() { - QSet expectedFields = QSet(); - expectedFields = expectedHiddenItemFields; + QSet expectedFields = { + "x", + "y", + "type", + "elevation", + "item", + "flag", + }; if (projectConfig.hiddenItemQuantityEnabled) { expectedFields << "quantity"; } if (projectConfig.hiddenItemRequiresItemfinderEnabled) { expectedFields << "underfoot"; } - expectedFields << "x" << "y"; return expectedFields; } @@ -771,19 +727,17 @@ OrderedJson::object SecretBaseEvent::buildEventJson(Project *) { secretBaseJson["elevation"] = this->getElevation(); secretBaseJson["secret_base_id"] = this->getBaseID(); - this->addCustomAttributesTo(&secretBaseJson); - + OrderedJson::append(&secretBaseJson, this->getCustomAttributes()); return secretBaseJson; } -bool SecretBaseEvent::loadFromJson(const QJsonObject &json, Project *) { - this->setX(ParseUtil::jsonToInt(json["x"])); - this->setY(ParseUtil::jsonToInt(json["y"])); - this->setElevation(ParseUtil::jsonToInt(json["elevation"])); - this->setBaseID(ParseUtil::jsonToQString(json["secret_base_id"])); - - this->readCustomAttributes(json); +bool SecretBaseEvent::loadFromJson(QJsonObject json, Project *) { + this->setX(readInt(&json, "x")); + this->setY(readInt(&json, "y")); + this->setElevation(readInt(&json, "elevation")); + this->setBaseID(readString(&json, "secret_base_id")); + this->setCustomAttributes(json); return true; } @@ -792,16 +746,14 @@ void SecretBaseEvent::setDefaultValues(Project *project) { this->setElevation(0); } -const QSet expectedSecretBaseFields = { - "type", - "elevation", - "secret_base_id", -}; - QSet SecretBaseEvent::getExpectedFields() { - QSet expectedFields = QSet(); - expectedFields = expectedSecretBaseFields; - expectedFields << "x" << "y"; + static const QSet expectedFields = { + "x", + "y", + "type", + "elevation", + "secret_base_id", + }; return expectedFields; } @@ -829,12 +781,15 @@ EventFrame *HealLocationEvent::createEventFrame() { return this->eventFrame; } +QString HealLocationEvent::getHostMapName() const { + return this->getMap() ? this->getMap()->constantName() : this->hostMapName; +} + OrderedJson::object HealLocationEvent::buildEventJson(Project *project) { OrderedJson::object healLocationJson; healLocationJson["id"] = this->getIdName(); - // This field doesn't need to be stored in the Event itself, so it's output only. - healLocationJson["map"] = this->getMap() ? this->getMap()->constantName() : QString(); + healLocationJson["map"] = this->getHostMapName(); healLocationJson["x"] = this->getX(); healLocationJson["y"] = this->getY(); if (projectConfig.healLocationRespawnDataEnabled) { @@ -843,26 +798,26 @@ OrderedJson::object HealLocationEvent::buildEventJson(Project *project) { healLocationJson["respawn_npc"] = this->getRespawnNPC(); } - this->addCustomAttributesTo(&healLocationJson); - + OrderedJson::append(&healLocationJson, this->getCustomAttributes()); return healLocationJson; } -bool HealLocationEvent::loadFromJson(const QJsonObject &json, Project *project) { - this->setX(ParseUtil::jsonToInt(json["x"])); - this->setY(ParseUtil::jsonToInt(json["y"])); - this->setIdName(ParseUtil::jsonToQString(json["id"])); +bool HealLocationEvent::loadFromJson(QJsonObject json, Project *project) { + this->setX(readInt(&json, "x")); + this->setY(readInt(&json, "y")); + this->setIdName(readString(&json, "id")); + this->setHostMapName(readString(&json, "map")); if (projectConfig.healLocationRespawnDataEnabled) { // Log a warning if "respawn_map" isn't a known map ID, but don't overwrite user data. - const QString mapConstant = ParseUtil::jsonToQString(json["respawn_map"]); + const QString mapConstant = readString(&json, "respawn_map"); if (!project->mapConstantsToMapNames.contains(mapConstant)) logWarn(QString("Unknown Respawn Map constant '%1'.").arg(mapConstant)); this->setRespawnMapName(project->mapConstantsToMapNames.value(mapConstant, mapConstant)); - this->setRespawnNPC(ParseUtil::jsonToQString(json["respawn_npc"])); + this->setRespawnNPC(readString(&json, "respawn_npc")); } - this->readCustomAttributes(json); + this->setCustomAttributes(json); return true; } @@ -875,16 +830,19 @@ void HealLocationEvent::setDefaultValues(Project *project) { } const QSet expectedHealLocationFields = { - "id", - "map" + }; QSet HealLocationEvent::getExpectedFields() { - QSet expectedFields = expectedHealLocationFields; + QSet expectedFields = { + "x", + "y", + "id", + "map", + }; if (projectConfig.healLocationRespawnDataEnabled) { expectedFields.insert("respawn_map"); expectedFields.insert("respawn_npc"); } - expectedFields << "x" << "y"; return expectedFields; } diff --git a/src/lib/orderedjson.cpp b/src/lib/orderedjson.cpp index 24bb264a..c501a596 100644 --- a/src/lib/orderedjson.cpp +++ b/src/lib/orderedjson.cpp @@ -311,32 +311,37 @@ const Json & JsonArray::operator[] (int i) const { else return m_value[i]; } -const Json Json::fromQJsonValue(QJsonValue value) { +Json Json::fromQJsonValue(const QJsonValue &value) { switch (value.type()) { case QJsonValue::String: return value.toString(); case QJsonValue::Double: return value.toInt(); case QJsonValue::Bool: return value.toBool(); - case QJsonValue::Array: - { - QJsonArray qArr = value.toArray(); - Json::array arr; - for (const auto &i: qArr) - arr.push_back(Json::fromQJsonValue(i)); - return arr; + case QJsonValue::Array: { + Json::array array; + Json::append(&array, value.toArray()); + return array; } - case QJsonValue::Object: - { - QJsonObject qObj = value.toObject(); - Json::object obj; - for (auto it = qObj.constBegin(); it != qObj.constEnd(); it++) - obj[it.key()] = Json::fromQJsonValue(it.value()); - return obj; + case QJsonValue::Object: { + Json::object object; + Json::append(&object, value.toObject()); + return object; } default: return static_null(); } } +void Json::append(Json::array *array, const QJsonArray &qArray) { + for (const auto &i: qArray) { + array->push_back(fromQJsonValue(i)); + } +} + +void Json::append(Json::object *object, const QJsonObject &qObject) { + for (auto it = qObject.constBegin(); it != qObject.constEnd(); it++) { + (*object)[it.key()] = fromQJsonValue(it.value()); + } +} /* * * * * * * * * * * * * * * * * * * * * Comparison diff --git a/src/project.cpp b/src/project.cpp index bef26614..a942d6fc 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -218,8 +218,8 @@ bool Project::readMapJson(const QString &mapName, QJsonDocument * out) { return true; } -bool Project::loadMapEvent(Map *map, const QJsonObject &json, Event::Type defaultType) { - QString typeString = ParseUtil::jsonToQString(json["type"]); +bool Project::loadMapEvent(Map *map, QJsonObject json, Event::Type defaultType) { + QString typeString = ParseUtil::jsonToQString(json.take("type")); Event::Type type = typeString.isEmpty() ? defaultType : Event::typeFromJsonKey(typeString); Event* event = Event::create(type); if (!event) { @@ -245,10 +245,10 @@ bool Project::loadMapData(Map* map) { QJsonObject mapObj = mapDoc.object(); // We should already know the map constant ID from the initial project launch, but we'll ensure it's correct here anyway. - map->setConstantName(ParseUtil::jsonToQString(mapObj["id"])); + map->setConstantName(ParseUtil::jsonToQString(mapObj.take("id"))); this->mapConstantsToMapNames.insert(map->constantName(), map->name()); - const QString layoutId = ParseUtil::jsonToQString(mapObj["layout"]); + const QString layoutId = ParseUtil::jsonToQString(mapObj.take("layout")); Layout* layout = this->mapLayouts.value(layoutId); if (!layout) { // We've already verified layout IDs on project launch and ignored maps with invalid IDs, so this shouldn't happen. @@ -257,24 +257,24 @@ bool Project::loadMapData(Map* map) { } map->setLayout(layout); - map->header()->setSong(ParseUtil::jsonToQString(mapObj["music"])); - map->header()->setLocation(ParseUtil::jsonToQString(mapObj["region_map_section"])); - map->header()->setRequiresFlash(ParseUtil::jsonToBool(mapObj["requires_flash"])); - map->header()->setWeather(ParseUtil::jsonToQString(mapObj["weather"])); - map->header()->setType(ParseUtil::jsonToQString(mapObj["map_type"])); - map->header()->setShowsLocationName(ParseUtil::jsonToBool(mapObj["show_map_name"])); - map->header()->setBattleScene(ParseUtil::jsonToQString(mapObj["battle_scene"])); + map->header()->setSong(ParseUtil::jsonToQString(mapObj.take("music"))); + map->header()->setLocation(ParseUtil::jsonToQString(mapObj.take("region_map_section"))); + map->header()->setRequiresFlash(ParseUtil::jsonToBool(mapObj.take("requires_flash"))); + map->header()->setWeather(ParseUtil::jsonToQString(mapObj.take("weather"))); + map->header()->setType(ParseUtil::jsonToQString(mapObj.take("map_type"))); + map->header()->setShowsLocationName(ParseUtil::jsonToBool(mapObj.take("show_map_name"))); + map->header()->setBattleScene(ParseUtil::jsonToQString(mapObj.take("battle_scene"))); if (projectConfig.mapAllowFlagsEnabled) { - map->header()->setAllowsBiking(ParseUtil::jsonToBool(mapObj["allow_cycling"])); - map->header()->setAllowsEscaping(ParseUtil::jsonToBool(mapObj["allow_escaping"])); - map->header()->setAllowsRunning(ParseUtil::jsonToBool(mapObj["allow_running"])); + map->header()->setAllowsBiking(ParseUtil::jsonToBool(mapObj.take("allow_cycling"))); + map->header()->setAllowsEscaping(ParseUtil::jsonToBool(mapObj.take("allow_escaping"))); + map->header()->setAllowsRunning(ParseUtil::jsonToBool(mapObj.take("allow_running"))); } if (projectConfig.floorNumberEnabled) { - map->header()->setFloorNumber(ParseUtil::jsonToInt(mapObj["floor_number"])); + map->header()->setFloorNumber(ParseUtil::jsonToInt(mapObj.take("floor_number"))); } - map->setSharedEventsMap(ParseUtil::jsonToQString(mapObj["shared_events_map"])); - map->setSharedScriptsMap(ParseUtil::jsonToQString(mapObj["shared_scripts_map"])); + map->setSharedEventsMap(ParseUtil::jsonToQString(mapObj.take("shared_events_map"))); + map->setSharedScriptsMap(ParseUtil::jsonToQString(mapObj.take("shared_scripts_map"))); // Events map->resetEvents(); @@ -289,7 +289,7 @@ bool Project::loadMapData(Map* map) { for (auto i = defaultEventTypes.constBegin(); i != defaultEventTypes.constEnd(); i++) { QString eventGroupKey = i.key(); Event::Type defaultType = i.value(); - const QJsonArray eventsJsonArr = mapObj[eventGroupKey].toArray(); + const QJsonArray eventsJsonArr = mapObj.take(eventGroupKey).toArray(); for (int i = 0; i < eventsJsonArr.size(); i++) { if (!loadMapEvent(map, eventsJsonArr.at(i).toObject(), defaultType)) { logError(QString("Failed to load event for %1, in %2 at index %3.").arg(map->name()).arg(eventGroupKey).arg(i)); @@ -304,7 +304,7 @@ bool Project::loadMapData(Map* map) { } map->deleteConnections(); - QJsonArray connectionsArr = mapObj["connections"].toArray(); + QJsonArray connectionsArr = mapObj.take("connections").toArray(); if (!connectionsArr.isEmpty()) { for (int i = 0; i < connectionsArr.size(); i++) { QJsonObject connectionObj = connectionsArr[i].toObject(); @@ -316,14 +316,7 @@ bool Project::loadMapData(Map* map) { map->loadConnection(connection); } } - - QMap customAttributes; - for (auto i = mapObj.constBegin(); i != mapObj.constEnd(); i++) { - if (!this->topLevelMapFields.contains(i.key())) { - customAttributes.insert(i.key(), i.value()); - } - } - map->setCustomAttributes(customAttributes); + map->setCustomAttributes(mapObj); return true; } @@ -621,16 +614,11 @@ void Project::saveMapLayouts() { layoutObj["secondary_tileset"] = layout->tileset_secondary_label; layoutObj["border_filepath"] = layout->border_path; layoutObj["blockdata_filepath"] = layout->blockdata_path; - for (auto it = layout->customData.constBegin(); it != layout->customData.constEnd(); it++) { - layoutObj[it.key()] = OrderedJson::fromQJsonValue(it.value()); - } + OrderedJson::append(&layoutObj, layout->customData); layoutsArr.push_back(layoutObj); } layoutsObj["layouts"] = layoutsArr; - - for (auto it = this->customLayoutsData.constBegin(); it != this->customLayoutsData.constEnd(); it++) { - layoutsObj[it.key()] = OrderedJson::fromQJsonValue(it.value()); - } + OrderedJson::append(&layoutsObj, this->customLayoutsData); ignoreWatchedFileTemporarily(layoutsFilepath); @@ -690,9 +678,7 @@ void Project::saveMapGroups() { } mapGroupsObj[groupName] = groupArr; } - for (auto it = this->customMapGroupsData.constBegin(); it != this->customMapGroupsData.constEnd(); it++) { - mapGroupsObj[it.key()] = OrderedJson::fromQJsonValue(it.value()); - } + OrderedJson::append(&mapGroupsObj, this->customMapGroupsData); ignoreWatchedFileTemporarily(mapGroupsFilepath); @@ -727,19 +713,14 @@ void Project::saveRegionMapSections() { mapSectionObj["width"] = location.map.width; mapSectionObj["height"] = location.map.height; } - - for (auto it = location.custom.constBegin(); it != location.custom.constEnd(); it++) { - mapSectionObj[it.key()] = OrderedJson::fromQJsonValue(it.value()); - } + OrderedJson::append(&mapSectionObj, location.custom); mapSectionArray.append(mapSectionObj); } OrderedJson::object object; object["map_sections"] = mapSectionArray; - for (auto it = this->customMapSectionsData.constBegin(); it != this->customMapSectionsData.constEnd(); it++) { - object[it.key()] = OrderedJson::fromQJsonValue(it.value()); - } + OrderedJson::append(&object, this->customMapSectionsData); ignoreWatchedFileTemporarily(filepath); OrderedJson json(object); @@ -894,9 +875,7 @@ void Project::saveHealLocations() { OrderedJson::object object; object["heal_locations"] = eventJsonArr; - for (auto it = this->customHealLocationsData.constBegin(); it != this->customHealLocationsData.constEnd(); it++) { - object[it.key()] = OrderedJson::fromQJsonValue(it.value()); - } + OrderedJson::append(&object, this->customHealLocationsData); ignoreWatchedFileTemporarily(filepath); OrderedJson json(object); @@ -1230,10 +1209,7 @@ void Project::saveMap(Map *map, bool skipLayout) { connectionObj["map"] = getMapConstant(connection->targetMapName(), connection->targetMapName()); connectionObj["offset"] = connection->offset(); connectionObj["direction"] = connection->direction(); - auto customData = connection->customData(); - for (auto it = customData.constBegin(); it != customData.constEnd(); it++) { - connectionObj[it.key()] = OrderedJson::fromQJsonValue(it.value()); - } + OrderedJson::append(&connectionObj, connection->customData()); connectionsArr.append(connectionObj); } mapObj["connections"] = connectionsArr; @@ -1289,10 +1265,7 @@ void Project::saveMap(Map *map, bool skipLayout) { this->healLocations[map->constantName()] = hlEvents; // Custom header fields. - const auto customAttributes = map->customAttributes(); - for (auto i = customAttributes.constBegin(); i != customAttributes.constEnd(); i++) { - mapObj[i.key()] = OrderedJson::fromQJsonValue(i.value()); - } + OrderedJson::append(&mapObj, map->customAttributes()); OrderedJson mapJson(mapObj); OrderedJsonDoc jsonDoc(&mapJson); @@ -2555,7 +2528,7 @@ bool Project::readHealLocations() { auto event = new HealLocationEvent(); event->loadFromJson(healLocationObj, this); - this->healLocations[ParseUtil::jsonToQString(healLocationObj["map"])].append(event); + this->healLocations[event->getHostMapName()].append(event); this->healLocationSaveOrder.append(event->getIdName()); } this->customHealLocationsData = healLocationsObj; diff --git a/src/ui/customattributestable.cpp b/src/ui/customattributestable.cpp index 65381443..28153b4d 100644 --- a/src/ui/customattributestable.cpp +++ b/src/ui/customattributestable.cpp @@ -39,8 +39,8 @@ CustomAttributesTable::CustomAttributesTable(QWidget *parent) : }); } -QMap CustomAttributesTable::getAttributes() const { - QMap fields; +QJsonObject CustomAttributesTable::getAttributes() const { + QJsonObject fields; for (int row = 0; row < this->rowCount(); row++) { auto keyValuePair = this->getAttribute(row); if (!keyValuePair.first.isEmpty()) @@ -145,10 +145,10 @@ void CustomAttributesTable::addNewAttribute(const QString &key, const QJsonValue } // For programmatically populating the table -void CustomAttributesTable::setAttributes(const QMap &attributes) { +void CustomAttributesTable::setAttributes(const QJsonObject &attributes) { m_keys.clear(); this->setRowCount(0); // Clear old values - for (auto it = attributes.cbegin(); it != attributes.cend(); it++) + for (auto it = attributes.constBegin(); it != attributes.constEnd(); it++) this->addAttribute(it.key(), it.value()); this->resizeVertically(); }