From 6c3ee3c46d2f22f3320034786058fa4e0cf5edda Mon Sep 17 00:00:00 2001 From: garak <garakmon@gmail.com> Date: Thu, 12 Aug 2021 19:19:21 -0400 Subject: [PATCH] order wild encounter json reading --- include/core/parseutil.h | 1 + include/core/wildmoninfo.h | 5 +-- src/core/parseutil.cpp | 11 ++++++ src/core/wildmoninfo.cpp | 2 +- src/editor.cpp | 50 +++++++++++++++++---------- src/project.cpp | 71 ++++++++++++++++++++++---------------- src/ui/montabwidget.cpp | 12 ++++--- 7 files changed, 95 insertions(+), 57 deletions(-) diff --git a/include/core/parseutil.h b/include/core/parseutil.h index 009e07c3..d1ec1623 100644 --- a/include/core/parseutil.h +++ b/include/core/parseutil.h @@ -53,6 +53,7 @@ public: QList<QStringList> getLabelMacros(const QList<QStringList>&, const QString&); QStringList getLabelValues(const QList<QStringList>&, const QString&); bool tryParseJsonFile(QJsonDocument *out, const QString &filepath); + bool tryParseOrderedJsonFile(poryjson::Json::object *out, const QString &filepath); bool ensureFieldsExist(const QJsonObject &obj, const QList<QString> &fields); // Returns the 1-indexed line number for the definition of scriptLabel in the scripts file at filePath. diff --git a/include/core/wildmoninfo.h b/include/core/wildmoninfo.h index 06877622..a42522e7 100644 --- a/include/core/wildmoninfo.h +++ b/include/core/wildmoninfo.h @@ -3,6 +3,7 @@ #define GUARD_WILDMONINFO_H #include <QtWidgets> +#include "orderedmap.h" struct WildPokemon { int minLevel = 5; @@ -17,13 +18,13 @@ struct WildMonInfo { }; struct WildPokemonHeader { - QHash<QString, WildMonInfo> wildMons; + tsl::ordered_map<QString, WildMonInfo> wildMons; }; struct EncounterField { QString name; QVector<int> encounterRates; - QMap<QString, QVector<int>> groups; + tsl::ordered_map<QString, QVector<int>> groups; }; typedef QVector<EncounterField> EncounterFields; diff --git a/src/core/parseutil.cpp b/src/core/parseutil.cpp index 79464b8b..fad3c804 100644 --- a/src/core/parseutil.cpp +++ b/src/core/parseutil.cpp @@ -404,6 +404,17 @@ bool ParseUtil::tryParseJsonFile(QJsonDocument *out, const QString &filepath) { return true; } +bool ParseUtil::tryParseOrderedJsonFile(poryjson::Json::object *out, const QString &filepath) { + QString err; + QString jsonTxt = readTextFile(filepath); + *out = OrderedJson::parse(jsonTxt, err).object_items(); + if (!err.isEmpty()) { + logError(QString("Error: Failed to parse json file %1: %2").arg(filepath).arg(err)); + return false; + } + return true; +} + bool ParseUtil::ensureFieldsExist(const QJsonObject &obj, const QList<QString> &fields) { for (QString field : fields) { if (!obj.contains(field)) { diff --git a/src/core/wildmoninfo.cpp b/src/core/wildmoninfo.cpp index a6e730e3..2fe9be7a 100644 --- a/src/core/wildmoninfo.cpp +++ b/src/core/wildmoninfo.cpp @@ -19,7 +19,7 @@ WildMonInfo copyMonInfoFromTab(QTableWidget *monTable, EncounterField monField) WildMonInfo newInfo; QVector<WildPokemon> newWildMons; - bool extraColumn = !monField.groups.isEmpty(); + bool extraColumn = !monField.groups.empty(); for (int row = 0; row < monTable->rowCount(); row++) { WildPokemon newWildMon; newWildMon.species = monTable->cellWidget(row, extraColumn ? 2 : 1)->findChild<QComboBox *>()->currentText(); diff --git a/src/editor.cpp b/src/editor.cpp index bd7b0caa..87574adc 100644 --- a/src/editor.cpp +++ b/src/editor.cpp @@ -340,12 +340,14 @@ void Editor::addNewWildMonGroup(QWidget *window) { if (fieldCheckboxes[tabIndex]->isChecked()) { if (copyCheckbox->isChecked()) { MonTabWidget *copyFrom = static_cast<MonTabWidget *>(stack->widget(stackIndex)); - if (copyFrom->isTabEnabled(tabIndex)) - header.wildMons.insert(fieldName, copyMonInfoFromTab(copyFrom->tableAt(tabIndex), monField)); - else - header.wildMons.insert(fieldName, getDefaultMonInfo(monField)); + if (copyFrom->isTabEnabled(tabIndex)) { + header.wildMons[fieldName] = copyMonInfoFromTab(copyFrom->tableAt(tabIndex), monField); + } + else { + header.wildMons[fieldName] = getDefaultMonInfo(monField); + } } else { - header.wildMons.insert(fieldName, getDefaultMonInfo(monField)); + header.wildMons[fieldName] = getDefaultMonInfo(monField); } tabWidget->populateTab(tabIndex, header.wildMons[fieldName], fieldName); } else { @@ -409,14 +411,16 @@ void Editor::configureEncounterJSON(QWidget *window) { int total = 0, spinnerIndex = 0; QString groupTotalMessage; QMap<QString, int> groupTotals; - for (QString key : currentField.groups.keys()) - groupTotals.insert(key, 0);// add to group map and initialize total to zero + for (auto keyPair : currentField.groups) { + groupTotals.insert(keyPair.first, 0);// add to group map and initialize total to zero + } for (auto slot : fieldSlots) { QSpinBox *spinner = slot->findChild<QSpinBox *>(); int val = spinner->value(); currentField.encounterRates[spinnerIndex] = val; - if (!currentField.groups.isEmpty()) { - for (QString key : currentField.groups.keys()) { + if (!currentField.groups.empty()) { + for (auto keyPair : currentField.groups) { + QString key = keyPair.first; if (currentField.groups[key].contains(spinnerIndex)) { groupTotals[key] += val; break; @@ -427,9 +431,10 @@ void Editor::configureEncounterJSON(QWidget *window) { } spinnerIndex++; } - if (!currentField.groups.isEmpty()) { + if (!currentField.groups.empty()) { groupTotalMessage += "Totals: "; - for (QString key : currentField.groups.keys()) { + for (auto keyPair : currentField.groups) { + QString key = keyPair.first; groupTotalMessage += QString("%1 (%2),\t").arg(groupTotals[key]).arg(key); } groupTotalMessage.chop(2); @@ -456,7 +461,7 @@ void Editor::configureEncounterJSON(QWidget *window) { updateTotal(currentField); }); - bool useGroups = !currentField.groups.isEmpty(); + bool useGroups = !currentField.groups.empty(); QFrame *slotChoiceFrame = new QFrame; QVBoxLayout *slotChoiceLayout = new QVBoxLayout; @@ -465,22 +470,27 @@ void Editor::configureEncounterJSON(QWidget *window) { connect(groupCombo, QOverload<const QString &>::of(&QComboBox::textActivated), [&tempFields, ¤tField, index](QString newGroupName) { for (EncounterField &field : tempFields) { if (field.name == currentField.name) { - for (QString groupName : field.groups.keys()) { + for (auto groupNameIterator : field.groups) { + QString groupName = groupNameIterator.first; if (field.groups[groupName].contains(index)) { field.groups[groupName].removeAll(index); break; } } - for (QString groupName : field.groups.keys()) { + for (auto groupNameIterator : field.groups) { + QString groupName = groupNameIterator.first; if (groupName == newGroupName) field.groups[newGroupName].append(index); } break; } } }); - groupCombo->addItems(currentField.groups.keys()); + for (auto groupNameIterator : currentField.groups) { + groupCombo->addItem(groupNameIterator.first); + } QString currentGroupName; - for (QString groupName : currentField.groups.keys()) { + for (auto groupNameIterator : currentField.groups) { + QString groupName = groupNameIterator.first; if (currentField.groups[groupName].contains(index)) { currentGroupName = groupName; break; @@ -676,7 +686,8 @@ void Editor::updateEncounterFields(EncounterFields newFields) { for (auto groupNamePair : project->wildMonData[map]) { QString groupName = groupNamePair.first; WildPokemonHeader &monHeader = project->wildMonData[map][groupName]; - for (QString fieldName : monHeader.wildMons.keys()) { + for (auto fieldNamePair : monHeader.wildMons) { + QString fieldName = fieldNamePair.first; if (fieldName == oldFieldName) { monHeader.wildMons[fieldName].wildPokemon.resize(newField.encounterRates.size()); } @@ -692,9 +703,10 @@ void Editor::updateEncounterFields(EncounterFields newFields) { for (auto groupNamePair : project->wildMonData[map]) { QString groupName = groupNamePair.first; WildPokemonHeader &monHeader = project->wildMonData[map][groupName]; - for (QString fieldName : monHeader.wildMons.keys()) { + for (auto fieldNamePair : monHeader.wildMons) { + QString fieldName = fieldNamePair.first; if (fieldName == oldFieldName) { - monHeader.wildMons.remove(fieldName); + monHeader.wildMons.erase(fieldName); } } } diff --git a/src/project.cpp b/src/project.cpp index 3217da1c..7051dcd0 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -730,7 +730,8 @@ void Project::saveWildMonData() { fieldObject["encounter_rates"] = rateArray; OrderedJson::object groupsObject; - for (QString groupName : fieldInfo.groups.keys()) { + for (auto groupNamePair : fieldInfo.groups) { + QString groupName = groupNamePair.first; OrderedJson::array subGroupIndices; std::sort(fieldInfo.groups[groupName].begin(), fieldInfo.groups[groupName].end()); for (int slotIndex : fieldInfo.groups[groupName]) { @@ -754,9 +755,10 @@ void Project::saveWildMonData() { encounterObject["base_label"] = groupLabel; WildPokemonHeader encounterHeader = wildMonData[key][groupLabel]; - for (QString fieldName : encounterHeader.wildMons.keys()) { + for (auto fieldNamePair : encounterHeader.wildMons) { + QString fieldName = fieldNamePair.first; OrderedJson::object fieldObject; - WildMonInfo monInfo = encounterHeader.wildMons.value(fieldName); + WildMonInfo monInfo = encounterHeader.wildMons[fieldName]; fieldObject["encounter_rate"] = monInfo.encounterRate; OrderedJson::array monArray; for (WildPokemon wildMon : monInfo.wildPokemon) { @@ -1726,20 +1728,18 @@ bool Project::readWildMonData() { QString wildMonJsonFilepath = QString("%1/src/data/wild_encounters.json").arg(root); fileWatcher.addPath(wildMonJsonFilepath); - QJsonDocument wildMonsJsonDoc; - if (!parser.tryParseJsonFile(&wildMonsJsonDoc, wildMonJsonFilepath)) { + + OrderedJson::object wildMonObj; + if (!parser.tryParseOrderedJsonFile(&wildMonObj, wildMonJsonFilepath)) { logError(QString("Failed to read wild encounters from %1").arg(wildMonJsonFilepath)); return false; } - QJsonObject wildMonObj = wildMonsJsonDoc.object(); - - for (auto subObjectRef : wildMonObj["wild_encounter_groups"].toArray()) { - QJsonObject subObject = subObjectRef.toObject(); - if (!subObject["for_maps"].toBool()) { + for (OrderedJson subObjectRef : wildMonObj["wild_encounter_groups"].array_items()) { + OrderedJson::object subObject = subObjectRef.object_items(); + if (!subObject["for_maps"].bool_value()) { QString err; - QString subObjson = QJsonDocument(subObject).toJson(); - OrderedJson::object orderedSubObject = OrderedJson::parse(subObjson, err).object_items(); + OrderedJson::object orderedSubObject = OrderedJson::parse(OrderedJson(subObject).dump(), err).object_items(); extraEncounterGroups.push_back(orderedSubObject); if (!err.isEmpty()) { logWarn(QString("Encountered a problem while parsing extra encounter groups: %1").arg(err)); @@ -1747,44 +1747,55 @@ bool Project::readWildMonData() { continue; } - for (auto field : subObject["fields"].toArray()) { + for (OrderedJson field : subObject["fields"].array_items()) { EncounterField encounterField; - encounterField.name = field.toObject()["type"].toString(); - for (auto val : field.toObject()["encounter_rates"].toArray()) { - encounterField.encounterRates.append(val.toInt()); + OrderedJson::object fieldObj = field.object_items(); + encounterField.name = fieldObj["type"].string_value(); + for (auto val : fieldObj["encounter_rates"].array_items()) { + encounterField.encounterRates.append(val.int_value()); } - for (QString group : field.toObject()["groups"].toObject().keys()) { - for (auto slotNum : field.toObject()["groups"].toObject()[group].toArray()) { - encounterField.groups[group].append(slotNum.toInt()); + + QList<QString> subGroups; + for (auto groupPair : fieldObj["groups"].object_items()) { + subGroups.append(groupPair.first); + } + for (QString group : subGroups) { + OrderedJson::object groupsObj = fieldObj["groups"].object_items(); + for (auto slotNum : groupsObj[group].array_items()) { + encounterField.groups[group].append(slotNum.int_value()); } } wildMonFields.append(encounterField); } - QJsonArray encounters = subObject["encounters"].toArray(); - for (QJsonValue encounter : encounters) { - QString mapConstant = encounter.toObject().value("map").toString(); + auto encounters = subObject["encounters"].array_items(); + for (auto encounter : encounters) { + OrderedJson::object encounterObj = encounter.object_items(); + QString mapConstant = encounterObj["map"].string_value(); WildPokemonHeader header; for (EncounterField monField : wildMonFields) { QString field = monField.name; - if (encounter.toObject().value(field) != QJsonValue::Undefined) { + if (!encounterObj[field].is_null()) { + OrderedJson::object encounterFieldObj = encounterObj[field].object_items(); header.wildMons[field].active = true; - header.wildMons[field].encounterRate = encounter.toObject().value(field).toObject().value("encounter_rate").toInt(); - for (QJsonValue mon : encounter.toObject().value(field).toObject().value("mons").toArray()) { + header.wildMons[field].encounterRate = encounterFieldObj["encounter_rate"].int_value(); + for (auto mon : encounterFieldObj["mons"].array_items()) { WildPokemon newMon; - newMon.minLevel = mon.toObject().value("min_level").toInt(); - newMon.maxLevel = mon.toObject().value("max_level").toInt(); - newMon.species = mon.toObject().value("species").toString(); + OrderedJson::object monObj = mon.object_items(); + newMon.minLevel = monObj["min_level"].int_value(); + newMon.maxLevel = monObj["max_level"].int_value(); + newMon.species = monObj["species"].string_value(); header.wildMons[field].wildPokemon.append(newMon); } } } - wildMonData[mapConstant].insert({encounter.toObject().value("base_label").toString(), header}); - encounterGroupLabels.append(encounter.toObject().value("base_label").toString()); + wildMonData[mapConstant].insert({encounterObj["base_label"].string_value(), header}); + encounterGroupLabels.append(encounterObj["base_label"].string_value()); } } + return true; } diff --git a/src/ui/montabwidget.cpp b/src/ui/montabwidget.cpp index bc3c24e8..765749ca 100644 --- a/src/ui/montabwidget.cpp +++ b/src/ui/montabwidget.cpp @@ -71,7 +71,7 @@ void MonTabWidget::populateTab(int tabIndex, WildMonInfo monInfo, QString fieldN fieldIndex++; } bool insertGroupLabel = false; - if (!editor->project->wildMonFields[fieldIndex].groups.isEmpty()) insertGroupLabel = true; + if (!editor->project->wildMonFields[fieldIndex].groups.empty()) insertGroupLabel = true; speciesTable->setRowCount(monInfo.wildPokemon.size()); speciesTable->setColumnCount(insertGroupLabel ? 8 : 7); @@ -159,8 +159,9 @@ void MonTabWidget::createSpeciesTableRow(QTableWidget *table, WildPokemon mon, i } double slotChanceTotal = 0.0; - if (!editor->project->wildMonFields[fieldIndex].groups.isEmpty()) { - for (QString groupKey : editor->project->wildMonFields[fieldIndex].groups.keys()) { + if (!editor->project->wildMonFields[fieldIndex].groups.empty()) { + for (auto groupKeyPair : editor->project->wildMonFields[fieldIndex].groups) { + QString groupKey = groupKeyPair.first; if (editor->project->wildMonFields[fieldIndex].groups[groupKey].contains(index)) { for (int chanceIndex : editor->project->wildMonFields[fieldIndex].groups[groupKey]) { slotChanceTotal += static_cast<double>(editor->project->wildMonFields[fieldIndex].encounterRates[chanceIndex]); @@ -198,11 +199,12 @@ void MonTabWidget::createSpeciesTableRow(QTableWidget *table, WildPokemon mon, i maxLevelFrame->setLayout(maxLevelSpinboxLayout); bool insertGroupLabel = false; - if (!editor->project->wildMonFields[fieldIndex].groups.isEmpty()) insertGroupLabel = true; + if (!editor->project->wildMonFields[fieldIndex].groups.empty()) insertGroupLabel = true; table->setCellWidget(index, 0, monNum); if (insertGroupLabel) { QString groupName = QString(); - for (QString groupKey : editor->project->wildMonFields[fieldIndex].groups.keys()) { + for (auto groupKeyPair : editor->project->wildMonFields[fieldIndex].groups) { + QString groupKey = groupKeyPair.first; if (editor->project->wildMonFields[fieldIndex].groups[groupKey].contains(index)) { groupName = groupKey; break;