Add explicit type conversions for ordered json

This commit is contained in:
GriffinR 2026-01-23 21:16:47 -05:00
parent af931c7f4d
commit e012b790a8
6 changed files with 86 additions and 59 deletions

View File

@ -183,6 +183,12 @@ public:
// Return a reference to obj[key] if this is an object, Json() otherwise.
const Json & operator[](const QString &key) const;
// Equivalent to string_value(), int_value(), and bool_value(),
// but will attempt to convert the internal value if it's of a different type.
QString toString() const;
int toInt() const;
bool toBool() const;
// Serialize.
void dump(QString &out, int *) const;
QString dump(int *indent = nullptr) const {
@ -251,8 +257,11 @@ protected:
virtual void dump(QString &out, int *indent) const = 0;
virtual double number_value() const;
virtual int int_value() const;
virtual int toInt() const;
virtual bool bool_value() const;
virtual bool toBool() const;
virtual const QString &string_value() const;
virtual QString toString() const;
virtual const Json::array &array_items() const;
virtual const Json &operator[](int i) const;
virtual const Json::object &object_items() const;

View File

@ -27,7 +27,7 @@ RegionMap::RegionMap(Project *project) :
bool RegionMap::loadMapData(poryjson::Json data) {
poryjson::Json::object mapObject = data.object_items();
this->alias = mapObject["alias"].string_value();
this->alias = mapObject["alias"].toString();
poryjson::Json tilemapJson = mapObject["tilemap"];
poryjson::Json layoutJson = mapObject["layout"];
@ -63,19 +63,19 @@ bool RegionMap::loadTilemap(poryjson::Json tilemapJson) {
poryjson::Json::object tilemapObject = tilemapJson.object_items();
this->tilemap_width = tilemapObject["width"].int_value();
this->tilemap_height = tilemapObject["height"].int_value();
this->tilemap_width = tilemapObject["width"].toInt();
this->tilemap_height = tilemapObject["height"].toInt();
QString tilemapFormat = tilemapObject["format"].string_value();
QString tilemapFormat = tilemapObject["format"].toString();
QMap<QString, TilemapFormat> formatsMap = { {"plain", TilemapFormat::Plain}, {"4bpp", TilemapFormat::BPP_4}, {"8bpp", TilemapFormat::BPP_8} };
this->tilemap_format = formatsMap[tilemapFormat];
this->tileset_path = tilemapObject["tileset_path"].string_value();
this->tilemap_path = tilemapObject["tilemap_path"].string_value();
this->tileset_path = tilemapObject["tileset_path"].toString();
this->tilemap_path = tilemapObject["tilemap_path"].toString();
if (tilemapObject.contains("palette")) {
this->palette_path = tilemapObject["palette"].string_value();
this->palette_path = tilemapObject["palette"].toString();
}
QImage tilesetFile(fullPath(this->tileset_path));
@ -118,16 +118,16 @@ bool RegionMap::loadLayout(poryjson::Json layoutJson) {
poryjson::Json::object layoutObject = layoutJson.object_items();
QString layoutFormat = layoutObject["format"].string_value();
QString layoutFormat = layoutObject["format"].toString();
QMap<QString, LayoutFormat> layoutFormatMap = { {"binary", LayoutFormat::Binary}, {"C array", LayoutFormat::CArray} };
this->layout_format = layoutFormatMap[layoutFormat];
this->layout_path = layoutObject["path"].string_value();
this->layout_width = layoutObject["width"].int_value();
this->layout_height = layoutObject["height"].int_value();
this->layout_path = layoutObject["path"].toString();
this->layout_width = layoutObject["width"].toInt();
this->layout_height = layoutObject["height"].toInt();
this->offset_left = layoutObject["offset_left"].int_value();
this->offset_top = layoutObject["offset_top"].int_value();
this->offset_left = layoutObject["offset_left"].toInt();
this->offset_top = layoutObject["offset_top"].toInt();
bool errored = false;

View File

@ -162,6 +162,8 @@ protected:
class JsonDouble final : public Value<Json::NUMBER, double> {
double number_value() const override { return m_value; }
int int_value() const override { return static_cast<int>(m_value); }
QString toString() const override { return QString::number(m_value); }
bool toBool() const override { return m_value != 0; }
bool equals(const JsonValue * other) const override { return m_value == other->number_value(); }
bool less(const JsonValue * other) const override { return m_value < other->number_value(); }
public:
@ -171,6 +173,8 @@ public:
class JsonInt final : public Value<Json::NUMBER, int> {
double number_value() const override { return m_value; }
int int_value() const override { return m_value; }
QString toString() const override { return QString::number(m_value); }
bool toBool() const override { return m_value != 0; }
bool equals(const JsonValue * other) const override { return m_value == other->number_value(); }
bool less(const JsonValue * other) const override { return m_value < other->number_value(); }
public:
@ -179,12 +183,20 @@ public:
class JsonBoolean final : public Value<Json::BOOL, bool> {
bool bool_value() const override { return m_value; }
QString toString() const override { return m_value ? "true" : "false"; }
int toInt() const override { return m_value ? 1 : 0; }
public:
explicit JsonBoolean(bool value) : Value(value) {}
};
class JsonString final : public Value<Json::STRING, QString> {
const QString &string_value() const override { return m_value; }
int toInt() const override {
if (QString::compare(m_value, "true", Qt::CaseInsensitive) == 0) return 1;
if (QString::compare(m_value, "false", Qt::CaseInsensitive) == 0) return 0;
return m_value.toInt(nullptr, 0);
}
bool toBool() const override { return toInt() != 0; }
public:
explicit JsonString(const QString &value) : Value(value) {}
explicit JsonString(QString &&value) : Value(std::move(value)) {}
@ -244,8 +256,8 @@ Json::Json(std::nullptr_t) noexcept : m_ptr(statics().null) {}
Json::Json(double value) : m_ptr(make_shared<JsonDouble>(value)) {}
Json::Json(int value) : m_ptr(make_shared<JsonInt>(value)) {}
Json::Json(bool value) : m_ptr(value ? statics().t : statics().f) {}
Json::Json(const QString &value) : m_ptr(make_shared<JsonString>(value)) {}
Json::Json(QString &&value) : m_ptr(make_shared<JsonString>(std::move(value))) {}
Json::Json(const QString &value) : m_ptr(make_shared<JsonString>(value)) {}
Json::Json(QString &&value) : m_ptr(make_shared<JsonString>(std::move(value))) {}
Json::Json(const char * value) : m_ptr(make_shared<JsonString>(value)) {}
Json::Json(const Json::array &values) : m_ptr(make_shared<JsonArray>(values)) {}
Json::Json(Json::array &&values) : m_ptr(make_shared<JsonArray>(std::move(values))) {}
@ -256,24 +268,30 @@ Json::Json(Json::object &&values) : m_ptr(make_shared<JsonObject>(std::move
* Accessors
*/
Json::Type Json::type() const { return m_ptr->type(); }
double Json::number_value() const { return m_ptr->number_value(); }
int Json::int_value() const { return m_ptr->int_value(); }
bool Json::bool_value() const { return m_ptr->bool_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 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[] (const QString &key) const { return (*m_ptr)[key]; }
Json::Type Json::type() const { return m_ptr->type(); }
double Json::number_value() const { return m_ptr->number_value(); }
int Json::int_value() const { return m_ptr->int_value(); }
int Json::toInt() const { return m_ptr->toInt(); }
bool Json::bool_value() const { return m_ptr->bool_value(); }
bool Json::toBool() const { return m_ptr->toBool(); }
const QString & Json::string_value() const { return m_ptr->string_value(); }
QString Json::toString() const { return m_ptr->toString(); }
const QVector<Json> & Json::array_items() const { return m_ptr->array_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[] (const QString &key) const { return (*m_ptr)[key]; }
double JsonValue::number_value() const { return 0; }
int JsonValue::int_value() const { return 0; }
bool JsonValue::bool_value() const { return false; }
const QString & JsonValue::string_value() const { return statics().empty_string; }
const QVector<Json> & JsonValue::array_items() const { return statics().empty_vector; }
const Json::object & JsonValue::object_items() const { return statics().empty_map; }
const Json & JsonValue::operator[] (int) const { return static_null(); }
const Json & JsonValue::operator[] (const QString &) const { return static_null(); }
double JsonValue::number_value() const { return 0; }
int JsonValue::int_value() const { return 0; }
int JsonValue::toInt() const { return int_value(); }
bool JsonValue::bool_value() const { return false; }
bool JsonValue::toBool() const { return bool_value(); }
const QString & JsonValue::string_value() const { return statics().empty_string; }
QString JsonValue::toString() const { return string_value(); }
const QVector<Json> & JsonValue::array_items() const { return statics().empty_vector; }
const Json::object & JsonValue::object_items() const { return statics().empty_map; }
const Json & JsonValue::operator[] (int) const { return static_null(); }
const Json & JsonValue::operator[] (const QString &) const { return static_null(); }
const Json & JsonObject::operator[] (const QString &key) const {
static auto iter = m_value.find(key);

View File

@ -1792,7 +1792,7 @@ bool Project::readWildMonData() {
// We're only interested in wild encounter data that's associated with maps ("for_maps" == true).
// Any other wild encounter data (e.g. for Battle Pike / Battle Pyramid) will be ignored.
// We'll record any data that's not for maps in extraEncounterGroups to be outputted when we save.
if (!mainArrayObject["for_maps"].bool_value()) {
if (!mainArrayObject["for_maps"].toBool()) {
this->extraEncounterGroups.push_back(mainArrayObject);
continue;
} else {
@ -1802,7 +1802,7 @@ bool Project::readWildMonData() {
}
// If multiple "for_maps" data sets are found they will be collapsed into a single set.
QString label = mainArrayObject.take("label").string_value();
QString label = mainArrayObject.take("label").toString();
if (this->wildMonTableName.isEmpty()) {
this->wildMonTableName = label;
} else {
@ -1820,11 +1820,11 @@ bool Project::readWildMonData() {
OrderedJson::object fieldObject = fieldJson.object_items();
EncounterField encounterField;
encounterField.name = fieldObject.take("type").string_value();
encounterField.name = fieldObject.take("type").toString();
OrderedJson::array encounterRatesArray = fieldObject.take("encounter_rates").array_items();
for (const auto &val : encounterRatesArray) {
encounterField.encounterRates.append(val.int_value());
encounterField.encounterRates.append(val.toInt());
}
// Each element of the "groups" array is an object with the group name as the key (e.g. "old_rod")
@ -1833,7 +1833,7 @@ bool Project::readWildMonData() {
for (auto groupPair : groups) {
const QString groupName = groupPair.first;
for (auto slotNum : groupPair.second.array_items()) {
encounterField.groups[groupName].append(slotNum.int_value());
encounterField.groups[groupName].append(slotNum.toInt());
}
}
encounterField.customData = fieldObject;
@ -1865,7 +1865,7 @@ bool Project::readWildMonData() {
monInfo.active = true;
// Read encounter rate
monInfo.encounterRate = encounterFieldObj.take("encounter_rate").int_value();
monInfo.encounterRate = encounterFieldObj.take("encounter_rate").toInt();
encounterRateFrequencyMaps[field][monInfo.encounterRate]++;
// Read wild pokémon list
@ -1874,9 +1874,9 @@ bool Project::readWildMonData() {
OrderedJson::object monObj = monJson.object_items();
WildPokemon newMon;
newMon.minLevel = monObj.take("min_level").int_value();
newMon.maxLevel = monObj.take("max_level").int_value();
newMon.species = monObj.take("species").string_value();
newMon.minLevel = monObj.take("min_level").toInt();
newMon.maxLevel = monObj.take("max_level").toInt();
newMon.species = monObj.take("species").toString();
newMon.customData = monObj;
monInfo.wildPokemon.append(newMon);
}
@ -1888,8 +1888,8 @@ bool Project::readWildMonData() {
}
header.wildMons[field] = monInfo;
}
const QString mapConstant = encounterObj.take("map").string_value();
const QString baseLabel = encounterObj.take("base_label").string_value();
const QString mapConstant = encounterObj.take("map").toString();
const QString baseLabel = encounterObj.take("base_label").toString();
header.customData = encounterObj;
this->wildMonData[mapConstant].insert({baseLabel, header});
this->encounterGroupLabels.append(baseLabel);

View File

@ -184,7 +184,7 @@ bool RegionMapEditor::buildConfigDialog() {
for (auto o : mapsObject["region_maps"].array_items()) {
poryjson::Json::object object = o.object_items();
QListWidgetItem *newItem = new QListWidgetItem;
newItem->setText(object["alias"].string_value());
newItem->setText(object["alias"].toString());
QString objectString;
int i = 0;
o.dump(objectString, &i);
@ -245,7 +245,7 @@ bool RegionMapEditor::buildConfigDialog() {
resultJson.dump(resultStr, &tab);
QListWidgetItem *newItem = new QListWidgetItem;
newItem->setText(resultObj["alias"].string_value());
newItem->setText(resultObj["alias"].toString());
newItem->setData(Qt::UserRole, resultStr);
regionMapList->addItem(newItem);
updateJsonFromList();
@ -398,7 +398,7 @@ bool RegionMapEditor::setup() {
// load the region maps into this->region_maps
poryjson::Json::object regionMapObjectCopy = this->rmConfigJson.object_items();
for (auto o : regionMapObjectCopy["region_maps"].array_items()) {
QString alias = o.object_items().at("alias").string_value();
QString alias = o.object_items().at("alias").toString();
RegionMap *newMap = new RegionMap(this->project);
newMap->setEntries(&this->region_map_entries);

View File

@ -44,30 +44,30 @@ void RegionMapPropertiesDialog::setProperties(poryjson::Json json) {
poryjson::Json::object object = json.object_items();
// Region Map Properties
ui->config_alias->setText(object["alias"].string_value());
ui->config_alias->setText(object["alias"].toString());
// Tilemap properties
poryjson::Json::object tilemap = object["tilemap"].object_items();
ui->config_tilemapFormat->setCurrentText(tilemap["format"].string_value());
ui->config_tilemapWidth->setValue(tilemap["width"].int_value());
ui->config_tilemapHeight->setValue(tilemap["height"].int_value());
ui->config_tilemapFormat->setCurrentText(tilemap["format"].toString());
ui->config_tilemapWidth->setValue(tilemap["width"].toInt());
ui->config_tilemapHeight->setValue(tilemap["height"].toInt());
ui->config_tilemapImagePath->setText(tilemap["tileset_path"].string_value());
ui->config_tilemapBinPath->setText(tilemap["tilemap_path"].string_value());
ui->config_tilemapImagePath->setText(tilemap["tileset_path"].toString());
ui->config_tilemapBinPath->setText(tilemap["tilemap_path"].toString());
if (tilemap.contains("palette"))
ui->config_tilemapPalettePath->setText(tilemap["palette"].string_value());
ui->config_tilemapPalettePath->setText(tilemap["palette"].toString());
// Layout props
if (object["layout"].is_null()) {
ui->group_layout->setChecked(false);
} else {
poryjson::Json::object layout = object["layout"].object_items();
ui->config_layoutFormat->setCurrentText(layout["format"].string_value());
ui->config_layoutPath->setText(layout["path"].string_value());
ui->config_layoutWidth->setValue(layout["width"].int_value());
ui->config_layoutHeight->setValue(layout["height"].int_value());
ui->config_leftOffs->setValue(layout["offset_left"].int_value());
ui->config_topOffs->setValue(layout["offset_top"].int_value());
ui->config_layoutFormat->setCurrentText(layout["format"].toString());
ui->config_layoutPath->setText(layout["path"].toString());
ui->config_layoutWidth->setValue(layout["width"].toInt());
ui->config_layoutHeight->setValue(layout["height"].toInt());
ui->config_leftOffs->setValue(layout["offset_left"].toInt());
ui->config_topOffs->setValue(layout["offset_top"].toInt());
}
}