From c9b0d139b26e8c10dacb4ae0bf816b6a9a987631 Mon Sep 17 00:00:00 2001 From: GriffinR Date: Sat, 29 Mar 2025 22:54:13 -0400 Subject: [PATCH 1/8] Preserve custom fields in the map_sections, layouts, and connections arrays --- include/core/mapconnection.h | 5 +++ include/core/maplayout.h | 2 ++ include/project.h | 1 + src/core/maplayout.cpp | 1 + src/project.cpp | 70 +++++++++++++++++++++++------------- 5 files changed, 54 insertions(+), 25 deletions(-) diff --git a/include/core/mapconnection.h b/include/core/mapconnection.h index 21c00ac6..e95c25df 100644 --- a/include/core/mapconnection.h +++ b/include/core/mapconnection.h @@ -5,6 +5,7 @@ #include #include #include +#include class Project; class Map; @@ -29,6 +30,9 @@ public: int offset() const { return m_offset; } void setOffset(int offset, bool mirror = true); + QJsonObject customData() const { return m_customData; } + void setCustomData(const QJsonObject &customData) { m_customData = customData; } + MapConnection* findMirror(); MapConnection* createMirror(); @@ -49,6 +53,7 @@ private: QString m_targetMapName; QString m_direction; int m_offset; + QJsonObject m_customData; void markMapEdited(); Map* getMap(const QString& mapName) const; diff --git a/include/core/maplayout.h b/include/core/maplayout.h index 57da8840..119a2232 100644 --- a/include/core/maplayout.h +++ b/include/core/maplayout.h @@ -42,6 +42,8 @@ public: Tileset *tileset_primary = nullptr; Tileset *tileset_secondary = nullptr; + QJsonObject customData; + Blockdata blockdata; QImage image; diff --git a/include/project.h b/include/project.h index 9a031c0d..09a39bb6 100644 --- a/include/project.h +++ b/include/project.h @@ -263,6 +263,7 @@ public: private: QHash mapSectionDisplayNames; + QHash mapSectionCustomData; QMap modifiedFileTimestamps; QMap facingDirections; QHash speciesToIconPath; diff --git a/src/core/maplayout.cpp b/src/core/maplayout.cpp index e443a635..33408f6a 100644 --- a/src/core/maplayout.cpp +++ b/src/core/maplayout.cpp @@ -31,6 +31,7 @@ void Layout::copyFrom(const Layout *other) { this->tileset_secondary = other->tileset_secondary; this->blockdata = other->blockdata; this->border = other->border; + this->customData = other->customData; } QString Layout::layoutConstantFromName(const QString &name) { diff --git a/src/project.cpp b/src/project.cpp index bbbc052c..8841cd7f 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -308,10 +308,12 @@ bool Project::loadMapData(Map* map) { if (!connectionsArr.isEmpty()) { for (int i = 0; i < connectionsArr.size(); i++) { QJsonObject connectionObj = connectionsArr[i].toObject(); - const QString direction = ParseUtil::jsonToQString(connectionObj["direction"]); - const int offset = ParseUtil::jsonToInt(connectionObj["offset"]); - const QString mapConstant = ParseUtil::jsonToQString(connectionObj["map"]); - map->loadConnection(new MapConnection(this->mapConstantsToMapNames.value(mapConstant, mapConstant), direction, offset)); + const QString direction = ParseUtil::jsonToQString(connectionObj.take("direction")); + const int offset = ParseUtil::jsonToInt(connectionObj.take("offset")); + const QString mapConstant = ParseUtil::jsonToQString(connectionObj.take("map")); + auto connection = new MapConnection(this->mapConstantsToMapNames.value(mapConstant, mapConstant), direction, offset); + connection->setCustomData(connectionObj); + map->loadConnection(connection); } } @@ -503,7 +505,7 @@ bool Project::readMapLayouts() { if (layoutObj.isEmpty()) continue; Layout *layout = new Layout(); - layout->id = ParseUtil::jsonToQString(layoutObj["id"]); + layout->id = ParseUtil::jsonToQString(layoutObj.take("id")); if (layout->id.isEmpty()) { logError(QString("Missing 'id' value on layout %1 in %2").arg(i).arg(layoutsFilepath)); delete layout; @@ -514,20 +516,20 @@ bool Project::readMapLayouts() { delete layout; continue; } - layout->name = ParseUtil::jsonToQString(layoutObj["name"]); + layout->name = ParseUtil::jsonToQString(layoutObj.take("name")); if (layout->name.isEmpty()) { logError(QString("Missing 'name' value for %1 in %2").arg(layout->id).arg(layoutsFilepath)); delete layout; return false; } - int lwidth = ParseUtil::jsonToInt(layoutObj["width"]); + int lwidth = ParseUtil::jsonToInt(layoutObj.take("width")); if (lwidth <= 0) { logError(QString("Invalid 'width' value '%1' for %2 in %3. Must be greater than 0.").arg(lwidth).arg(layout->id).arg(layoutsFilepath)); delete layout; return false; } layout->width = lwidth; - int lheight = ParseUtil::jsonToInt(layoutObj["height"]); + int lheight = ParseUtil::jsonToInt(layoutObj.take("height")); if (lheight <= 0) { logError(QString("Invalid 'height' value '%1' for %2 in %3. Must be greater than 0.").arg(lheight).arg(layout->id).arg(layoutsFilepath)); delete layout; @@ -535,12 +537,12 @@ bool Project::readMapLayouts() { } layout->height = lheight; if (projectConfig.useCustomBorderSize) { - int bwidth = ParseUtil::jsonToInt(layoutObj["border_width"]); + int bwidth = ParseUtil::jsonToInt(layoutObj.take("border_width")); if (bwidth <= 0) { // 0 is an expected border width/height that should be handled, GF used it for the RS layouts in FRLG bwidth = DEFAULT_BORDER_WIDTH; } layout->border_width = bwidth; - int bheight = ParseUtil::jsonToInt(layoutObj["border_height"]); + int bheight = ParseUtil::jsonToInt(layoutObj.take("border_height")); if (bheight <= 0) { bheight = DEFAULT_BORDER_HEIGHT; } @@ -549,30 +551,31 @@ bool Project::readMapLayouts() { layout->border_width = DEFAULT_BORDER_WIDTH; layout->border_height = DEFAULT_BORDER_HEIGHT; } - layout->tileset_primary_label = ParseUtil::jsonToQString(layoutObj["primary_tileset"]); + layout->tileset_primary_label = ParseUtil::jsonToQString(layoutObj.take("primary_tileset")); if (layout->tileset_primary_label.isEmpty()) { logError(QString("Missing 'primary_tileset' value for %1 in %2").arg(layout->id).arg(layoutsFilepath)); delete layout; return false; } - layout->tileset_secondary_label = ParseUtil::jsonToQString(layoutObj["secondary_tileset"]); + layout->tileset_secondary_label = ParseUtil::jsonToQString(layoutObj.take("secondary_tileset")); if (layout->tileset_secondary_label.isEmpty()) { logError(QString("Missing 'secondary_tileset' value for %1 in %2").arg(layout->id).arg(layoutsFilepath)); delete layout; return false; } - layout->border_path = ParseUtil::jsonToQString(layoutObj["border_filepath"]); + layout->border_path = ParseUtil::jsonToQString(layoutObj.take("border_filepath")); if (layout->border_path.isEmpty()) { logError(QString("Missing 'border_filepath' value for %1 in %2").arg(layout->id).arg(layoutsFilepath)); delete layout; return false; } - layout->blockdata_path = ParseUtil::jsonToQString(layoutObj["blockdata_filepath"]); + layout->blockdata_path = ParseUtil::jsonToQString(layoutObj.take("blockdata_filepath")); if (layout->blockdata_path.isEmpty()) { logError(QString("Missing 'blockdata_filepath' value for %1 in %2").arg(layout->id).arg(layoutsFilepath)); delete layout; return false; } + layout->customData = layoutObj; this->mapLayouts.insert(layout->id, layout); this->mapLayoutsMaster.insert(layout->id, layout->copy()); @@ -615,6 +618,9 @@ 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()); + } layoutsArr.push_back(layoutObj); } @@ -711,6 +717,11 @@ void Project::saveRegionMapSections() { mapSectionObj["height"] = entry.height; } + QJsonObject customData = this->mapSectionCustomData.value(idName); + for (auto it = customData.constBegin(); it != customData.constEnd(); it++) { + mapSectionObj[it.key()] = OrderedJson::fromQJsonValue(it.value()); + } + mapSectionArray.append(mapSectionObj); } @@ -1203,6 +1214,10 @@ 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()); + } connectionsArr.append(connectionObj); } mapObj["connections"] = connectionsArr; @@ -2320,6 +2335,7 @@ bool Project::readRegionMapSections() { this->mapSectionIdNames.clear(); this->mapSectionIdNamesSaveOrder.clear(); this->mapSectionDisplayNames.clear(); + this->mapSectionCustomData.clear(); this->regionMapEntries.clear(); const QString defaultName = getEmptyMapsecName(); const QString requiredPrefix = projectConfig.getIdentifier(ProjectIdentifier::define_map_section_prefix); @@ -2351,7 +2367,7 @@ bool Project::readRegionMapSections() { continue; } } - const QString idName = ParseUtil::jsonToQString(mapSectionObj[idField]); + const QString idName = ParseUtil::jsonToQString(mapSectionObj.take(idField)); if (!idName.startsWith(requiredPrefix)) { logWarn(QString("Ignoring data for map section '%1' in '%2'. IDs must start with the prefix '%3'").arg(idName).arg(filepath).arg(requiredPrefix)); continue; @@ -2361,7 +2377,7 @@ bool Project::readRegionMapSections() { this->mapSectionIdNamesSaveOrder.append(idName); if (mapSectionObj.contains("name")) - this->mapSectionDisplayNames.insert(idName, ParseUtil::jsonToQString(mapSectionObj["name"])); + this->mapSectionDisplayNames.insert(idName, ParseUtil::jsonToQString(mapSectionObj.take("name"))); // Map sections may have additional data indicating their position on the region map. // If they have this data, we can add them to the region map entry list. @@ -2373,16 +2389,20 @@ bool Project::readRegionMapSections() { break; } } - if (!hasRegionMapData) - continue; + if (hasRegionMapData) { + MapSectionEntry entry; + entry.x = ParseUtil::jsonToInt(mapSectionObj.take("x")); + entry.y = ParseUtil::jsonToInt(mapSectionObj.take("y")); + entry.width = ParseUtil::jsonToInt(mapSectionObj.take("width")); + entry.height = ParseUtil::jsonToInt(mapSectionObj.take("height")); + entry.valid = true; + this->regionMapEntries[idName] = entry; + } - MapSectionEntry entry; - entry.x = ParseUtil::jsonToInt(mapSectionObj["x"]); - entry.y = ParseUtil::jsonToInt(mapSectionObj["y"]); - entry.width = ParseUtil::jsonToInt(mapSectionObj["width"]); - entry.height = ParseUtil::jsonToInt(mapSectionObj["height"]); - entry.valid = true; - this->regionMapEntries[idName] = entry; + // Preserve any remaining fields for when we save. + if (!mapSectionObj.isEmpty()) { + this->mapSectionCustomData[idName] = mapSectionObj; + } } // Make sure the default name is present in the list. From a4508918a17c4bc820538cf2deb70ac1ae4939b9 Mon Sep 17 00:00:00 2001 From: GriffinR Date: Mon, 31 Mar 2025 19:33:31 -0400 Subject: [PATCH 2/8] Preserve custom global fields in layouts, heal_locations, region_map_sections, and map_groups json files --- include/project.h | 6 +++++ src/project.cpp | 56 +++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 55 insertions(+), 7 deletions(-) diff --git a/include/project.h b/include/project.h index 09a39bb6..4ed95f06 100644 --- a/include/project.h +++ b/include/project.h @@ -269,6 +269,12 @@ private: QHash speciesToIconPath; QHash maps; + // Fields for preserving top-level JSON data that Porymap isn't expecting. + QJsonObject customLayoutsData; + QJsonObject customMapSectionsData; + QJsonObject customMapGroupsData; + QJsonObject customHealLocationsData; + // Maps/layouts represented in these sets have been fully loaded from the project. // If a valid map name / layout id is not in these sets, a Map / Layout object exists // for it in Project::maps / Project::mapLayouts, but it has been minimally populated diff --git a/src/project.cpp b/src/project.cpp index 8841cd7f..98bd7215 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -475,6 +475,7 @@ void Project::clearMapLayouts() { this->layoutIds.clear(); this->layoutIdsMaster.clear(); this->loadedLayoutIds.clear(); + this->customLayoutsData = QJsonObject(); } bool Project::readMapLayouts() { @@ -491,7 +492,7 @@ bool Project::readMapLayouts() { QJsonObject layoutsObj = layoutsDoc.object(); - this->layoutsLabel = ParseUtil::jsonToQString(layoutsObj["layouts_table_label"]); + this->layoutsLabel = ParseUtil::jsonToQString(layoutsObj.take("layouts_table_label")); if (this->layoutsLabel.isEmpty()) { this->layoutsLabel = "gMapLayouts"; logWarn(QString("'layouts_table_label' value is missing from %1. Defaulting to %2") @@ -499,7 +500,7 @@ bool Project::readMapLayouts() { .arg(layoutsLabel)); } - QJsonArray layouts = layoutsObj["layouts"].toArray(); + QJsonArray layouts = layoutsObj.take("layouts").toArray(); for (int i = 0; i < layouts.size(); i++) { QJsonObject layoutObj = layouts[i].toObject(); if (layoutObj.isEmpty()) @@ -588,6 +589,8 @@ bool Project::readMapLayouts() { return false; } + this->customLayoutsData = layoutsObj; + return true; } @@ -623,10 +626,14 @@ void Project::saveMapLayouts() { } 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()); + } ignoreWatchedFileTemporarily(layoutsFilepath); - layoutsObj["layouts"] = layoutsArr; OrderedJson layoutJson(layoutsObj); OrderedJsonDoc jsonDoc(&layoutJson); jsonDoc.dump(&layoutsFile); @@ -683,6 +690,9 @@ void Project::saveMapGroups() { } mapGroupsObj[groupName] = groupArr; } + for (auto it = this->customMapGroupsData.constBegin(); it != this->customMapGroupsData.constEnd(); it++) { + mapGroupsObj[it.key()] = OrderedJson::fromQJsonValue(it.value()); + } ignoreWatchedFileTemporarily(mapGroupsFilepath); @@ -727,6 +737,9 @@ void Project::saveRegionMapSections() { 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()); + } ignoreWatchedFileTemporarily(filepath); OrderedJson json(object); @@ -881,6 +894,9 @@ 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()); + } ignoreWatchedFileTemporarily(filepath); OrderedJson json(object); @@ -1787,6 +1803,7 @@ bool Project::readMapGroups() { this->mapNames.clear(); this->groupNames.clear(); this->groupNameToMapNames.clear(); + this->customMapGroupsData = QJsonObject(); this->initTopLevelMapFields(); @@ -1809,7 +1826,12 @@ bool Project::readMapGroups() { QStringList failedMapNames; for (int groupIndex = 0; groupIndex < mapGroupOrder.size(); groupIndex++) { const QString groupName = ParseUtil::jsonToQString(mapGroupOrder.at(groupIndex)); - const QJsonArray mapNamesJson = mapGroupsObj.value(groupName).toArray(); + if (this->groupNames.contains(groupName)) { + logWarn(QString("Ignoring repeated map group name '%1'.").arg(groupName)); + continue; + } + + const QJsonArray mapNamesJson = mapGroupsObj.take(groupName).toArray(); this->groupNames.append(groupName); // Process the names in this map group @@ -1903,6 +1925,12 @@ bool Project::readMapGroups() { this->mapConstantsToMapNames.insert(dynamicMapConstant, dynamicMapName); this->mapNames.append(dynamicMapName); + // Save custom JSON data. + // Chuck the "connections_include_order" field, this is only for matching. + // TODO: Setting not to do this, on the off chance someone wants this field. + mapGroupsObj.remove("connections_include_order"); + this->customMapGroupsData = mapGroupsObj; + return true; } @@ -2335,11 +2363,16 @@ bool Project::readRegionMapSections() { this->mapSectionIdNames.clear(); this->mapSectionIdNamesSaveOrder.clear(); this->mapSectionDisplayNames.clear(); - this->mapSectionCustomData.clear(); this->regionMapEntries.clear(); const QString defaultName = getEmptyMapsecName(); const QString requiredPrefix = projectConfig.getIdentifier(ProjectIdentifier::define_map_section_prefix); + // The first of these is the custom data for each individual map section object, + // the second is the custom top-level data in the map sections file. + // TODO: Clarify this by relocating the various map section data maps to a single class? + this->mapSectionCustomData.clear(); + this->customMapSectionsData = QJsonObject(); + QJsonDocument doc; const QString filepath = projectConfig.getFilePath(ProjectFilePath::json_region_map_entries); QString error; @@ -2349,7 +2382,8 @@ bool Project::readRegionMapSections() { } fileWatcher.addPath(QString("%1/%2").arg(this->root).arg(filepath)); - QJsonArray mapSections = doc.object()["map_sections"].toArray(); + QJsonObject mapSectionsGlobalObj = doc.object(); + QJsonArray mapSections = mapSectionsGlobalObj.take("map_sections").toArray(); for (int i = 0; i < mapSections.size(); i++) { QJsonObject mapSectionObj = mapSections.at(i).toObject(); @@ -2399,11 +2433,16 @@ bool Project::readRegionMapSections() { this->regionMapEntries[idName] = entry; } + // Chuck the "name_clone" field, this is only for matching. + // TODO: Setting not to do this, on the off chance someone wants this field. + mapSectionObj.remove("name_clone"); + // Preserve any remaining fields for when we save. if (!mapSectionObj.isEmpty()) { this->mapSectionCustomData[idName] = mapSectionObj; } } + this->customMapSectionsData = mapSectionsGlobalObj; // Make sure the default name is present in the list. if (!this->mapSectionIdNames.contains(defaultName)) { @@ -2477,6 +2516,7 @@ void Project::clearHealLocations() { } this->healLocations.clear(); this->healLocationSaveOrder.clear(); + this->customHealLocationsData = QJsonObject(); } bool Project::readHealLocations() { @@ -2491,7 +2531,8 @@ bool Project::readHealLocations() { } fileWatcher.addPath(QString("%1/%2").arg(this->root).arg(filepath)); - QJsonArray healLocations = doc.object()["heal_locations"].toArray(); + QJsonObject healLocationsObj = doc.object(); + QJsonArray healLocations = healLocationsObj.take("heal_locations").toArray(); for (int i = 0; i < healLocations.size(); i++) { QJsonObject healLocationObj = healLocations.at(i).toObject(); static const QString mapField = QStringLiteral("map"); @@ -2505,6 +2546,7 @@ bool Project::readHealLocations() { this->healLocations[ParseUtil::jsonToQString(healLocationObj["map"])].append(event); this->healLocationSaveOrder.append(event->getIdName()); } + this->customHealLocationsData = healLocationsObj; return true; } From e94fce0c8d78100492fc58c7ca11c9679aa49814 Mon Sep 17 00:00:00 2001 From: GriffinR Date: Thu, 3 Apr 2025 13:24:50 -0400 Subject: [PATCH 3/8] Combine the 3 QMaps for MAPSEC data --- include/core/regionmap.h | 6 +-- include/core/regionmapeditcommands.h | 4 +- include/project.h | 17 +++++-- include/ui/regionmapeditor.h | 2 +- src/core/regionmapeditcommands.cpp | 2 +- src/project.cpp | 73 ++++++++++++++++------------ src/ui/regionmapeditor.cpp | 4 +- 7 files changed, 63 insertions(+), 45 deletions(-) diff --git a/include/core/regionmap.h b/include/core/regionmap.h index 18362663..c8afb1b2 100644 --- a/include/core/regionmap.h +++ b/include/core/regionmap.h @@ -56,8 +56,8 @@ public: bool loadLayout(poryjson::Json); bool loadEntries(); - void setEntries(QMap *entries) { this->region_map_entries = entries; } - void setEntries(const QMap &entries) { *(this->region_map_entries) = entries; } + void setEntries(QHash *entries) { this->region_map_entries = entries; } + void setEntries(const QHash &entries) { *(this->region_map_entries) = entries; } void clearEntries() { this->region_map_entries->clear(); } MapSectionEntry getEntry(QString section); void setEntry(QString section, MapSectionEntry entry); @@ -151,7 +151,7 @@ signals: void mapNeedsDisplaying(); private: - QMap *region_map_entries = nullptr; + QHash *region_map_entries = nullptr; QString alias = ""; diff --git a/include/core/regionmapeditcommands.h b/include/core/regionmapeditcommands.h index 05b12bc3..e47fdb7b 100644 --- a/include/core/regionmapeditcommands.h +++ b/include/core/regionmapeditcommands.h @@ -153,7 +153,7 @@ private: /// ClearEntries class ClearEntries : public QUndoCommand { public: - ClearEntries(RegionMap *map, QMap, QUndoCommand *parent = nullptr); + ClearEntries(RegionMap *map, QHash, QUndoCommand *parent = nullptr); void undo() override; void redo() override; @@ -163,7 +163,7 @@ public: private: RegionMap *map; - QMap entries; + QHash entries; }; #endif // REGIONMAPEDITCOMMANDS_H diff --git a/include/project.h b/include/project.h index 4ed95f06..44094aaa 100644 --- a/include/project.h +++ b/include/project.h @@ -62,7 +62,6 @@ public: QStringList mapSectionIdNames; QMap encounterTypeToName; QMap terrainTypeToName; - QMap regionMapEntries; QMap> metatileLabelsMap; QMap unusedMetatileLabels; QMap metatileBehaviorMap; @@ -157,7 +156,7 @@ public: bool addNewMapsec(const QString &idName, const QString &displayName = QString()); void removeMapsec(const QString &idName); - QString getMapsecDisplayName(const QString &idName) const { return this->mapSectionDisplayNames.value(idName); } + QString getMapsecDisplayName(const QString &idName) const { return this->locationData.value(idName).displayName; } void setMapsecDisplayName(const QString &idName, const QString &displayName); bool hasUnsavedChanges(); @@ -240,6 +239,9 @@ public: static QString getExistingFilepath(QString filepath); void applyParsedLimits(); + void setRegionMapEntries(const QHash &entries); + QHash getRegionMapEntries() const; + static QString getEmptyMapDefineName(); static QString getDynamicMapDefineName(); static QString getDynamicMapName(); @@ -262,8 +264,6 @@ public: static QString getMapGroupPrefix(); private: - QHash mapSectionDisplayNames; - QHash mapSectionCustomData; QMap modifiedFileTimestamps; QMap facingDirections; QHash speciesToIconPath; @@ -298,6 +298,15 @@ private: }; QMap eventGraphicsMap; + // The extra data that can be associated with each MAPSEC name. + struct LocationData + { + MapSectionEntry map; + QString displayName; + QJsonObject custom; + }; + QHash locationData; + void updateLayout(Layout *); void setNewLayoutBlockdata(Layout *layout); diff --git a/include/ui/regionmapeditor.h b/include/ui/regionmapeditor.h index 9a838827..490324af 100644 --- a/include/ui/regionmapeditor.h +++ b/include/ui/regionmapeditor.h @@ -95,7 +95,7 @@ private: void saveConfig(); bool loadRegionMapEntries(); bool saveRegionMapEntries(); - QMap region_map_entries; + QHash region_map_entries; bool buildConfigDialog(); poryjson::Json configRegionMapDialog(); diff --git a/src/core/regionmapeditcommands.cpp b/src/core/regionmapeditcommands.cpp index 7a12cbc6..f21f1d72 100644 --- a/src/core/regionmapeditcommands.cpp +++ b/src/core/regionmapeditcommands.cpp @@ -260,7 +260,7 @@ void ResizeTilemap::undo() { /// -ClearEntries::ClearEntries(RegionMap *map, QMap entries, QUndoCommand *parent) +ClearEntries::ClearEntries(RegionMap *map, QHash entries, QUndoCommand *parent) : QUndoCommand(parent) { setText("Clear Entries"); diff --git a/src/project.cpp b/src/project.cpp index 98bd7215..891f709f 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -712,23 +712,23 @@ void Project::saveRegionMapSections() { OrderedJson::array mapSectionArray; for (const auto &idName : this->mapSectionIdNamesSaveOrder) { + const LocationData location = this->locationData.value(idName); + OrderedJson::object mapSectionObj; mapSectionObj["id"] = idName; - if (this->mapSectionDisplayNames.contains(idName)) { - mapSectionObj["name"] = this->mapSectionDisplayNames.value(idName); + if (!location.displayName.isEmpty()) { + mapSectionObj["name"] = location.displayName; } - if (this->regionMapEntries.contains(idName)) { - MapSectionEntry entry = this->regionMapEntries.value(idName); - mapSectionObj["x"] = entry.x; - mapSectionObj["y"] = entry.y; - mapSectionObj["width"] = entry.width; - mapSectionObj["height"] = entry.height; + if (location.map.valid) { + mapSectionObj["x"] = location.map.x; + mapSectionObj["y"] = location.map.y; + mapSectionObj["width"] = location.map.width; + mapSectionObj["height"] = location.map.height; } - QJsonObject customData = this->mapSectionCustomData.value(idName); - for (auto it = customData.constBegin(); it != customData.constEnd(); it++) { + for (auto it = location.custom.constBegin(); it != location.custom.constEnd(); it++) { mapSectionObj[it.key()] = OrderedJson::fromQJsonValue(it.value()); } @@ -2360,19 +2360,14 @@ bool Project::readFieldmapMasks() { } bool Project::readRegionMapSections() { + this->locationData.clear(); this->mapSectionIdNames.clear(); this->mapSectionIdNamesSaveOrder.clear(); - this->mapSectionDisplayNames.clear(); - this->regionMapEntries.clear(); + this->customMapSectionsData = QJsonObject(); + const QString defaultName = getEmptyMapsecName(); const QString requiredPrefix = projectConfig.getIdentifier(ProjectIdentifier::define_map_section_prefix); - // The first of these is the custom data for each individual map section object, - // the second is the custom top-level data in the map sections file. - // TODO: Clarify this by relocating the various map section data maps to a single class? - this->mapSectionCustomData.clear(); - this->customMapSectionsData = QJsonObject(); - QJsonDocument doc; const QString filepath = projectConfig.getFilePath(ProjectFilePath::json_region_map_entries); QString error; @@ -2410,8 +2405,10 @@ bool Project::readRegionMapSections() { this->mapSectionIdNames.append(idName); this->mapSectionIdNamesSaveOrder.append(idName); - if (mapSectionObj.contains("name")) - this->mapSectionDisplayNames.insert(idName, ParseUtil::jsonToQString(mapSectionObj.take("name"))); + LocationData location; + if (mapSectionObj.contains("name")) { + location.displayName = ParseUtil::jsonToQString(mapSectionObj.take("name")); + } // Map sections may have additional data indicating their position on the region map. // If they have this data, we can add them to the region map entry list. @@ -2424,13 +2421,11 @@ bool Project::readRegionMapSections() { } } if (hasRegionMapData) { - MapSectionEntry entry; - entry.x = ParseUtil::jsonToInt(mapSectionObj.take("x")); - entry.y = ParseUtil::jsonToInt(mapSectionObj.take("y")); - entry.width = ParseUtil::jsonToInt(mapSectionObj.take("width")); - entry.height = ParseUtil::jsonToInt(mapSectionObj.take("height")); - entry.valid = true; - this->regionMapEntries[idName] = entry; + location.map.x = ParseUtil::jsonToInt(mapSectionObj.take("x")); + location.map.y = ParseUtil::jsonToInt(mapSectionObj.take("y")); + location.map.width = ParseUtil::jsonToInt(mapSectionObj.take("width")); + location.map.height = ParseUtil::jsonToInt(mapSectionObj.take("height")); + location.map.valid = true; } // Chuck the "name_clone" field, this is only for matching. @@ -2438,9 +2433,9 @@ bool Project::readRegionMapSections() { mapSectionObj.remove("name_clone"); // Preserve any remaining fields for when we save. - if (!mapSectionObj.isEmpty()) { - this->mapSectionCustomData[idName] = mapSectionObj; - } + location.custom = mapSectionObj; + + this->locationData.insert(idName, location); } this->customMapSectionsData = mapSectionsGlobalObj; @@ -2453,6 +2448,20 @@ bool Project::readRegionMapSections() { return true; } +void Project::setRegionMapEntries(const QHash &entries) { + for (auto it = entries.constBegin(); it != entries.constEnd(); it++) { + this->locationData[it.key()].map = it.value(); + } +} + +QHash Project::getRegionMapEntries() const { + QHash entries; + for (auto it = this->locationData.constBegin(); it != this->locationData.constEnd(); it++) { + entries[it.key()] = it.value().map; + } + return entries; +} + QString Project::getEmptyMapsecName() { return projectConfig.getIdentifier(ProjectIdentifier::define_map_section_prefix) + projectConfig.getIdentifier(ProjectIdentifier::define_map_section_empty); } @@ -2503,9 +2512,9 @@ void Project::removeMapsec(const QString &idName) { } void Project::setMapsecDisplayName(const QString &idName, const QString &displayName) { - if (this->mapSectionDisplayNames.value(idName) == displayName) + if (getMapsecDisplayName(idName) == displayName) return; - this->mapSectionDisplayNames[idName] = displayName; + this->locationData[idName].displayName = displayName; this->hasUnsavedDataChanges = true; emit mapSectionDisplayNameChanged(idName, displayName); } diff --git a/src/ui/regionmapeditor.cpp b/src/ui/regionmapeditor.cpp index 2febccd8..27fb5f2f 100644 --- a/src/ui/regionmapeditor.cpp +++ b/src/ui/regionmapeditor.cpp @@ -108,12 +108,12 @@ void RegionMapEditor::applyUserShortcuts() { } bool RegionMapEditor::loadRegionMapEntries() { - this->region_map_entries = this->project->regionMapEntries; + this->region_map_entries = this->project->getRegionMapEntries(); return true; } bool RegionMapEditor::saveRegionMapEntries() { - this->project->regionMapEntries = this->region_map_entries; + this->project->setRegionMapEntries(this->region_map_entries); this->project->saveRegionMapSections(); return true; } From 011f6196b56ede6207df724d70887f0dafe10ed5 Mon Sep 17 00:00:00 2001 From: GriffinR Date: Thu, 3 Apr 2025 13:43:54 -0400 Subject: [PATCH 4/8] Add setting to keep data only needed for matching --- forms/projectsettingseditor.ui | 14 ++++++++++++-- include/config.h | 2 ++ src/config.cpp | 3 +++ src/project.cpp | 13 ++++++++----- src/ui/projectsettingseditor.cpp | 2 ++ 5 files changed, 27 insertions(+), 7 deletions(-) diff --git a/forms/projectsettingseditor.ui b/forms/projectsettingseditor.ui index a088d87e..179392dd 100644 --- a/forms/projectsettingseditor.ui +++ b/forms/projectsettingseditor.ui @@ -39,7 +39,7 @@ 0 0 559 - 568 + 589 @@ -66,6 +66,16 @@ + + + + <html><head/><body><p>If enabled, Porymap will not discard data like &quot;connections_include_order&quot; or &quot;name_clone&quot;, which serve no purpose other than recreating the original game.</p></body></html> + + + Preserve data only needed to match the original game + + + @@ -1084,7 +1094,7 @@ 0 0 559 - 788 + 840 diff --git a/include/config.h b/include/config.h index eb9c9ac3..6746a0f4 100644 --- a/include/config.h +++ b/include/config.h @@ -323,6 +323,7 @@ public: this->tilesetsHaveCallback = true; this->tilesetsHaveIsCompressed = true; this->setTransparentPixelsBlack = true; + this->preserveMatchingOnlyData = false; this->filePaths.clear(); this->eventIconPaths.clear(); this->pokemonIconPaths.clear(); @@ -389,6 +390,7 @@ public: bool tilesetsHaveCallback; bool tilesetsHaveIsCompressed; bool setTransparentPixelsBlack; + bool preserveMatchingOnlyData; int metatileAttributesSize; uint32_t metatileBehaviorMask; uint32_t metatileTerrainTypeMask; diff --git a/src/config.cpp b/src/config.cpp index d74adbcb..d76f17a5 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -809,6 +809,8 @@ void ProjectConfig::parseConfigKeyValue(QString key, QString value) { this->tilesetsHaveIsCompressed = getConfigBool(key, value); } else if (key == "set_transparent_pixels_black") { this->setTransparentPixelsBlack = getConfigBool(key, value); + } else if (key == "preserve_matching_only_data") { + this->preserveMatchingOnlyData = getConfigBool(key, value); } else if (key == "event_icon_path_object") { this->eventIconPaths[Event::Group::Object] = value; } else if (key == "event_icon_path_warp") { @@ -899,6 +901,7 @@ QMap ProjectConfig::getKeyValueMap() { map.insert("tilesets_have_callback", QString::number(this->tilesetsHaveCallback)); map.insert("tilesets_have_is_compressed", QString::number(this->tilesetsHaveIsCompressed)); map.insert("set_transparent_pixels_black", QString::number(this->setTransparentPixelsBlack)); + map.insert("preserve_matching_only_data", QString::number(this->preserveMatchingOnlyData)); map.insert("metatile_attributes_size", QString::number(this->metatileAttributesSize)); map.insert("metatile_behavior_mask", Util::toHexString(this->metatileBehaviorMask)); map.insert("metatile_terrain_type_mask", Util::toHexString(this->metatileTerrainTypeMask)); diff --git a/src/project.cpp b/src/project.cpp index 891f709f..bef26614 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -1925,10 +1925,12 @@ bool Project::readMapGroups() { this->mapConstantsToMapNames.insert(dynamicMapConstant, dynamicMapName); this->mapNames.append(dynamicMapName); - // Save custom JSON data. // Chuck the "connections_include_order" field, this is only for matching. - // TODO: Setting not to do this, on the off chance someone wants this field. - mapGroupsObj.remove("connections_include_order"); + if (!projectConfig.preserveMatchingOnlyData) { + mapGroupsObj.remove("connections_include_order"); + } + + // Preserve any remaining fields for when we save. this->customMapGroupsData = mapGroupsObj; return true; @@ -2429,8 +2431,9 @@ bool Project::readRegionMapSections() { } // Chuck the "name_clone" field, this is only for matching. - // TODO: Setting not to do this, on the off chance someone wants this field. - mapSectionObj.remove("name_clone"); + if (!projectConfig.preserveMatchingOnlyData) { + mapSectionObj.remove("name_clone"); + } // Preserve any remaining fields for when we save. location.custom = mapSectionObj; diff --git a/src/ui/projectsettingseditor.cpp b/src/ui/projectsettingseditor.cpp index fa84f3e0..90951dd7 100644 --- a/src/ui/projectsettingseditor.cpp +++ b/src/ui/projectsettingseditor.cpp @@ -443,6 +443,7 @@ void ProjectSettingsEditor::refresh() { ui->checkBox_OutputCallback->setChecked(projectConfig.tilesetsHaveCallback); ui->checkBox_OutputIsCompressed->setChecked(projectConfig.tilesetsHaveIsCompressed); ui->checkBox_DisableWarning->setChecked(porymapConfig.warpBehaviorWarningDisabled); + ui->checkBox_PreserveMatchingOnlyData->setChecked(projectConfig.preserveMatchingOnlyData); // Radio buttons if (projectConfig.setTransparentPixelsBlack) @@ -524,6 +525,7 @@ void ProjectSettingsEditor::save() { projectConfig.tilesetsHaveIsCompressed = ui->checkBox_OutputIsCompressed->isChecked(); porymapConfig.warpBehaviorWarningDisabled = ui->checkBox_DisableWarning->isChecked(); projectConfig.setTransparentPixelsBlack = ui->radioButton_RenderBlack->isChecked(); + projectConfig.preserveMatchingOnlyData = ui->checkBox_PreserveMatchingOnlyData->isChecked(); // Save spin box settings projectConfig.defaultElevation = ui->spinBox_Elevation->value(); From 029e959bfefd3fafe5b9364052ea84add7e6055f Mon Sep 17 00:00:00 2001 From: GriffinR Date: Thu, 3 Apr 2025 13:53:33 -0400 Subject: [PATCH 5/8] Simplify fromQJsonValue loops --- include/core/events.h | 42 ++-- include/core/map.h | 6 +- include/lib/orderedjson.h | 4 +- include/project.h | 2 +- include/ui/customattributestable.h | 4 +- src/core/events.cpp | 368 +++++++++++++---------------- src/lib/orderedjson.cpp | 35 +-- src/project.cpp | 85 +++---- src/ui/customattributestable.cpp | 8 +- 9 files changed, 250 insertions(+), 304 deletions(-) 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(); } From f3a28848b9dcd226688b01805deb5a8d45e3ac08 Mon Sep 17 00:00:00 2001 From: GriffinR Date: Fri, 4 Apr 2025 11:54:39 -0400 Subject: [PATCH 6/8] Preserve custom fields in wild_encounters.json --- include/core/parseutil.h | 2 +- include/core/wildmoninfo.h | 10 +++-- include/lib/orderedjson.h | 19 +++++++-- include/lib/orderedmap.h | 11 ++++++ include/project.h | 6 ++- include/ui/regionmapeditor.h | 2 +- src/core/parseutil.cpp | 4 +- src/editor.cpp | 4 +- src/lib/orderedjson.cpp | 12 ------ src/project.cpp | 76 ++++++++++++++++++++++-------------- 10 files changed, 90 insertions(+), 56 deletions(-) diff --git a/include/core/parseutil.h b/include/core/parseutil.h index 4c19a27c..e02d0504 100644 --- a/include/core/parseutil.h +++ b/include/core/parseutil.h @@ -58,7 +58,7 @@ public: QMap readCDefinesByRegex(const QString &filename, const QSet ®exList, QString *error = nullptr); QMap readCDefinesByName(const QString &filename, const QSet &names, QString *error = nullptr); QStringList readCDefineNames(const QString &filename, const QSet ®exList, QString *error = nullptr); - tsl::ordered_map> readCStructs(const QString &, const QString & = "", const QHash& = {}); + OrderedMap> readCStructs(const QString &, const QString & = "", const QHash& = {}); QList getLabelMacros(const QList&, const QString&); QStringList getLabelValues(const QList&, const QString&); bool tryParseJsonFile(QJsonDocument *out, const QString &filepath, QString *error = nullptr); diff --git a/include/core/wildmoninfo.h b/include/core/wildmoninfo.h index 3c94fb17..a3665b7d 100644 --- a/include/core/wildmoninfo.h +++ b/include/core/wildmoninfo.h @@ -3,7 +3,7 @@ #define GUARD_WILDMONINFO_H #include -#include "orderedmap.h" +#include "orderedjson.h" class WildPokemon { public: @@ -13,22 +13,26 @@ public: int minLevel; int maxLevel; QString species; + OrderedJson::object customData; }; struct WildMonInfo { bool active = false; int encounterRate = 0; QVector wildPokemon; + OrderedJson::object customData; }; struct WildPokemonHeader { - tsl::ordered_map wildMons; + OrderedMap wildMons; + OrderedJson::object customData; }; struct EncounterField { QString name; // Ex: "fishing_mons" QVector encounterRates; - tsl::ordered_map> groups; // Ex: "good_rod", {2, 3, 4} + OrderedMap> groups; // Ex: "good_rod", {2, 3, 4} + OrderedJson::object customData; }; typedef QVector EncounterFields; diff --git a/include/lib/orderedjson.h b/include/lib/orderedjson.h index 73422a2b..cb5139d3 100644 --- a/include/lib/orderedjson.h +++ b/include/lib/orderedjson.h @@ -99,7 +99,7 @@ public: // Array and object typedefs typedef QVector array; - typedef tsl::ordered_map object; + typedef OrderedMap object; // Constructors for the various types of JSON value. Json() noexcept; // NUL @@ -133,8 +133,21 @@ public: Json(const V & v) : Json(array(v.begin(), v.end())) {} static Json fromQJsonValue(const QJsonValue &value); - static void append(Json::array *array, const QJsonArray &qArray); - static void append(Json::object *object, const QJsonObject &qObject); + + static void append(Json::array *array, const QJsonArray &addendum) { + for (const auto &i : addendum) array->push_back(fromQJsonValue(i)); + } + static void append(Json::array *array, const Json::array &addendum) { + for (const auto &i : addendum) array->push_back(i); + } + static void append(Json::object *object, const QJsonObject &addendum) { + for (auto it = addendum.constBegin(); it != addendum.constEnd(); it++) + (*object)[it.key()] = fromQJsonValue(it.value()); + } + static void append(Json::object *object, const Json::object &addendum) { + for (auto it = addendum.cbegin(); it != addendum.cend(); it++) + (*object)[it.key()] = it.value(); + } // This prevents Json(some_pointer) from accidentally producing a bool. Use // Json(bool(some_pointer)) if that behavior is desired. diff --git a/include/lib/orderedmap.h b/include/lib/orderedmap.h index 40882d9f..33fcfc50 100644 --- a/include/lib/orderedmap.h +++ b/include/lib/orderedmap.h @@ -1977,6 +1977,14 @@ public: size_type erase(const K& key, std::size_t precalculated_hash) { return m_ht.erase(key, precalculated_hash); } + + // Naive solution for take, should probably be replaced with one that does a single lookup and no unnecessary insertion. + // We want to mirror the behavior of QMap::take, which returns a default-constructed value if the key is not present. + T take(const key_type& key) { + typename ValueSelect::value_type value = m_ht[key]; + m_ht.erase(key); + return value; + } @@ -2404,4 +2412,7 @@ private: } // end namespace tsl +template +using OrderedMap = tsl::ordered_map; + #endif diff --git a/include/project.h b/include/project.h index 5f37c5e7..bcc53ae7 100644 --- a/include/project.h +++ b/include/project.h @@ -143,12 +143,11 @@ public: QString getNewHealLocationName(const Map* map) const; bool readWildMonData(); - tsl::ordered_map> wildMonData; + OrderedMap> wildMonData; QString wildMonTableName; QVector wildMonFields; QVector encounterGroupLabels; - QVector extraEncounterGroups; bool readSpeciesIconPaths(); QString getDefaultSpeciesIconPath(const QString &species); @@ -274,6 +273,9 @@ private: QJsonObject customMapSectionsData; QJsonObject customMapGroupsData; QJsonObject customHealLocationsData; + OrderedJson::object customWildMonData; + OrderedJson::object customWildMonGroupData; + OrderedJson::array extraEncounterGroups; // Maps/layouts represented in these sets have been fully loaded from the project. // If a valid map name / layout id is not in these sets, a Map / Layout object exists diff --git a/include/ui/regionmapeditor.h b/include/ui/regionmapeditor.h index 490324af..8ecf0a76 100644 --- a/include/ui/regionmapeditor.h +++ b/include/ui/regionmapeditor.h @@ -54,7 +54,7 @@ private: Project *project; RegionMap *region_map = nullptr; - tsl::ordered_map region_maps; + OrderedMap region_maps; QString configFilepath; diff --git a/src/core/parseutil.cpp b/src/core/parseutil.cpp index e172ea42..da2a8f8e 100644 --- a/src/core/parseutil.cpp +++ b/src/core/parseutil.cpp @@ -610,12 +610,12 @@ bool ParseUtil::gameStringToBool(const QString &gameString, bool * ok) { return gameStringToInt(gameString, ok) != 0; } -tsl::ordered_map> ParseUtil::readCStructs(const QString &filename, const QString &label, const QHash &memberMap) { +OrderedMap> ParseUtil::readCStructs(const QString &filename, const QString &label, const QHash &memberMap) { QString filePath = pathWithRoot(filename); auto cParser = fex::Parser(); auto tokens = fex::Lexer().LexFile(filePath); auto topLevelObjects = cParser.ParseTopLevelObjects(tokens); - tsl::ordered_map> structs; + OrderedMap> structs; for (auto it = topLevelObjects.begin(); it != topLevelObjects.end(); it++) { QString structLabel = QString::fromStdString(it->first); if (structLabel.isEmpty()) continue; diff --git a/src/editor.cpp b/src/editor.cpp index b29a47bc..19acbe60 100644 --- a/src/editor.cpp +++ b/src/editor.cpp @@ -596,7 +596,7 @@ void Editor::configureEncounterJSON(QWidget *window) { if (newNameDialog.exec() == QDialog::Accepted) { QString newFieldName = newNameEdit->text(); QVector newFieldRates(1, 100); - tempFields.append({newFieldName, newFieldRates, {}}); + tempFields.append({newFieldName, newFieldRates, {}, {}}); fieldChoices->addItem(newFieldName); fieldChoices->setCurrentIndex(fieldChoices->count() - 1); } @@ -675,7 +675,7 @@ void Editor::saveEncounterTabData() { if (!stack->count()) return; - tsl::ordered_map &encounterMap = project->wildMonData[map->constantName()]; + OrderedMap &encounterMap = project->wildMonData[map->constantName()]; for (int groupIndex = 0; groupIndex < stack->count(); groupIndex++) { MonTabWidget *tabWidget = static_cast(stack->widget(groupIndex)); diff --git a/src/lib/orderedjson.cpp b/src/lib/orderedjson.cpp index c501a596..d6ba4dbd 100644 --- a/src/lib/orderedjson.cpp +++ b/src/lib/orderedjson.cpp @@ -331,18 +331,6 @@ Json Json::fromQJsonValue(const QJsonValue &value) { } } -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 a942d6fc..871b8e2c 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -747,7 +747,7 @@ void Project::saveWildMonData() { monHeadersObject["for_maps"] = true; OrderedJson::array fieldsInfoArray; - for (EncounterField fieldInfo : wildMonFields) { + for (EncounterField fieldInfo : this->wildMonFields) { OrderedJson::object fieldObject; OrderedJson::array rateArray; @@ -770,48 +770,52 @@ void Project::saveWildMonData() { } if (!groupsObject.empty()) fieldObject["groups"] = groupsObject; + OrderedJson::append(&fieldObject, fieldInfo.customData); fieldsInfoArray.append(fieldObject); } monHeadersObject["fields"] = fieldsInfoArray; OrderedJson::array encountersArray; - for (auto keyPair : wildMonData) { + for (auto keyPair : this->wildMonData) { QString key = keyPair.first; - for (auto grouplLabelPair : wildMonData[key]) { + for (auto grouplLabelPair : this->wildMonData[key]) { QString groupLabel = grouplLabelPair.first; OrderedJson::object encounterObject; encounterObject["map"] = key; encounterObject["base_label"] = groupLabel; - WildPokemonHeader encounterHeader = wildMonData[key][groupLabel]; + WildPokemonHeader encounterHeader = this->wildMonData[key][groupLabel]; for (auto fieldNamePair : encounterHeader.wildMons) { QString fieldName = fieldNamePair.first; - OrderedJson::object fieldObject; + OrderedJson::object monInfoObject; WildMonInfo monInfo = encounterHeader.wildMons[fieldName]; - fieldObject["encounter_rate"] = monInfo.encounterRate; + monInfoObject["encounter_rate"] = monInfo.encounterRate; OrderedJson::array monArray; for (WildPokemon wildMon : monInfo.wildPokemon) { OrderedJson::object monEntry; monEntry["min_level"] = wildMon.minLevel; monEntry["max_level"] = wildMon.maxLevel; monEntry["species"] = wildMon.species; + OrderedJson::append(&monEntry, wildMon.customData); monArray.push_back(monEntry); } - fieldObject["mons"] = monArray; - encounterObject[fieldName] = fieldObject; + monInfoObject["mons"] = monArray; + OrderedJson::append(&monInfoObject, monInfo.customData); + + encounterObject[fieldName] = monInfoObject; + OrderedJson::append(&encounterObject, encounterHeader.customData); } encountersArray.push_back(encounterObject); } } monHeadersObject["encounters"] = encountersArray; - wildEncounterGroups.push_back(monHeadersObject); + OrderedJson::append(&monHeadersObject, this->customWildMonGroupData); - // add extra Json objects that are not associated with maps to the file - for (auto extraObject : extraEncounterGroups) { - wildEncounterGroups.push_back(extraObject); - } + wildEncounterGroups.push_back(monHeadersObject); + OrderedJson::append(&wildEncounterGroups, this->extraEncounterGroups); wildEncountersObject["wild_encounter_groups"] = wildEncounterGroups; + OrderedJson::append(&wildEncountersObject, this->customWildMonData); ignoreWatchedFileTemporarily(wildEncountersJsonFilepath); OrderedJson encounterJson(wildEncountersObject); @@ -1607,6 +1611,8 @@ bool Project::readWildMonData() { this->pokemonMaxLevel = 100; this->maxEncounterRate = 2880/16; this->wildEncountersLoaded = false; + this->customWildMonData = OrderedJson::object(); + this->customWildMonGroupData = OrderedJson::object(); if (!userConfig.useEncounterJson) { return true; } @@ -1652,7 +1658,8 @@ bool Project::readWildMonData() { QMap> encounterRateFrequencyMaps; // Parse "wild_encounter_groups". This is the main object array containing all the data in this file. - for (OrderedJson mainArrayJson : wildMonObj["wild_encounter_groups"].array_items()) { + OrderedJson::array mainArray = wildMonObj.take("wild_encounter_groups").array_items(); + for (const OrderedJson &mainArrayJson : mainArray) { OrderedJson::object mainArrayObject = mainArrayJson.object_items(); // We're only interested in wild encounter data that's associated with maps ("for_maps" == true). @@ -1661,10 +1668,14 @@ bool Project::readWildMonData() { if (!mainArrayObject["for_maps"].bool_value()) { this->extraEncounterGroups.push_back(mainArrayObject); continue; + } else { + // Note: We don't call 'take' above, we don't want to strip data from extraEncounterGroups. + // We do want to strip it from the main group, because it shouldn't be treated as custom data. + mainArrayObject.erase("for_maps"); } // If multiple "for_maps" data sets are found they will be collapsed into a single set. - QString label = mainArrayObject["label"].string_value(); + QString label = mainArrayObject.take("label").string_value(); if (this->wildMonTableName.isEmpty()) { this->wildMonTableName = label; } else { @@ -1677,24 +1688,25 @@ bool Project::readWildMonData() { // Each element describes a type of wild encounter Porymap can expect to find, and we represent this data with an EncounterField. // They should contain a name ("type"), the number of encounter slots and the ratio at which they occur ("encounter_rates"), // and whether the encounters are divided into groups (like fishing rods). - for (const OrderedJson &fieldJson : mainArrayObject["fields"].array_items()) { + for (const OrderedJson &fieldJson : mainArrayObject.take("fields").array_items()) { OrderedJson::object fieldObject = fieldJson.object_items(); EncounterField encounterField; - encounterField.name = fieldObject["type"].string_value(); + encounterField.name = fieldObject.take("type").string_value(); - for (auto val : fieldObject["encounter_rates"].array_items()) { + for (auto val : fieldObject.take("encounter_rates").array_items()) { encounterField.encounterRates.append(val.int_value()); } // Each element of the "groups" array is an object with the group name as the key (e.g. "old_rod") // and an array of slot numbers indicating which encounter slots in this encounter type belong to that group. - for (auto groupPair : fieldObject["groups"].object_items()) { + for (auto groupPair : fieldObject.take("groups").object_items()) { const QString groupName = groupPair.first; for (auto slotNum : groupPair.second.array_items()) { encounterField.groups[groupName].append(slotNum.int_value()); } } + encounterField.customData = fieldObject; encounterRateFrequencyMaps.insert(encounterField.name, QMap()); this->wildMonFields.append(encounterField); @@ -1704,7 +1716,7 @@ bool Project::readWildMonData() { // Each element is an object that will tell us which map it's associated with, // its symbol name (which we will display in the Groups dropdown) and a list of // pokémon associated with any of the encounter types described by the data we parsed above. - for (const auto &encounterJson : mainArrayObject["encounters"].array_items()) { + for (const auto &encounterJson : mainArrayObject.take("encounters").array_items()) { OrderedJson::object encounterObj = encounterJson.object_items(); WildPokemonHeader header; @@ -1712,29 +1724,31 @@ bool Project::readWildMonData() { // Check for each possible encounter type. for (const EncounterField &monField : this->wildMonFields) { const QString field = monField.name; - if (encounterObj[field].is_null()) { + if (!encounterObj.contains(field)) { // Encounter type isn't present continue; } - OrderedJson::object encounterFieldObj = encounterObj[field].object_items(); + OrderedJson::object encounterFieldObj = encounterObj.take(field).object_items(); WildMonInfo monInfo; monInfo.active = true; // Read encounter rate - monInfo.encounterRate = encounterFieldObj["encounter_rate"].int_value(); + monInfo.encounterRate = encounterFieldObj.take("encounter_rate").int_value(); encounterRateFrequencyMaps[field][monInfo.encounterRate]++; // Read wild pokémon list - for (auto monJson : encounterFieldObj["mons"].array_items()) { + for (const auto &monJson : encounterFieldObj.take("mons").array_items()) { OrderedJson::object monObj = monJson.object_items(); WildPokemon newMon; - newMon.minLevel = monObj["min_level"].int_value(); - newMon.maxLevel = monObj["max_level"].int_value(); - newMon.species = monObj["species"].string_value(); + newMon.minLevel = monObj.take("min_level").int_value(); + newMon.maxLevel = monObj.take("max_level").int_value(); + newMon.species = monObj.take("species").string_value(); + newMon.customData = monObj; monInfo.wildPokemon.append(newMon); } + monInfo.customData = encounterFieldObj; // If the user supplied too few pokémon for this group then we fill in the rest with default values. for (int i = monInfo.wildPokemon.length(); i < monField.encounterRates.length(); i++) { @@ -1742,13 +1756,15 @@ bool Project::readWildMonData() { } header.wildMons[field] = monInfo; } - - const QString mapConstant = encounterObj["map"].string_value(); - const QString baseLabel = encounterObj["base_label"].string_value(); + const QString mapConstant = encounterObj.take("map").string_value(); + const QString baseLabel = encounterObj.take("base_label").string_value(); + header.customData = encounterObj; this->wildMonData[mapConstant].insert({baseLabel, header}); this->encounterGroupLabels.append(baseLabel); } + this->customWildMonGroupData = mainArrayObject; } + this->customWildMonData = wildMonObj; // For each encounter type, set default encounter rate to most common value. // Iterate over map of encounter type names to frequency maps... From db9e9d6f65077b230d14df7bfc779a7489956fde Mon Sep 17 00:00:00 2001 From: GriffinR Date: Fri, 4 Apr 2025 13:09:14 -0400 Subject: [PATCH 7/8] Remove Project::topLevelMapFields --- include/project.h | 4 ++-- src/mainwindow.cpp | 2 +- src/project.cpp | 16 +++++++--------- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/include/project.h b/include/project.h index bcc53ae7..c5aed0a3 100644 --- a/include/project.h +++ b/include/project.h @@ -71,7 +71,6 @@ public: QSet modifiedFiles; bool usingAsmTilesets; QSet disabledSettingsNames; - QSet topLevelMapFields; int pokemonMinLevel; int pokemonMaxLevel; int maxEncounterRate; @@ -161,7 +160,6 @@ public: bool hasUnsavedChanges(); bool hasUnsavedDataChanges = false; - void initTopLevelMapFields(); bool readMapJson(const QString &mapName, QJsonDocument * out); bool loadMapEvent(Map *map, QJsonObject json, Event::Type defaultType = Event::Type::None); bool loadMapData(Map*); @@ -241,6 +239,8 @@ public: void setRegionMapEntries(const QHash &entries); QHash getRegionMapEntries() const; + QSet getTopLevelMapFields() const; + static QString getEmptyMapDefineName(); static QString getDynamicMapDefineName(); static QString getDynamicMapName(); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index af7eaabe..28d7f996 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -1192,7 +1192,7 @@ bool MainWindow::setProjectUI() { ui->layoutList->setModel(layoutListProxyModel); ui->layoutList->sortByColumn(0, Qt::SortOrder::AscendingOrder); - ui->mapCustomAttributesFrame->table()->setRestrictedKeys(project->topLevelMapFields); + ui->mapCustomAttributesFrame->table()->setRestrictedKeys(project->getTopLevelMapFields()); return true; } diff --git a/src/project.cpp b/src/project.cpp index 871b8e2c..f5499730 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -177,8 +177,8 @@ Map* Project::loadMap(const QString &mapName) { return map; } -void Project::initTopLevelMapFields() { - static const QSet defaultTopLevelMapFields = { +QSet Project::getTopLevelMapFields() const { + QSet fields = { "id", "name", "layout", @@ -197,15 +197,15 @@ void Project::initTopLevelMapFields() { "shared_events_map", "shared_scripts_map", }; - this->topLevelMapFields = defaultTopLevelMapFields; if (projectConfig.mapAllowFlagsEnabled) { - this->topLevelMapFields.insert("allow_cycling"); - this->topLevelMapFields.insert("allow_escaping"); - this->topLevelMapFields.insert("allow_running"); + fields.insert("allow_cycling"); + fields.insert("allow_escaping"); + fields.insert("allow_running"); } if (projectConfig.floorNumberEnabled) { - this->topLevelMapFields.insert("floor_number"); + fields.insert("floor_number"); } + return fields; } bool Project::readMapJson(const QString &mapName, QJsonDocument * out) { @@ -1794,8 +1794,6 @@ bool Project::readMapGroups() { this->groupNameToMapNames.clear(); this->customMapGroupsData = QJsonObject(); - this->initTopLevelMapFields(); - const QString filepath = projectConfig.getFilePath(ProjectFilePath::json_map_groups); fileWatcher.addPath(root + "/" + filepath); QJsonDocument mapGroupsDoc; From 5c9e84b4c0d0ee4f96d960d43f9730fe605f2fff Mon Sep 17 00:00:00 2001 From: GriffinR Date: Fri, 4 Apr 2025 13:37:15 -0400 Subject: [PATCH 8/8] Add missing key take --- src/project.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/project.cpp b/src/project.cpp index f5499730..6f225ff6 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -1804,7 +1804,7 @@ bool Project::readMapGroups() { } QJsonObject mapGroupsObj = mapGroupsDoc.object(); - QJsonArray mapGroupOrder = mapGroupsObj["group_order"].toArray(); + QJsonArray mapGroupOrder = mapGroupsObj.take("group_order").toArray(); const QString dynamicMapName = getDynamicMapName(); const QString dynamicMapConstant = getDynamicMapDefineName();