add tsl::ordered_map for json objects,

update project code to save json files with new ordered object
This commit is contained in:
garakmon 2020-03-05 22:46:25 -05:00 committed by huderlem
parent 12614a174a
commit 799e5537f9
9 changed files with 2535 additions and 133 deletions

1
.gitignore vendored
View file

@ -3,6 +3,7 @@ porymap.pro.user
*.autosave *.autosave
*.stash *.stash
*.o *.o
*.DS_Store
porymap.app* porymap.app*
porymap porymap
porymap.cfg porymap.cfg

View file

@ -4,7 +4,10 @@
#include <QString> #include <QString>
#include <QPixmap> #include <QPixmap>
#include <QMap> #include <QMap>
#include <QJsonObject>
#include "orderedjson.h"
using OrderedJson = poryjson::Json;
class EventType class EventType
{ {
@ -67,19 +70,19 @@ public:
static Event* createNewHiddenItemEvent(Project*); static Event* createNewHiddenItemEvent(Project*);
static Event* createNewSecretBaseEvent(Project*); static Event* createNewSecretBaseEvent(Project*);
QJsonObject buildObjectEventJSON(); OrderedJson::object buildObjectEventJSON();
QJsonObject buildWarpEventJSON(QMap<QString, QString>*); OrderedJson::object buildWarpEventJSON(QMap<QString, QString>*);
QJsonObject buildTriggerEventJSON(); OrderedJson::object buildTriggerEventJSON();
QJsonObject buildWeatherTriggerEventJSON(); OrderedJson::object buildWeatherTriggerEventJSON();
QJsonObject buildSignEventJSON(); OrderedJson::object buildSignEventJSON();
QJsonObject buildHiddenItemEventJSON(); OrderedJson::object buildHiddenItemEventJSON();
QJsonObject buildSecretBaseEventJSON(); OrderedJson::object buildSecretBaseEventJSON();
void setPixmapFromSpritesheet(QImage, int, int, int, bool); void setPixmapFromSpritesheet(QImage, int, int, int, bool);
int getPixelX(); int getPixelX();
int getPixelY(); int getPixelY();
QMap<QString, bool> getExpectedFields(); QMap<QString, bool> getExpectedFields();
void readCustomValues(QJsonObject values); void readCustomValues(QJsonObject values);
void addCustomValuesTo(QJsonObject *obj); void addCustomValuesTo(OrderedJson::object *obj);
void setFrameFromMovement(QString); void setFrameFromMovement(QString);
QMap<QString, QString> values; QMap<QString, QString> values;

View file

@ -1,4 +1,3 @@
/// Wrappings around QJsonObjects that preserves order
/* poryjson /* poryjson
* *
* poryjson is a modified version of json11, which adds support to preserve the key order * poryjson is a modified version of json11, which adds support to preserve the key order
@ -56,15 +55,14 @@
#include <QString> #include <QString>
#include <QVector> #include <QVector>
#include <QPair>
#include <QFile> #include <QFile>
#include <QTextStream> #include <QTextStream>
#include <map>
#include <memory> #include <memory>
#include <initializer_list> #include <initializer_list>
// temp #include "orderedmap.h"
#include <iostream>
#ifdef _MSC_VER #ifdef _MSC_VER
#if _MSC_VER <= 1800 // VS 2013 #if _MSC_VER <= 1800 // VS 2013
@ -95,7 +93,7 @@ public:
// Array and object typedefs // Array and object typedefs
typedef QVector<Json> array; typedef QVector<Json> array;
typedef std::map<QString, Json> object; typedef tsl::ordered_map<QString, Json> object;
// Constructors for the various types of JSON value. // Constructors for the various types of JSON value.
Json() noexcept; // NUL Json() noexcept; // NUL
@ -196,14 +194,6 @@ public:
bool operator> (const Json &rhs) const { return (rhs < *this); } bool operator> (const Json &rhs) const { return (rhs < *this); }
bool operator>= (const Json &rhs) const { return !(*this < rhs); } bool operator>= (const Json &rhs) const { return !(*this < rhs); }
/* has_shape(types, err)
*
* Return true if this is a JSON object and, for each item in types, has a field of
* the given type. If not, return false and set err to a descriptive message.
*/
typedef std::initializer_list<std::pair<QString, Type>> shape;
bool has_shape(const shape & types, QString & err) const;
private: private:
std::shared_ptr<JsonValue> m_ptr; std::shared_ptr<JsonValue> m_ptr;
}; };

2406
include/lib/orderedmap.h Normal file

File diff suppressed because it is too large Load diff

View file

@ -7,6 +7,7 @@
#include "event.h" #include "event.h"
#include "wildmoninfo.h" #include "wildmoninfo.h"
#include "parseutil.h" #include "parseutil.h"
#include "orderedjson.h"
#include <QStringList> #include <QStringList>
#include <QList> #include <QList>
@ -93,7 +94,7 @@ public:
QMap<QString, QMap<QString, WildPokemonHeader>> wildMonData; QMap<QString, QMap<QString, WildPokemonHeader>> wildMonData;
QVector<EncounterField> wildMonFields; QVector<EncounterField> wildMonFields;
QVector<QString> encounterGroupLabels; QVector<QString> encounterGroupLabels;
QMap<QString, QJsonObject> extraEncounterGroups; QVector<poryjson::Json::object> extraEncounterGroups;
bool readSpeciesIconPaths(); bool readSpeciesIconPaths();
QMap<QString, QString> speciesToIconPath; QMap<QString, QString> speciesToIconPath;

View file

@ -30,7 +30,7 @@ SOURCES += src/core/block.cpp \
src/core/tileset.cpp \ src/core/tileset.cpp \
src/core/regionmap.cpp \ src/core/regionmap.cpp \
src/core/wildmoninfo.cpp \ src/core/wildmoninfo.cpp \
src/core/orderedjson.cpp \ src/lib/orderedjson.cpp \
src/ui/aboutporymap.cpp \ src/ui/aboutporymap.cpp \
src/ui/bordermetatilespixmapitem.cpp \ src/ui/bordermetatilespixmapitem.cpp \
src/ui/collisionpixmapitem.cpp \ src/ui/collisionpixmapitem.cpp \
@ -92,7 +92,8 @@ HEADERS += include/core/block.h \
include/core/tileset.h \ include/core/tileset.h \
include/core/regionmap.h \ include/core/regionmap.h \
include/core/wildmoninfo.h \ include/core/wildmoninfo.h \
include/core/orderedjson.h \ include/lib/orderedmap.h \
include/lib/orderedjson.h \
include/ui/aboutporymap.h \ include/ui/aboutporymap.h \
include/ui/bordermetatilespixmapitem.h \ include/ui/bordermetatilespixmapitem.h \
include/ui/collisionpixmapitem.h \ include/ui/collisionpixmapitem.h \
@ -152,3 +153,4 @@ RESOURCES += \
INCLUDEPATH += include INCLUDEPATH += include
INCLUDEPATH += include/core INCLUDEPATH += include/core
INCLUDEPATH += include/ui INCLUDEPATH += include/ui
INCLUDEPATH += include/lib

View file

@ -239,7 +239,7 @@ void Event::readCustomValues(QJsonObject values)
} }
} }
void Event::addCustomValuesTo(QJsonObject *obj) void Event::addCustomValuesTo(OrderedJson::object *obj)
{ {
for (QString key : this->customValues.keys()) { for (QString key : this->customValues.keys()) {
if (!obj->contains(key)) { if (!obj->contains(key)) {
@ -248,9 +248,9 @@ void Event::addCustomValuesTo(QJsonObject *obj)
} }
} }
QJsonObject Event::buildObjectEventJSON() OrderedJson::object Event::buildObjectEventJSON()
{ {
QJsonObject eventObj; OrderedJson::object eventObj;
eventObj["graphics_id"] = this->get("sprite"); eventObj["graphics_id"] = this->get("sprite");
eventObj["x"] = this->getU16("x"); eventObj["x"] = this->getU16("x");
eventObj["y"] = this->getU16("y"); eventObj["y"] = this->getU16("y");
@ -267,9 +267,9 @@ QJsonObject Event::buildObjectEventJSON()
return eventObj; return eventObj;
} }
QJsonObject Event::buildWarpEventJSON(QMap<QString, QString> *mapNamesToMapConstants) OrderedJson::object Event::buildWarpEventJSON(QMap<QString, QString> *mapNamesToMapConstants)
{ {
QJsonObject warpObj; OrderedJson::object warpObj;
warpObj["x"] = this->getU16("x"); warpObj["x"] = this->getU16("x");
warpObj["y"] = this->getU16("y"); warpObj["y"] = this->getU16("y");
warpObj["elevation"] = this->getInt("elevation"); warpObj["elevation"] = this->getInt("elevation");
@ -280,9 +280,9 @@ QJsonObject Event::buildWarpEventJSON(QMap<QString, QString> *mapNamesToMapConst
return warpObj; return warpObj;
} }
QJsonObject Event::buildTriggerEventJSON() OrderedJson::object Event::buildTriggerEventJSON()
{ {
QJsonObject triggerObj; OrderedJson::object triggerObj;
triggerObj["type"] = "trigger"; triggerObj["type"] = "trigger";
triggerObj["x"] = this->getU16("x"); triggerObj["x"] = this->getU16("x");
triggerObj["y"] = this->getU16("y"); triggerObj["y"] = this->getU16("y");
@ -295,9 +295,9 @@ QJsonObject Event::buildTriggerEventJSON()
return triggerObj; return triggerObj;
} }
QJsonObject Event::buildWeatherTriggerEventJSON() OrderedJson::object Event::buildWeatherTriggerEventJSON()
{ {
QJsonObject weatherObj; OrderedJson::object weatherObj;
weatherObj["type"] = "weather"; weatherObj["type"] = "weather";
weatherObj["x"] = this->getU16("x"); weatherObj["x"] = this->getU16("x");
weatherObj["y"] = this->getU16("y"); weatherObj["y"] = this->getU16("y");
@ -308,9 +308,9 @@ QJsonObject Event::buildWeatherTriggerEventJSON()
return weatherObj; return weatherObj;
} }
QJsonObject Event::buildSignEventJSON() OrderedJson::object Event::buildSignEventJSON()
{ {
QJsonObject signObj; OrderedJson::object signObj;
signObj["type"] = "sign"; signObj["type"] = "sign";
signObj["x"] = this->getU16("x"); signObj["x"] = this->getU16("x");
signObj["y"] = this->getU16("y"); signObj["y"] = this->getU16("y");
@ -322,9 +322,9 @@ QJsonObject Event::buildSignEventJSON()
return signObj; return signObj;
} }
QJsonObject Event::buildHiddenItemEventJSON() OrderedJson::object Event::buildHiddenItemEventJSON()
{ {
QJsonObject hiddenItemObj; OrderedJson::object hiddenItemObj;
hiddenItemObj["type"] = "hidden_item"; hiddenItemObj["type"] = "hidden_item";
hiddenItemObj["x"] = this->getU16("x"); hiddenItemObj["x"] = this->getU16("x");
hiddenItemObj["y"] = this->getU16("y"); hiddenItemObj["y"] = this->getU16("y");
@ -336,9 +336,9 @@ QJsonObject Event::buildHiddenItemEventJSON()
return hiddenItemObj; return hiddenItemObj;
} }
QJsonObject Event::buildSecretBaseEventJSON() OrderedJson::object Event::buildSecretBaseEventJSON()
{ {
QJsonObject secretBaseObj; OrderedJson::object secretBaseObj;
secretBaseObj["type"] = "secret_base"; secretBaseObj["type"] = "secret_base";
secretBaseObj["x"] = this->getU16("x"); secretBaseObj["x"] = this->getU16("x");
secretBaseObj["y"] = this->getU16("y"); secretBaseObj["y"] = this->getU16("y");

View file

@ -26,8 +26,6 @@
#include <cstdio> #include <cstdio>
#include <limits> #include <limits>
#include <QDebug>
namespace poryjson { namespace poryjson {
static const int max_depth = 200; static const int max_depth = 200;
@ -50,11 +48,13 @@ struct NullStruct {
* Serialization * Serialization
*/ */
static void dump(NullStruct, QString &out, int *) { static void dump(NullStruct, QString &out, int *indent) {
if (!out.endsWith(": ")) out += QString(*indent * 2, ' ');
out += "null"; out += "null";
} }
static void dump(double value, QString &out, int *) { static void dump(double value, QString &out, int *indent) {
if (!out.endsWith(": ")) out += QString(*indent * 2, ' ');
if (std::isfinite(value)) { if (std::isfinite(value)) {
char buf[32]; char buf[32];
snprintf(buf, sizeof buf, "%.17g", value); snprintf(buf, sizeof buf, "%.17g", value);
@ -64,17 +64,20 @@ static void dump(double value, QString &out, int *) {
} }
} }
static void dump(int value, QString &out, int *) { static void dump(int value, QString &out, int *indent) {
if (!out.endsWith(": ")) out += QString(*indent * 2, ' ');
char buf[32]; char buf[32];
snprintf(buf, sizeof buf, "%d", value); snprintf(buf, sizeof buf, "%d", value);
out += buf; out += buf;
} }
static void dump(bool value, QString &out, int *) { static void dump(bool value, QString &out, int *indent) {
if (!out.endsWith(": ")) out += QString(*indent * 2, ' ');
out += value ? "true" : "false"; out += value ? "true" : "false";
} }
static void dump(const QString &value, QString &out, int *) { static void dump(const QString &value, QString &out, int *indent, bool isKey = false) {
if (!isKey && !out.endsWith(": ")) out += QString(*indent * 2, ' ');
out += '"'; out += '"';
for (int i = 0; i < value.length(); i++) { for (int i = 0; i < value.length(); i++) {
const char ch = value[i].unicode(); const char ch = value[i].unicode();
@ -132,12 +135,12 @@ static void dump(const Json::object &values, QString &out, int *indent) {
if (!out.endsWith(": ")) out += QString(*indent * 2, ' '); if (!out.endsWith(": ")) out += QString(*indent * 2, ' ');
out += "{\n"; out += "{\n";
*indent += 1; *indent += 1;
for (const auto &kv : values) { for (auto kv : values) {
if (!first) { if (!first) {
out += ",\n"; out += ",\n";
} }
out += QString(*indent * 2, ' '); out += QString(*indent * 2, ' ');
dump(kv.first, out, indent); dump(kv.first, out, indent, true);
out += ": "; out += ": ";
kv.second.dump(out, indent); kv.second.dump(out, indent);
first = false; first = false;
@ -241,7 +244,7 @@ struct Statics {
const std::shared_ptr<JsonValue> f = make_shared<JsonBoolean>(false); const std::shared_ptr<JsonValue> f = make_shared<JsonBoolean>(false);
const QString empty_string; const QString empty_string;
const QVector<Json> empty_vector; const QVector<Json> empty_vector;
const map<QString, Json> empty_map; const Json::object empty_map;
Statics() {} Statics() {}
}; };
@ -283,7 +286,7 @@ int Json::int_value() const { return m_ptr->int_valu
bool Json::bool_value() const { return m_ptr->bool_value(); } bool Json::bool_value() const { return m_ptr->bool_value(); }
const QString & Json::string_value() const { return m_ptr->string_value(); } const QString & Json::string_value() const { return m_ptr->string_value(); }
const QVector<Json> & Json::array_items() const { return m_ptr->array_items(); } const QVector<Json> & Json::array_items() const { return m_ptr->array_items(); }
const map<QString, Json> & Json::object_items() const { return m_ptr->object_items(); } const Json::object & Json::object_items() const { return m_ptr->object_items(); }
const Json & Json::operator[] (int i) const { return (*m_ptr)[i]; } const Json & Json::operator[] (int i) const { return (*m_ptr)[i]; }
const Json & Json::operator[] (const QString &key) const { return (*m_ptr)[key]; } const Json & Json::operator[] (const QString &key) const { return (*m_ptr)[key]; }
@ -292,13 +295,13 @@ int JsonValue::int_value() const { return
bool JsonValue::bool_value() const { return false; } bool JsonValue::bool_value() const { return false; }
const QString & JsonValue::string_value() const { return statics().empty_string; } const QString & JsonValue::string_value() const { return statics().empty_string; }
const QVector<Json> & JsonValue::array_items() const { return statics().empty_vector; } const QVector<Json> & JsonValue::array_items() const { return statics().empty_vector; }
const map<QString, Json> & JsonValue::object_items() const { return statics().empty_map; } const Json::object & JsonValue::object_items() const { return statics().empty_map; }
const Json & JsonValue::operator[] (int) const { return static_null(); } const Json & JsonValue::operator[] (int) const { return static_null(); }
const Json & JsonValue::operator[] (const QString &) const { return static_null(); } const Json & JsonValue::operator[] (const QString &) const { return static_null(); }
const Json & JsonObject::operator[] (const QString &key) const { const Json & JsonObject::operator[] (const QString &key) const {
auto iter = m_value.find(key); static auto iter = m_value.find(key);
return (iter == m_value.end()) ? static_null() : iter->second; return (iter == m_value.end()) ? static_null() : (*iter).second;
} }
const Json & JsonArray::operator[] (int i) const { const Json & JsonArray::operator[] (int i) const {
if (i >= m_value.size()) return static_null(); if (i >= m_value.size()) return static_null();
@ -385,7 +388,7 @@ struct JsonParser final {
* Advance until the current character is non-whitespace. * Advance until the current character is non-whitespace.
*/ */
void consume_whitespace() { void consume_whitespace() {
while (str[i] == ' ' || str[i] == '\r' || str[i] == '\n' || str[i] == '\t') while (i < str.length() && (str[i] == ' ' || str[i] == '\r' || str[i] == '\n' || str[i] == '\t'))
i++; i++;
} }
@ -639,7 +642,8 @@ struct JsonParser final {
Json expect(const QString &expected, Json res) { Json expect(const QString &expected, Json res) {
assert(i != 0); assert(i != 0);
i--; i--;
if (str == expected) { QString result = str.right(str.size() - i).left(expected.length());
if (result == expected) {
i += expected.length(); i += expected.length();
return res; return res;
} else { } else {
@ -678,7 +682,7 @@ struct JsonParser final {
return parse_string(); return parse_string();
if (ch == '{') { if (ch == '{') {
map<QString, Json> data; Json::object data;
ch = get_next_token(); ch = get_next_token();
if (ch == '}') if (ch == '}')
return data; return data;
@ -753,26 +757,4 @@ Json Json::parse(const QString &in, QString &err, JsonParse strategy) {
return result; return result;
} }
/* * * * * * * * * * * * * * * * * * * *
* Shape-checking
*/
bool Json::has_shape(const shape & types, QString & err) const {
if (!is_object()) {
err = "expected JSON object, got " + dump();
return false;
}
const auto& obj_items = object_items();
for (auto & item : types) {
const auto it = obj_items.find(item.first);
if (it == obj_items.cend() || it->second.type() != item.second) {
err = "bad type for " + item.first + " in " + dump();
return false;
}
}
return true;
}
} // namespace poryjson } // namespace poryjson

View file

@ -9,6 +9,8 @@
#include "tileset.h" #include "tileset.h"
#include "imageexport.h" #include "imageexport.h"
#include "orderedjson.h"
#include <QDir> #include <QDir>
#include <QJsonArray> #include <QJsonArray>
#include <QJsonDocument> #include <QJsonDocument>
@ -21,6 +23,9 @@
#include <QRegularExpression> #include <QRegularExpression>
#include <algorithm> #include <algorithm>
using OrderedJson = poryjson::Json;
using OrderedJsonDoc = poryjson::JsonDoc;
int Project::num_tiles_primary = 512; int Project::num_tiles_primary = 512;
int Project::num_tiles_total = 1024; int Project::num_tiles_total = 1024;
int Project::num_metatiles_primary = 512; int Project::num_metatiles_primary = 512;
@ -513,13 +518,13 @@ void Project::saveMapLayouts() {
return; return;
} }
QJsonObject layoutsObj; OrderedJson::object layoutsObj;
layoutsObj["layouts_table_label"] = layoutsLabel; layoutsObj["layouts_table_label"] = layoutsLabel;
QJsonArray layoutsArr; OrderedJson::array layoutsArr;
for (QString layoutId : mapLayoutsTableMaster) { for (QString layoutId : mapLayoutsTableMaster) {
MapLayout *layout = mapLayouts.value(layoutId); MapLayout *layout = mapLayouts.value(layoutId);
QJsonObject layoutObj; OrderedJson::object layoutObj;
layoutObj["id"] = layout->id; layoutObj["id"] = layout->id;
layoutObj["name"] = layout->name; layoutObj["name"] = layout->name;
layoutObj["width"] = layout->width.toInt(nullptr, 0); layoutObj["width"] = layout->width.toInt(nullptr, 0);
@ -528,12 +533,14 @@ void Project::saveMapLayouts() {
layoutObj["secondary_tileset"] = layout->tileset_secondary_label; layoutObj["secondary_tileset"] = layout->tileset_secondary_label;
layoutObj["border_filepath"] = layout->border_path; layoutObj["border_filepath"] = layout->border_path;
layoutObj["blockdata_filepath"] = layout->blockdata_path; layoutObj["blockdata_filepath"] = layout->blockdata_path;
layoutsArr.append(layoutObj); layoutsArr.push_back(layoutObj);
} }
layoutsObj["layouts"] = layoutsArr; layoutsObj["layouts"] = layoutsArr;
QJsonDocument layoutsDoc(layoutsObj); OrderedJson layoutJson(layoutsObj);
layoutsFile.write(layoutsDoc.toJson()); OrderedJsonDoc jsonDoc(&layoutJson);
jsonDoc.dump(&layoutsFile);
layoutsFile.close();
} }
void Project::setNewMapLayout(Map* map) { void Project::setNewMapLayout(Map* map) {
@ -562,27 +569,29 @@ void Project::saveMapGroups() {
return; return;
} }
QJsonObject mapGroupsObj; OrderedJson::object mapGroupsObj;
mapGroupsObj["layouts_table_label"] = layoutsLabel; mapGroupsObj["layouts_table_label"] = layoutsLabel;
QJsonArray groupNamesArr; OrderedJson::array groupNamesArr;
for (QString groupName : *this->groupNames) { for (QString groupName : *this->groupNames) {
groupNamesArr.append(groupName); groupNamesArr.push_back(groupName);
} }
mapGroupsObj["group_order"] = groupNamesArr; mapGroupsObj["group_order"] = groupNamesArr;
int groupNum = 0; int groupNum = 0;
for (QStringList mapNames : groupedMapNames) { for (QStringList mapNames : groupedMapNames) {
QJsonArray groupArr; OrderedJson::array groupArr;
for (QString mapName : mapNames) { for (QString mapName : mapNames) {
groupArr.append(mapName); groupArr.push_back(mapName);
} }
mapGroupsObj[this->groupNames->at(groupNum)] = groupArr; mapGroupsObj[this->groupNames->at(groupNum)] = groupArr;
groupNum++; groupNum++;
} }
QJsonDocument mapGroupsDoc(mapGroupsObj); OrderedJson mapGroupJson(mapGroupsObj);
mapGroupsFile.write(mapGroupsDoc.toJson()); OrderedJsonDoc jsonDoc(&mapGroupJson);
jsonDoc.dump(&mapGroupsFile);
mapGroupsFile.close();
} }
void Project::saveWildMonData() { void Project::saveWildMonData() {
@ -595,78 +604,79 @@ void Project::saveWildMonData() {
return; return;
} }
QJsonObject wildEncountersObject; OrderedJson::object wildEncountersObject;
QJsonArray wildEncounterGroups = QJsonArray(); OrderedJson::array wildEncounterGroups;
// gWildMonHeaders label is not mutable // gWildMonHeaders label is not mutable
QJsonObject monHeadersObject; OrderedJson::object monHeadersObject;
monHeadersObject["label"] = "gWildMonHeaders"; monHeadersObject["label"] = "gWildMonHeaders";
monHeadersObject["for_maps"] = true; monHeadersObject["for_maps"] = true;
QJsonArray fieldsInfoArray; OrderedJson::array fieldsInfoArray;
for (EncounterField fieldInfo : wildMonFields) { for (EncounterField fieldInfo : wildMonFields) {
QJsonObject fieldObject; OrderedJson::object fieldObject;
QJsonArray rateArray; OrderedJson::array rateArray;
for (int rate : fieldInfo.encounterRates) { for (int rate : fieldInfo.encounterRates) {
rateArray.append(rate); rateArray.push_back(rate);
} }
fieldObject["type"] = fieldInfo.name; fieldObject["type"] = fieldInfo.name;
fieldObject["encounter_rates"] = rateArray; fieldObject["encounter_rates"] = rateArray;
QJsonObject groupsObject; OrderedJson::object groupsObject;
for (QString groupName : fieldInfo.groups.keys()) { for (QString groupName : fieldInfo.groups.keys()) {
QJsonArray subGroupIndices; OrderedJson::array subGroupIndices;
std::sort(fieldInfo.groups[groupName].begin(), fieldInfo.groups[groupName].end()); std::sort(fieldInfo.groups[groupName].begin(), fieldInfo.groups[groupName].end());
for (int slotIndex : fieldInfo.groups[groupName]) { for (int slotIndex : fieldInfo.groups[groupName]) {
subGroupIndices.append(slotIndex); subGroupIndices.push_back(slotIndex);
} }
groupsObject[groupName] = subGroupIndices; groupsObject[groupName] = subGroupIndices;
} }
if (!groupsObject.isEmpty()) fieldObject["groups"] = groupsObject; if (!groupsObject.empty()) fieldObject["groups"] = groupsObject;
fieldsInfoArray.append(fieldObject); fieldsInfoArray.append(fieldObject);
} }
monHeadersObject["fields"] = fieldsInfoArray; monHeadersObject["fields"] = fieldsInfoArray;
QJsonArray encountersArray = QJsonArray(); OrderedJson::array encountersArray;
for (QString key : wildMonData.keys()) { for (QString key : wildMonData.keys()) {
for (QString groupLabel : wildMonData.value(key).keys()) { for (QString groupLabel : wildMonData.value(key).keys()) {
QJsonObject encounterObject; OrderedJson::object encounterObject;
encounterObject["map"] = key; encounterObject["map"] = key;
encounterObject["base_label"] = groupLabel; encounterObject["base_label"] = groupLabel;
WildPokemonHeader encounterHeader = wildMonData.value(key).value(groupLabel); WildPokemonHeader encounterHeader = wildMonData.value(key).value(groupLabel);
for (QString fieldName : encounterHeader.wildMons.keys()) { for (QString fieldName : encounterHeader.wildMons.keys()) {
QJsonObject fieldObject; OrderedJson::object fieldObject;
WildMonInfo monInfo = encounterHeader.wildMons.value(fieldName); WildMonInfo monInfo = encounterHeader.wildMons.value(fieldName);
fieldObject["encounter_rate"] = monInfo.encounterRate; fieldObject["encounter_rate"] = monInfo.encounterRate;
QJsonArray monArray; OrderedJson::array monArray;
for (WildPokemon wildMon : monInfo.wildPokemon) { for (WildPokemon wildMon : monInfo.wildPokemon) {
QJsonObject monEntry; OrderedJson::object monEntry;
monEntry["min_level"] = wildMon.minLevel; monEntry["min_level"] = wildMon.minLevel;
monEntry["max_level"] = wildMon.maxLevel; monEntry["max_level"] = wildMon.maxLevel;
monEntry["species"] = wildMon.species; monEntry["species"] = wildMon.species;
monArray.append(monEntry); monArray.push_back(monEntry);
} }
fieldObject["mons"] = monArray; fieldObject["mons"] = monArray;
encounterObject[fieldName] = fieldObject; encounterObject[fieldName] = fieldObject;
} }
encountersArray.append(encounterObject); encountersArray.push_back(encounterObject);
} }
} }
monHeadersObject["encounters"] = encountersArray; monHeadersObject["encounters"] = encountersArray;
wildEncounterGroups.append(monHeadersObject); wildEncounterGroups.push_back(monHeadersObject);
// add extra Json objects that are not associated with maps to the file // add extra Json objects that are not associated with maps to the file
for (QString label : extraEncounterGroups.keys()) { for (auto extraObject : extraEncounterGroups) {
wildEncounterGroups.append(extraEncounterGroups[label]); wildEncounterGroups.push_back(extraObject);
} }
wildEncountersObject["wild_encounter_groups"] = wildEncounterGroups; wildEncountersObject["wild_encounter_groups"] = wildEncounterGroups;
QJsonDocument wildEncountersDoc(wildEncountersObject); OrderedJson encounterJson(wildEncountersObject);
wildEncountersFile.write(wildEncountersDoc.toJson()); OrderedJsonDoc jsonDoc(&encounterJson);
jsonDoc.dump(&wildEncountersFile);
wildEncountersFile.close(); wildEncountersFile.close();
} }
@ -1105,7 +1115,7 @@ void Project::saveMap(Map *map) {
return; return;
} }
QJsonObject mapObj; OrderedJson::object mapObj;
// Header values. // Header values.
mapObj["id"] = map->constantName; mapObj["id"] = map->constantName;
mapObj["name"] = map->name; mapObj["name"] = map->name;
@ -1123,10 +1133,10 @@ void Project::saveMap(Map *map) {
// Connections // Connections
if (map->connections.length() > 0) { if (map->connections.length() > 0) {
QJsonArray connectionsArr; OrderedJson::array connectionsArr;
for (MapConnection* connection : map->connections) { for (MapConnection* connection : map->connections) {
if (mapNamesToMapConstants->contains(connection->map_name)) { if (mapNamesToMapConstants->contains(connection->map_name)) {
QJsonObject connectionObj; OrderedJson::object connectionObj;
connectionObj["direction"] = connection->direction; connectionObj["direction"] = connection->direction;
connectionObj["offset"] = connection->offset.toInt(); connectionObj["offset"] = connection->offset.toInt();
connectionObj["map"] = this->mapNamesToMapConstants->value(connection->map_name); connectionObj["map"] = this->mapNamesToMapConstants->value(connection->map_name);
@ -1142,51 +1152,51 @@ void Project::saveMap(Map *map) {
if (map->sharedEventsMap.isEmpty()) { if (map->sharedEventsMap.isEmpty()) {
// Object events // Object events
QJsonArray objectEventsArr; OrderedJson::array objectEventsArr;
for (int i = 0; i < map->events["object_event_group"].length(); i++) { for (int i = 0; i < map->events["object_event_group"].length(); i++) {
Event *object_event = map->events["object_event_group"].value(i); Event *object_event = map->events["object_event_group"].value(i);
QJsonObject eventObj = object_event->buildObjectEventJSON(); OrderedJson::object eventObj = object_event->buildObjectEventJSON();
objectEventsArr.append(eventObj); objectEventsArr.push_back(eventObj);
} }
mapObj["object_events"] = objectEventsArr; mapObj["object_events"] = objectEventsArr;
// Warp events // Warp events
QJsonArray warpEventsArr; OrderedJson::array warpEventsArr;
for (int i = 0; i < map->events["warp_event_group"].length(); i++) { for (int i = 0; i < map->events["warp_event_group"].length(); i++) {
Event *warp_event = map->events["warp_event_group"].value(i); Event *warp_event = map->events["warp_event_group"].value(i);
QJsonObject warpObj = warp_event->buildWarpEventJSON(mapNamesToMapConstants); OrderedJson::object warpObj = warp_event->buildWarpEventJSON(mapNamesToMapConstants);
warpEventsArr.append(warpObj); warpEventsArr.append(warpObj);
} }
mapObj["warp_events"] = warpEventsArr; mapObj["warp_events"] = warpEventsArr;
// Coord events // Coord events
QJsonArray coordEventsArr; OrderedJson::array coordEventsArr;
for (int i = 0; i < map->events["coord_event_group"].length(); i++) { for (int i = 0; i < map->events["coord_event_group"].length(); i++) {
Event *event = map->events["coord_event_group"].value(i); Event *event = map->events["coord_event_group"].value(i);
QString event_type = event->get("event_type"); QString event_type = event->get("event_type");
if (event_type == EventType::Trigger) { if (event_type == EventType::Trigger) {
QJsonObject triggerObj = event->buildTriggerEventJSON(); OrderedJson::object triggerObj = event->buildTriggerEventJSON();
coordEventsArr.append(triggerObj); coordEventsArr.append(triggerObj);
} else if (event_type == EventType::WeatherTrigger) { } else if (event_type == EventType::WeatherTrigger) {
QJsonObject weatherObj = event->buildWeatherTriggerEventJSON(); OrderedJson::object weatherObj = event->buildWeatherTriggerEventJSON();
coordEventsArr.append(weatherObj); coordEventsArr.append(weatherObj);
} }
} }
mapObj["coord_events"] = coordEventsArr; mapObj["coord_events"] = coordEventsArr;
// Bg Events // Bg Events
QJsonArray bgEventsArr; OrderedJson::array bgEventsArr;
for (int i = 0; i < map->events["bg_event_group"].length(); i++) { for (int i = 0; i < map->events["bg_event_group"].length(); i++) {
Event *event = map->events["bg_event_group"].value(i); Event *event = map->events["bg_event_group"].value(i);
QString event_type = event->get("event_type"); QString event_type = event->get("event_type");
if (event_type == EventType::Sign) { if (event_type == EventType::Sign) {
QJsonObject signObj = event->buildSignEventJSON(); OrderedJson::object signObj = event->buildSignEventJSON();
bgEventsArr.append(signObj); bgEventsArr.append(signObj);
} else if (event_type == EventType::HiddenItem) { } else if (event_type == EventType::HiddenItem) {
QJsonObject hiddenItemObj = event->buildHiddenItemEventJSON(); OrderedJson::object hiddenItemObj = event->buildHiddenItemEventJSON();
bgEventsArr.append(hiddenItemObj); bgEventsArr.append(hiddenItemObj);
} else if (event_type == EventType::SecretBase) { } else if (event_type == EventType::SecretBase) {
QJsonObject secretBaseObj = event->buildSecretBaseEventJSON(); OrderedJson::object secretBaseObj = event->buildSecretBaseEventJSON();
bgEventsArr.append(secretBaseObj); bgEventsArr.append(secretBaseObj);
} }
} }
@ -1204,8 +1214,9 @@ void Project::saveMap(Map *map) {
mapObj[key] = map->customHeaders[key]; mapObj[key] = map->customHeaders[key];
} }
QJsonDocument mapDoc(mapObj); OrderedJson mapJson(mapObj);
mapFile.write(mapDoc.toJson()); OrderedJsonDoc jsonDoc(&mapJson);
jsonDoc.dump(&mapFile);
mapFile.close(); mapFile.close();
saveLayoutBorder(map); saveLayoutBorder(map);
@ -1501,7 +1512,13 @@ bool Project::readWildMonData() {
for (auto subObjectRef : wildMonObj["wild_encounter_groups"].toArray()) { for (auto subObjectRef : wildMonObj["wild_encounter_groups"].toArray()) {
QJsonObject subObject = subObjectRef.toObject(); QJsonObject subObject = subObjectRef.toObject();
if (!subObject["for_maps"].toBool()) { if (!subObject["for_maps"].toBool()) {
extraEncounterGroups.insert(subObject["label"].toString(), subObject); QString err;
QString subObjson = QJsonDocument(subObject).toJson();
OrderedJson::object orderedSubObject = OrderedJson::parse(subObjson, err).object_items();
extraEncounterGroups.push_back(orderedSubObject);
if (!err.isEmpty()) {
logWarn(QString("Encountered a problem while parsing extra encounter groups: %1").arg(err));
}
continue; continue;
} }