diff --git a/src/openrct2/object/BannerObject.cpp b/src/openrct2/object/BannerObject.cpp index 70f0a6ae54..d756b2f568 100644 --- a/src/openrct2/object/BannerObject.cpp +++ b/src/openrct2/object/BannerObject.cpp @@ -14,7 +14,6 @@ #include "../localisation/Language.h" #include "../object/Object.h" #include "../object/ObjectRepository.h" -#include "ObjectJsonHelpers.h" #include "ObjectList.h" void BannerObject::ReadLegacy(IReadObjectContext* context, OpenRCT2::IStream* stream) @@ -82,20 +81,23 @@ void BannerObject::DrawPreview(rct_drawpixelinfo* dpi, int32_t width, int32_t he gfx_draw_sprite(dpi, imageId + 1, screenCoords + ScreenCoordsXY{ -12, 8 }, 0); } -void BannerObject::ReadJson(IReadObjectContext* context, const json_t* root) +void BannerObject::ReadJson(IReadObjectContext* context, json_t& root) { - auto properties = json_object_get(root, "properties"); + Guard::Assert(root.is_object(), "BannerObject::ReadJson expects parameter root to be object"); + json_t properties = root["properties"]; - _legacyType.banner.scrolling_mode = json_integer_value(json_object_get(properties, "scrollingMode")); - _legacyType.banner.price = json_integer_value(json_object_get(properties, "price")); - _legacyType.banner.flags = ObjectJsonHelpers::GetFlags( - properties, - { - { "hasPrimaryColour", BANNER_ENTRY_FLAG_HAS_PRIMARY_COLOUR }, - }); + if (properties.is_object()) + { + _legacyType.banner.scrolling_mode = Json::GetNumber(properties["scrollingMode"]); + _legacyType.banner.price = Json::GetNumber(properties["price"]); + _legacyType.banner.flags = Json::GetFlags( + properties, + { + { "hasPrimaryColour", BANNER_ENTRY_FLAG_HAS_PRIMARY_COLOUR }, + }); - SetPrimarySceneryGroup(ObjectJsonHelpers::GetString(json_object_get(properties, "sceneryGroup"))); + SetPrimarySceneryGroup(Json::GetString(properties["sceneryGroup"])); + } - ObjectJsonHelpers::LoadStrings(root, GetStringTable()); - ObjectJsonHelpers::LoadImages(context, root, GetImageTable()); + PopulateTablesFromJson(context, root); } diff --git a/src/openrct2/object/BannerObject.h b/src/openrct2/object/BannerObject.h index ea8ad00418..1877ce6d25 100644 --- a/src/openrct2/object/BannerObject.h +++ b/src/openrct2/object/BannerObject.h @@ -30,7 +30,7 @@ public: } void ReadLegacy(IReadObjectContext* context, OpenRCT2::IStream* stream) override; - void ReadJson(IReadObjectContext* context, const json_t* root) override; + void ReadJson(IReadObjectContext* context, json_t& root) override; void Load() override; void Unload() override; diff --git a/src/openrct2/object/EntranceObject.cpp b/src/openrct2/object/EntranceObject.cpp index be979fdcd5..974917bbb1 100644 --- a/src/openrct2/object/EntranceObject.cpp +++ b/src/openrct2/object/EntranceObject.cpp @@ -13,7 +13,6 @@ #include "../core/String.hpp" #include "../drawing/Drawing.h" #include "../localisation/Localisation.h" -#include "ObjectJsonHelpers.h" void EntranceObject::ReadLegacy(IReadObjectContext* context, OpenRCT2::IStream* stream) { @@ -51,12 +50,17 @@ void EntranceObject::DrawPreview(rct_drawpixelinfo* dpi, int32_t width, int32_t gfx_draw_sprite(dpi, imageId + 2, screenCoords + ScreenCoordsXY{ 32, 44 }, 0); } -void EntranceObject::ReadJson(IReadObjectContext* context, const json_t* root) +void EntranceObject::ReadJson(IReadObjectContext* context, json_t& root) { - auto properties = json_object_get(root, "properties"); - _legacyType.scrolling_mode = json_integer_value(json_object_get(properties, "scrollingMode")); - _legacyType.text_height = json_integer_value(json_object_get(properties, "textHeight")); + Guard::Assert(root.is_object(), "EntranceObject::ReadJson expects parameter root to be object"); - ObjectJsonHelpers::LoadStrings(root, GetStringTable()); - ObjectJsonHelpers::LoadImages(context, root, GetImageTable()); + json_t properties = root["properties"]; + + if (properties.is_object()) + { + _legacyType.scrolling_mode = Json::GetNumber(properties["scrollingMode"]); + _legacyType.text_height = Json::GetNumber(properties["textHeight"]); + } + + PopulateTablesFromJson(context, root); } diff --git a/src/openrct2/object/EntranceObject.h b/src/openrct2/object/EntranceObject.h index 4a9c48dda1..45e4d8dc72 100644 --- a/src/openrct2/object/EntranceObject.h +++ b/src/openrct2/object/EntranceObject.h @@ -29,7 +29,7 @@ public: } void ReadLegacy(IReadObjectContext* context, OpenRCT2::IStream* stream) override; - void ReadJson(IReadObjectContext* context, const json_t* root) override; + void ReadJson(IReadObjectContext* context, json_t& root) override; void Load() override; void Unload() override; diff --git a/src/openrct2/object/FootpathItemObject.cpp b/src/openrct2/object/FootpathItemObject.cpp index 8c9fb14e6d..e3352db258 100644 --- a/src/openrct2/object/FootpathItemObject.cpp +++ b/src/openrct2/object/FootpathItemObject.cpp @@ -15,7 +15,6 @@ #include "../localisation/Localisation.h" #include "../object/Object.h" #include "../object/ObjectRepository.h" -#include "ObjectJsonHelpers.h" #include "ObjectList.h" #include @@ -98,40 +97,36 @@ static uint8_t ParseDrawType(const std::string& s) return PATH_BIT_DRAW_TYPE_LIGHTS; } -void FootpathItemObject::ReadJson(IReadObjectContext* context, const json_t* root) +void FootpathItemObject::ReadJson(IReadObjectContext* context, json_t& root) { - auto properties = json_object_get(root, "properties"); - _legacyType.path_bit.draw_type = ParseDrawType(ObjectJsonHelpers::GetString(properties, "renderAs")); - _legacyType.path_bit.tool_id = ObjectJsonHelpers::ParseCursor( - ObjectJsonHelpers::GetString(properties, "cursor"), CURSOR_LAMPPOST_DOWN); - _legacyType.path_bit.price = json_integer_value(json_object_get(properties, "price")); + Guard::Assert(root.is_object(), "FootpathItemObject::ReadJson expects parameter root to be object"); - SetPrimarySceneryGroup(ObjectJsonHelpers::GetString(json_object_get(properties, "sceneryGroup"))); + json_t properties = root["properties"]; - // Flags - _legacyType.path_bit.flags = ObjectJsonHelpers::GetFlags( - properties, - { - { "isBin", PATH_BIT_FLAG_IS_BIN }, - { "isBench", PATH_BIT_FLAG_IS_BENCH }, - { "isBreakable", PATH_BIT_FLAG_BREAKABLE }, - { "isLamp", PATH_BIT_FLAG_LAMP }, - { "isJumpingFountainWater", PATH_BIT_FLAG_JUMPING_FOUNTAIN_WATER }, - { "isJumpingFountainSnow", PATH_BIT_FLAG_JUMPING_FOUNTAIN_SNOW }, - { "isTelevision", PATH_BIT_FLAG_IS_QUEUE_SCREEN }, - }); - - // HACK To avoid 'negated' properties in JSON, handle these separately until - // flags are inverted in this code base. - if (!ObjectJsonHelpers::GetBoolean(properties, "isAllowedOnQueue", false)) + if (properties.is_object()) { - _legacyType.path_bit.flags |= PATH_BIT_FLAG_DONT_ALLOW_ON_QUEUE; - } - if (!ObjectJsonHelpers::GetBoolean(properties, "isAllowedOnSlope", false)) - { - _legacyType.path_bit.flags |= PATH_BIT_FLAG_DONT_ALLOW_ON_SLOPE; + _legacyType.path_bit.draw_type = ParseDrawType(Json::GetString(properties["renderAs"])); + _legacyType.path_bit.tool_id = Cursor::FromString(Json::GetString(properties["cursor"]), CURSOR_LAMPPOST_DOWN); + _legacyType.path_bit.price = Json::GetNumber(properties["price"]); + + SetPrimarySceneryGroup(Json::GetString(properties["sceneryGroup"])); + + // clang-format off + _legacyType.path_bit.flags = Json::GetFlags( + properties, + { + { "isBin", PATH_BIT_FLAG_IS_BIN, Json::FlagType::Normal }, + { "isBench", PATH_BIT_FLAG_IS_BENCH, Json::FlagType::Normal }, + { "isBreakable", PATH_BIT_FLAG_BREAKABLE, Json::FlagType::Normal }, + { "isLamp", PATH_BIT_FLAG_LAMP, Json::FlagType::Normal }, + { "isJumpingFountainWater", PATH_BIT_FLAG_JUMPING_FOUNTAIN_WATER, Json::FlagType::Normal }, + { "isJumpingFountainSnow", PATH_BIT_FLAG_JUMPING_FOUNTAIN_SNOW, Json::FlagType::Normal }, + { "isAllowedOnQueue", PATH_BIT_FLAG_DONT_ALLOW_ON_QUEUE, Json::FlagType::Inverted }, + { "isAllowedOnSlope", PATH_BIT_FLAG_DONT_ALLOW_ON_SLOPE, Json::FlagType::Inverted }, + { "isTelevision", PATH_BIT_FLAG_IS_QUEUE_SCREEN, Json::FlagType::Normal }, + }); + // clang-format on } - ObjectJsonHelpers::LoadStrings(root, GetStringTable()); - ObjectJsonHelpers::LoadImages(context, root, GetImageTable()); + PopulateTablesFromJson(context, root); } diff --git a/src/openrct2/object/FootpathItemObject.h b/src/openrct2/object/FootpathItemObject.h index 4e6be3eb6c..4bbcc8741a 100644 --- a/src/openrct2/object/FootpathItemObject.h +++ b/src/openrct2/object/FootpathItemObject.h @@ -29,7 +29,7 @@ public: } void ReadLegacy(IReadObjectContext* context, OpenRCT2::IStream* stream) override; - void ReadJson(IReadObjectContext* context, const json_t* root) override; + void ReadJson(IReadObjectContext* context, json_t& root) override; void Load() override; void Unload() override; diff --git a/src/openrct2/object/FootpathObject.cpp b/src/openrct2/object/FootpathObject.cpp index 4356a9ceb1..4e3b8bc0a6 100644 --- a/src/openrct2/object/FootpathObject.cpp +++ b/src/openrct2/object/FootpathObject.cpp @@ -10,10 +10,10 @@ #include "FootpathObject.h" #include "../core/IStream.hpp" +#include "../core/Json.hpp" #include "../drawing/Drawing.h" #include "../localisation/Language.h" #include "../world/Footpath.h" -#include "ObjectJsonHelpers.h" void FootpathObject::ReadLegacy(IReadObjectContext* context, OpenRCT2::IStream* stream) { @@ -83,21 +83,25 @@ static RailingEntrySupportType ParseSupportType(const std::string& s) return RailingEntrySupportType::Box; } -void FootpathObject::ReadJson(IReadObjectContext* context, const json_t* root) +void FootpathObject::ReadJson(IReadObjectContext* context, json_t& root) { - auto properties = json_object_get(root, "properties"); - _legacyType.support_type = ParseSupportType(ObjectJsonHelpers::GetString(json_object_get(properties, "supportType"))); - _legacyType.scrolling_mode = json_integer_value(json_object_get(properties, "scrollingMode")); + Guard::Assert(root.is_object(), "FootpathObject::ReadJson expects parameter root to be object"); - // Flags - _legacyType.flags = ObjectJsonHelpers::GetFlags( - properties, - { - { "hasSupportImages", RAILING_ENTRY_FLAG_HAS_SUPPORT_BASE_SPRITE }, - { "hasElevatedPathImages", RAILING_ENTRY_FLAG_DRAW_PATH_OVER_SUPPORTS }, - { "editorOnly", FOOTPATH_ENTRY_FLAG_SHOW_ONLY_IN_SCENARIO_EDITOR }, - }); + auto properties = root["properties"]; - ObjectJsonHelpers::LoadStrings(root, GetStringTable()); - ObjectJsonHelpers::LoadImages(context, root, GetImageTable()); + if (properties.is_object()) + { + _legacyType.support_type = ParseSupportType(Json::GetString(properties["supportType"])); + _legacyType.scrolling_mode = Json::GetNumber(properties["scrollingMode"]); + + _legacyType.flags = Json::GetFlags( + properties, + { + { "hasSupportImages", RAILING_ENTRY_FLAG_HAS_SUPPORT_BASE_SPRITE }, + { "hasElevatedPathImages", RAILING_ENTRY_FLAG_DRAW_PATH_OVER_SUPPORTS }, + { "editorOnly", FOOTPATH_ENTRY_FLAG_SHOW_ONLY_IN_SCENARIO_EDITOR }, + }); + } + + PopulateTablesFromJson(context, root); } diff --git a/src/openrct2/object/FootpathObject.h b/src/openrct2/object/FootpathObject.h index 88766b2abe..7fe5274cdb 100644 --- a/src/openrct2/object/FootpathObject.h +++ b/src/openrct2/object/FootpathObject.h @@ -47,7 +47,7 @@ public: } void ReadLegacy(IReadObjectContext* context, OpenRCT2::IStream* stream) override; - void ReadJson(IReadObjectContext* context, const json_t* root) override; + void ReadJson(IReadObjectContext* context, json_t& root) override; void Load() override; void Unload() override; diff --git a/src/openrct2/object/LargeSceneryObject.cpp b/src/openrct2/object/LargeSceneryObject.cpp index 3358d79f7c..3ab667c39d 100644 --- a/src/openrct2/object/LargeSceneryObject.cpp +++ b/src/openrct2/object/LargeSceneryObject.cpp @@ -12,13 +12,13 @@ #include "LargeSceneryObject.h" #include "../core/IStream.hpp" +#include "../core/Json.hpp" #include "../core/Memory.hpp" #include "../drawing/Drawing.h" #include "../interface/Cursors.h" #include "../localisation/Language.h" #include "../world/Banner.h" #include "../world/Location.hpp" -#include "ObjectJsonHelpers.h" #include #include @@ -121,84 +121,83 @@ std::vector LargeSceneryObject::ReadTiles(OpenRCT2::IStr return tiles; } -void LargeSceneryObject::ReadJson(IReadObjectContext* context, const json_t* root) +void LargeSceneryObject::ReadJson(IReadObjectContext* context, json_t& root) { - auto properties = json_object_get(root, "properties"); + Guard::Assert(root.is_object(), "LargeSceneryObject::ReadJson expects parameter root to be object"); - _legacyType.large_scenery.tool_id = ObjectJsonHelpers::ParseCursor( - ObjectJsonHelpers::GetString(properties, "cursor"), CURSOR_STATUE_DOWN); - _legacyType.large_scenery.price = json_integer_value(json_object_get(properties, "price")); - _legacyType.large_scenery.removal_price = json_integer_value(json_object_get(properties, "removalPrice")); + auto properties = root["properties"]; - auto jScrollingMode = json_object_get(properties, "scrollingMode"); - _legacyType.large_scenery.scrolling_mode = jScrollingMode != nullptr ? json_integer_value(jScrollingMode) - : SCROLLING_MODE_NONE; + if (properties.is_object()) + { + _legacyType.large_scenery.tool_id = Cursor::FromString(Json::GetString(properties["cursor"]), CURSOR_STATUE_DOWN); - // Flags - _legacyType.large_scenery.flags = ObjectJsonHelpers::GetFlags( - properties, + _legacyType.large_scenery.price = Json::GetNumber(properties["price"]); + _legacyType.large_scenery.removal_price = Json::GetNumber(properties["removalPrice"]); + + _legacyType.large_scenery.scrolling_mode = Json::GetNumber(properties["scrollingMode"], SCROLLING_MODE_NONE); + + _legacyType.large_scenery.flags = Json::GetFlags( + properties, + { + { "hasPrimaryColour", LARGE_SCENERY_FLAG_HAS_PRIMARY_COLOUR }, + { "hasSecondaryColour", LARGE_SCENERY_FLAG_HAS_SECONDARY_COLOUR }, + { "isAnimated", LARGE_SCENERY_FLAG_ANIMATED }, + { "isPhotogenic", LARGE_SCENERY_FLAG_PHOTOGENIC }, + }); + + // Tiles + auto jTiles = properties["tiles"]; + if (jTiles.is_array()) { - { "hasPrimaryColour", LARGE_SCENERY_FLAG_HAS_PRIMARY_COLOUR }, - { "hasSecondaryColour", LARGE_SCENERY_FLAG_HAS_SECONDARY_COLOUR }, - { "isAnimated", LARGE_SCENERY_FLAG_ANIMATED }, - { "isPhotogenic", LARGE_SCENERY_FLAG_PHOTOGENIC }, - }); + _tiles = ReadJsonTiles(jTiles); + } - // Tiles - auto jTiles = json_object_get(properties, "tiles"); - if (jTiles != nullptr) - { - _tiles = ReadJsonTiles(jTiles); + // Read text + auto j3dFont = properties["3dFont"]; + if (j3dFont.is_object()) + { + _3dFont = ReadJson3dFont(j3dFont); + _legacyType.large_scenery.flags |= LARGE_SCENERY_FLAG_3D_TEXT; + } + + SetPrimarySceneryGroup(Json::GetString(properties["sceneryGroup"])); } - // Read text - auto j3dFont = json_object_get(properties, "3dFont"); - if (j3dFont != nullptr) - { - _3dFont = ReadJson3dFont(j3dFont); - _legacyType.large_scenery.flags |= LARGE_SCENERY_FLAG_3D_TEXT; - } - - SetPrimarySceneryGroup(ObjectJsonHelpers::GetString(json_object_get(properties, "sceneryGroup"))); - - ObjectJsonHelpers::LoadStrings(root, GetStringTable()); - ObjectJsonHelpers::LoadImages(context, root, GetImageTable()); + PopulateTablesFromJson(context, root); } -std::vector LargeSceneryObject::ReadJsonTiles(const json_t* jTiles) +std::vector LargeSceneryObject::ReadJsonTiles(json_t& jTiles) { std::vector tiles; - size_t index; - const json_t* jTile; - json_array_foreach(jTiles, index, jTile) + + for (auto& jTile : jTiles) { - rct_large_scenery_tile tile = {}; - tile.x_offset = json_integer_value(json_object_get(jTile, "x")); - tile.y_offset = json_integer_value(json_object_get(jTile, "y")); - tile.z_offset = json_integer_value(json_object_get(jTile, "z")); - tile.z_clearance = json_integer_value(json_object_get(jTile, "clearance")); - if (!ObjectJsonHelpers::GetBoolean(jTile, "hasSupports")) + if (jTile.is_object()) { - tile.flags |= LARGE_SCENERY_TILE_FLAG_NO_SUPPORTS; - } - if (ObjectJsonHelpers::GetBoolean(jTile, "allowSupportsAbove")) - { - tile.flags |= LARGE_SCENERY_TILE_FLAG_ALLOW_SUPPORTS_ABOVE; - } + rct_large_scenery_tile tile = {}; + tile.x_offset = Json::GetNumber(jTile["x"]); + tile.y_offset = Json::GetNumber(jTile["y"]); + tile.z_offset = Json::GetNumber(jTile["z"]); + tile.z_clearance = Json::GetNumber(jTile["clearance"]); - // All corners are by default occupied - auto jCorners = json_object_get(jTile, "corners"); - auto corners = 0xF; - if (jCorners != nullptr) - { - corners = json_integer_value(jCorners); + // clang-format off + tile.flags = Json::GetFlags( + jTile, + { + {"hasSupports", LARGE_SCENERY_TILE_FLAG_NO_SUPPORTS, Json::FlagType::Inverted}, + {"allowSupportsAbove", LARGE_SCENERY_TILE_FLAG_ALLOW_SUPPORTS_ABOVE, Json::FlagType::Normal} + }); + // clang-format on + + // All corners are by default occupied + uint16_t corners = Json::GetNumber(jTile["corners"], 0xF); + tile.flags |= (corners & 0xFF) << 12; + + auto walls = Json::GetNumber(jTile["walls"]); + tile.flags |= (walls & 0xFF) << 8; + + tiles.push_back(tile); } - tile.flags |= (corners & 0xFF) << 12; - - auto walls = json_integer_value(json_object_get(jTile, "walls")); - tile.flags |= (walls & 0xFF) << 8; - - tiles.push_back(tile); } // HACK Add end of tiles marker @@ -208,29 +207,32 @@ std::vector LargeSceneryObject::ReadJsonTiles(const json return tiles; } -std::unique_ptr LargeSceneryObject::ReadJson3dFont(const json_t* j3dFont) +std::unique_ptr LargeSceneryObject::ReadJson3dFont(json_t& j3dFont) { + Guard::Assert(j3dFont.is_object(), "LargeSceneryObject::ReadJson3dFont expects parameter j3dFont to be object"); + auto font = std::make_unique(); - auto jOffsets = json_object_get(j3dFont, "offsets"); - if (jOffsets != nullptr) + auto jOffsets = j3dFont["offsets"]; + if (jOffsets.is_array()) { auto offsets = ReadJsonOffsets(jOffsets); auto numOffsets = std::min(std::size(font->offset), offsets.size()); std::copy_n(offsets.data(), numOffsets, font->offset); } - font->max_width = json_integer_value(json_object_get(j3dFont, "maxWidth")); - font->num_images = json_integer_value(json_object_get(j3dFont, "numImages")); - font->flags = ObjectJsonHelpers::GetFlags( + font->max_width = Json::GetNumber(j3dFont["maxWidth"]); + font->num_images = Json::GetNumber(j3dFont["numImages"]); + + font->flags = Json::GetFlags( j3dFont, { { "isVertical", LARGE_SCENERY_TEXT_FLAG_VERTICAL }, { "isTwoLine", LARGE_SCENERY_TEXT_FLAG_TWO_LINE }, }); - auto jGlyphs = json_object_get(j3dFont, "glyphs"); - if (jGlyphs != nullptr) + auto jGlyphs = j3dFont["glyphs"]; + if (jGlyphs.is_array()) { auto glyphs = ReadJsonGlyphs(jGlyphs); auto numGlyphs = std::min(std::size(font->glyphs), glyphs.size()); @@ -240,33 +242,35 @@ std::unique_ptr LargeSceneryObject::ReadJson3dFont(const return font; } -std::vector LargeSceneryObject::ReadJsonOffsets(const json_t* jOffsets) +std::vector LargeSceneryObject::ReadJsonOffsets(json_t& jOffsets) { std::vector offsets; - size_t index; - const json_t* jOffset; - json_array_foreach(jOffsets, index, jOffset) + for (auto& jOffset : jOffsets) { - LocationXY16 offset = {}; - offset.x = json_integer_value(json_object_get(jOffset, "x")); - offset.y = json_integer_value(json_object_get(jOffset, "y")); - offsets.push_back(offset); + if (jOffset.is_object()) + { + LocationXY16 offset = {}; + offset.x = Json::GetNumber(jOffset["x"]); + offset.y = Json::GetNumber(jOffset["y"]); + offsets.push_back(offset); + } } return offsets; } -std::vector LargeSceneryObject::ReadJsonGlyphs(const json_t* jGlpyhs) +std::vector LargeSceneryObject::ReadJsonGlyphs(json_t& jGlyphs) { std::vector glyphs; - size_t index; - const json_t* jGlyph; - json_array_foreach(jGlpyhs, index, jGlyph) + for (auto& jGlyph : jGlyphs) { - rct_large_scenery_text_glyph glyph = {}; - glyph.image_offset = json_integer_value(json_object_get(jGlyph, "image")); - glyph.width = json_integer_value(json_object_get(jGlyph, "width")); - glyph.height = json_integer_value(json_object_get(jGlyph, "height")); - glyphs.push_back(glyph); + if (jGlyph.is_object()) + { + rct_large_scenery_text_glyph glyph = {}; + glyph.image_offset = Json::GetNumber(jGlyph["image"]); + glyph.width = Json::GetNumber(jGlyph["width"]); + glyph.height = Json::GetNumber(jGlyph["height"]); + glyphs.push_back(glyph); + } } return glyphs; } diff --git a/src/openrct2/object/LargeSceneryObject.h b/src/openrct2/object/LargeSceneryObject.h index 9b13c034a9..36ffd7b5c1 100644 --- a/src/openrct2/object/LargeSceneryObject.h +++ b/src/openrct2/object/LargeSceneryObject.h @@ -35,7 +35,7 @@ public: } void ReadLegacy(IReadObjectContext* context, OpenRCT2::IStream* stream) override; - void ReadJson(IReadObjectContext* context, const json_t* root) override; + void ReadJson(IReadObjectContext* context, json_t& root) override; void Load() override; void Unload() override; @@ -43,8 +43,8 @@ public: private: static std::vector ReadTiles(OpenRCT2::IStream* stream); - static std::vector ReadJsonTiles(const json_t* jTiles); - static std::unique_ptr ReadJson3dFont(const json_t* j3dFont); - static std::vector ReadJsonOffsets(const json_t* jOffsets); - static std::vector ReadJsonGlyphs(const json_t* jGlpyhs); + static std::vector ReadJsonTiles(json_t& jTiles); + static std::unique_ptr ReadJson3dFont(json_t& j3dFont); + static std::vector ReadJsonOffsets(json_t& jOffsets); + static std::vector ReadJsonGlyphs(json_t& jGlyphs); }; diff --git a/src/openrct2/object/RideObject.cpp b/src/openrct2/object/RideObject.cpp index 3e2e7cac68..9955f0616e 100644 --- a/src/openrct2/object/RideObject.cpp +++ b/src/openrct2/object/RideObject.cpp @@ -23,7 +23,6 @@ #include "../ride/RideData.h" #include "../ride/ShopItem.h" #include "../ride/Track.h" -#include "ObjectJsonHelpers.h" #include "ObjectRepository.h" #include @@ -523,175 +522,161 @@ uint8_t RideObject::CalculateNumHorizontalFrames(const rct_ride_entry_vehicle* v return numHorizontalFrames; } -void RideObject::ReadJson(IReadObjectContext* context, const json_t* root) +void RideObject::ReadJson(IReadObjectContext* context, json_t& root) { - auto properties = json_object_get(root, "properties"); + Guard::Assert(root.is_object(), "RideObject::ReadJson expects parameter root to be object"); - auto rideTypes = ObjectJsonHelpers::GetJsonStringArray(json_object_get(properties, "type")); - for (size_t i = 0; i < MAX_RIDE_TYPES_PER_RIDE_ENTRY; i++) + json_t properties = root["properties"]; + + if (properties.is_object()) { - uint8_t rideType = RIDE_TYPE_NULL; - if (i < rideTypes.size()) + // This will convert a string to an array + json_t rideTypes = Json::AsArray(properties["type"]); + size_t numRideTypes = rideTypes.size(); + + for (size_t i = 0; i < MAX_RIDE_TYPES_PER_RIDE_ENTRY; i++) { - rideType = ParseRideType(rideTypes[i]); - if (rideType == RIDE_TYPE_NULL) + uint8_t rideType = RIDE_TYPE_NULL; + + if (i < numRideTypes) { - context->LogError(OBJECT_ERROR_INVALID_PROPERTY, "Unknown ride type"); + rideType = ParseRideType(Json::GetString(rideTypes[i])); + + if (rideType == RIDE_TYPE_NULL) + { + context->LogError(OBJECT_ERROR_INVALID_PROPERTY, "Unknown ride type"); + } + } + + _legacyType.ride_type[i] = rideType; + } + + _legacyType.max_height = Json::GetNumber(properties["maxHeight"]); + + // This needs to be set for both shops/facilities _and_ regular rides. + for (auto& item : _legacyType.shop_item) + { + item = SHOP_ITEM_NONE; + } + + auto carColours = Json::AsArray(properties["carColours"]); + _presetColours = ReadJsonCarColours(carColours); + + if (IsRideTypeShopOrFacility(_legacyType.ride_type[0])) + { + // Standard car info for a shop + auto& car = _legacyType.vehicles[0]; + car.spacing = 544; + car.sprite_flags = VEHICLE_SPRITE_FLAG_FLAT; + car.sprite_width = 1; + car.sprite_height_negative = 1; + car.sprite_height_positive = 1; + car.flags = VEHICLE_ENTRY_FLAG_SPINNING; + car.car_visual = VEHICLE_VISUAL_FLAT_RIDE_OR_CAR_RIDE; + car.friction_sound_id = SoundId::Null; + car.sound_range = 0xFF; + car.draw_order = 6; + + // Shop item + auto rideSells = Json::AsArray(properties["sells"]); + auto numShopItems = std::min(static_cast(NUM_SHOP_ITEMS_PER_RIDE), rideSells.size()); + for (size_t i = 0; i < numShopItems; i++) + { + auto shopItem = ParseShopItem(Json::GetString(rideSells[i])); + if (shopItem == SHOP_ITEM_NONE) + { + context->LogWarning(OBJECT_ERROR_INVALID_PROPERTY, "Unknown shop item"); + } + + _legacyType.shop_item[i] = shopItem; + } + } + else + { + ReadJsonVehicleInfo(context, properties); + + auto swingMode = Json::GetNumber(properties["swingMode"]); + if (swingMode == 1) + { + _legacyType.flags |= RIDE_ENTRY_FLAG_ALTERNATIVE_SWING_MODE_1; + } + else if (swingMode == 2) + { + _legacyType.flags |= RIDE_ENTRY_FLAG_ALTERNATIVE_SWING_MODE_1; + _legacyType.flags |= RIDE_ENTRY_FLAG_ALTERNATIVE_SWING_MODE_2; + } + + auto rotationMode = Json::GetNumber(properties["rotationMode"]); + if (rotationMode == 1) + { + _legacyType.flags |= RIDE_ENTRY_FLAG_ALTERNATIVE_ROTATION_MODE_1; + } + else if (rotationMode == 2) + { + _legacyType.flags |= RIDE_ENTRY_FLAG_ALTERNATIVE_ROTATION_MODE_2; + } + + auto ratingMultiplier = properties["ratingMultipler"]; + if (ratingMultiplier.is_object()) + { + _legacyType.excitement_multiplier = Json::GetNumber(ratingMultiplier["excitement"]); + _legacyType.intensity_multiplier = Json::GetNumber(ratingMultiplier["intensity"]); + _legacyType.nausea_multiplier = Json::GetNumber(ratingMultiplier["nausea"]); } } - _legacyType.ride_type[i] = rideType; - } - - _legacyType.max_height = ObjectJsonHelpers::GetInteger(properties, "maxHeight"); - - // This needs to be set for both shops/facilities _and_ regular rides. - for (auto& item : _legacyType.shop_item) - { - item = SHOP_ITEM_NONE; - } - - _presetColours = ReadJsonCarColours(json_object_get(properties, "carColours")); - - if (IsRideTypeShopOrFacility(_legacyType.ride_type[0])) - { - // Standard car info for a shop - auto& car = _legacyType.vehicles[0]; - car.spacing = 544; - car.sprite_flags = VEHICLE_SPRITE_FLAG_FLAT; - car.sprite_width = 1; - car.sprite_height_negative = 1; - car.sprite_height_positive = 1; - car.flags = VEHICLE_ENTRY_FLAG_SPINNING; - car.car_visual = VEHICLE_VISUAL_FLAT_RIDE_OR_CAR_RIDE; - car.friction_sound_id = SoundId::Null; - car.sound_range = 0xFF; - car.draw_order = 6; - - // Shop item - auto rideSells = ObjectJsonHelpers::GetJsonStringArray(json_object_get(json_object_get(root, "properties"), "sells")); - auto numShopItems = std::min(static_cast(NUM_SHOP_ITEMS_PER_RIDE), rideSells.size()); - for (size_t i = 0; i < numShopItems; i++) - { - auto shopItem = ParseShopItem(rideSells[i]); - if (shopItem == SHOP_ITEM_NONE) + _legacyType.BuildMenuPriority = Json::GetNumber(properties["buildMenuPriority"]); + _legacyType.flags |= Json::GetFlags( + properties, { - context->LogWarning(OBJECT_ERROR_INVALID_PROPERTY, "Unknown shop item"); - } - - _legacyType.shop_item[i] = ParseShopItem(rideSells[i]); - } + { "noInversions", RIDE_ENTRY_FLAG_NO_INVERSIONS }, + { "noBanking", RIDE_ENTRY_FLAG_NO_BANKED_TRACK }, + { "playDepartSound", RIDE_ENTRY_FLAG_PLAY_DEPART_SOUND }, + // Skipping "disallowWandering", no vehicle sets this flag. + { "playSplashSound", RIDE_ENTRY_FLAG_PLAY_SPLASH_SOUND }, + { "playSplashSoundSlide", RIDE_ENTRY_FLAG_PLAY_SPLASH_SOUND_SLIDE }, + { "hasShelter", RIDE_ENTRY_FLAG_COVERED_RIDE }, + { "limitAirTimeBonus", RIDE_ENTRY_FLAG_LIMIT_AIRTIME_BONUS }, + { "disableBreakdown", RIDE_ENTRY_FLAG_CANNOT_BREAK_DOWN }, + // Skipping noDoorsOverTrack, moved to ride groups. + { "noCollisionCrashes", RIDE_ENTRY_FLAG_DISABLE_COLLISION_CRASHES }, + { "disablePainting", RIDE_ENTRY_FLAG_DISABLE_COLOUR_TAB }, + }); } - else - { - ReadJsonVehicleInfo(context, properties); - - auto swingMode = ObjectJsonHelpers::GetInteger(properties, "swingMode"); - if (swingMode == 1) - { - _legacyType.flags |= RIDE_ENTRY_FLAG_ALTERNATIVE_SWING_MODE_1; - } - else if (swingMode == 2) - { - _legacyType.flags |= RIDE_ENTRY_FLAG_ALTERNATIVE_SWING_MODE_1; - _legacyType.flags |= RIDE_ENTRY_FLAG_ALTERNATIVE_SWING_MODE_2; - } - - auto rotationMode = ObjectJsonHelpers::GetInteger(properties, "rotationMode"); - if (rotationMode == 1) - { - _legacyType.flags |= RIDE_ENTRY_FLAG_ALTERNATIVE_ROTATION_MODE_1; - } - else if (rotationMode == 2) - { - _legacyType.flags |= RIDE_ENTRY_FLAG_ALTERNATIVE_ROTATION_MODE_2; - } - - auto ratingMultiplier = json_object_get(properties, "ratingMultipler"); - if (ratingMultiplier != nullptr) - { - _legacyType.excitement_multiplier = ObjectJsonHelpers::GetInteger(ratingMultiplier, "excitement"); - _legacyType.intensity_multiplier = ObjectJsonHelpers::GetInteger(ratingMultiplier, "intensity"); - _legacyType.nausea_multiplier = ObjectJsonHelpers::GetInteger(ratingMultiplier, "nausea"); - } - - auto availableTrackPieces = ObjectJsonHelpers::GetJsonStringArray(json_object_get(properties, "availableTrackPieces")); - } - - _legacyType.BuildMenuPriority = ObjectJsonHelpers::GetInteger(properties, "buildMenuPriority", 0); - _legacyType.flags |= ObjectJsonHelpers::GetFlags( - properties, - { - { "noInversions", RIDE_ENTRY_FLAG_NO_INVERSIONS }, - { "noBanking", RIDE_ENTRY_FLAG_NO_BANKED_TRACK }, - { "playDepartSound", RIDE_ENTRY_FLAG_PLAY_DEPART_SOUND }, - // Skipping "disallowWandering", no vehicle sets this flag. - { "playSplashSound", RIDE_ENTRY_FLAG_PLAY_SPLASH_SOUND }, - { "playSplashSoundSlide", RIDE_ENTRY_FLAG_PLAY_SPLASH_SOUND_SLIDE }, - { "hasShelter", RIDE_ENTRY_FLAG_COVERED_RIDE }, - { "limitAirTimeBonus", RIDE_ENTRY_FLAG_LIMIT_AIRTIME_BONUS }, - { "disableBreakdown", RIDE_ENTRY_FLAG_CANNOT_BREAK_DOWN }, - // Skipping noDoorsOverTrack, moved to ride groups. - { "noCollisionCrashes", RIDE_ENTRY_FLAG_DISABLE_COLLISION_CRASHES }, - { "disablePainting", RIDE_ENTRY_FLAG_DISABLE_COLOUR_TAB }, - }); RideObjectUpdateRideType(&_legacyType); - ObjectJsonHelpers::LoadStrings(root, GetStringTable()); - ObjectJsonHelpers::LoadImages(context, root, GetImageTable()); + PopulateTablesFromJson(context, root); } -void RideObject::ReadJsonVehicleInfo([[maybe_unused]] IReadObjectContext* context, const json_t* properties) +void RideObject::ReadJsonVehicleInfo([[maybe_unused]] IReadObjectContext* context, json_t& properties) { - _legacyType.min_cars_in_train = ObjectJsonHelpers::GetInteger(properties, "minCarsPerTrain", 1); - _legacyType.max_cars_in_train = ObjectJsonHelpers::GetInteger(properties, "maxCarsPerTrain", 1); - _legacyType.cars_per_flat_ride = ObjectJsonHelpers::GetInteger(properties, "carsPerFlatRide", 255); - _legacyType.zero_cars = json_integer_value(json_object_get(properties, "numEmptyCars")); + Guard::Assert(properties.is_object(), "RideObject::ReadJsonVehicleInfo expects parameter properties to be object"); + + _legacyType.min_cars_in_train = Json::GetNumber(properties["minCarsPerTrain"], 1); + _legacyType.max_cars_in_train = Json::GetNumber(properties["maxCarsPerTrain"], 1); + _legacyType.cars_per_flat_ride = Json::GetNumber(properties["carsPerFlatRide"], 255); + _legacyType.zero_cars = Json::GetNumber(properties["numEmptyCars"]); // Train formation from car indices - _legacyType.default_vehicle = json_integer_value(json_object_get(properties, "defaultCar")); - _legacyType.tab_vehicle = json_integer_value(json_object_get(properties, "tabCar")); - auto tabScale = ObjectJsonHelpers::GetFloat(properties, "tabScale"); - if (tabScale != 0 && ObjectJsonHelpers::GetFloat(properties, "tabScale") <= 0.5f) + _legacyType.default_vehicle = Json::GetNumber(properties["defaultCar"]); + _legacyType.tab_vehicle = Json::GetNumber(properties["tabCar"]); + + float tabScale = Json::GetNumber(properties["tabScale"]); + if (tabScale != 0 && tabScale <= 0.5f) { _legacyType.flags |= RIDE_ENTRY_FLAG_VEHICLE_TAB_SCALE_HALF; } + json_t headCars = Json::AsArray(properties["headCars"]); + json_t tailCars = Json::AsArray(properties["tailCars"]); + // 0xFF means N/A. - _legacyType.front_vehicle = 0xFF; - _legacyType.second_vehicle = 0xFF; - _legacyType.third_vehicle = 0xFF; - _legacyType.rear_vehicle = 0xFF; + _legacyType.front_vehicle = Json::GetNumber(headCars[0], 0xFF); + _legacyType.second_vehicle = Json::GetNumber(headCars[1], 0xFF); + _legacyType.third_vehicle = Json::GetNumber(headCars[2], 0xFF); + _legacyType.rear_vehicle = Json::GetNumber(tailCars[0], 0xFF); - auto headCars = ObjectJsonHelpers::GetJsonIntegerArray(json_object_get(properties, "headCars")); - if (headCars.size() >= 1) - { - _legacyType.front_vehicle = headCars[0]; - } - if (headCars.size() >= 2) - { - _legacyType.second_vehicle = headCars[1]; - } - if (headCars.size() >= 3) - { - _legacyType.third_vehicle = headCars[2]; - } - if (headCars.size() >= 4) - { - // More than 3 head cars not supported yet! - } - - auto tailCars = ObjectJsonHelpers::GetJsonIntegerArray(json_object_get(properties, "tailCars")); - if (tailCars.size() >= 1) - { - _legacyType.rear_vehicle = tailCars[0]; - } - if (tailCars.size() >= 2) - { - // More than 1 tail car not supported yet! - } - - auto cars = ReadJsonCars(json_object_get(properties, "cars")); + auto cars = ReadJsonCars(properties["cars"]); auto numCars = std::min(std::size(_legacyType.vehicles), cars.size()); for (size_t i = 0; i < numCars; i++) { @@ -699,129 +684,131 @@ void RideObject::ReadJsonVehicleInfo([[maybe_unused]] IReadObjectContext* contex } } -std::vector RideObject::ReadJsonCars(const json_t* jCars) +std::vector RideObject::ReadJsonCars(json_t& jCars) { std::vector cars; - if (json_is_array(jCars)) + if (jCars.is_array()) { - json_t* jCar; - size_t index; - json_array_foreach(jCars, index, jCar) + for (auto& jCar : jCars) { - auto car = ReadJsonCar(jCar); - cars.push_back(car); + if (jCar.is_object()) + { + auto car = ReadJsonCar(jCar); + cars.push_back(car); + } } } - else if (json_is_object(jCars)) + else if (jCars.is_object()) { auto car = ReadJsonCar(jCars); cars.push_back(car); } + return cars; } -rct_ride_entry_vehicle RideObject::ReadJsonCar(const json_t* jCar) +rct_ride_entry_vehicle RideObject::ReadJsonCar(json_t& jCar) { + Guard::Assert(jCar.is_object(), "RideObject::ReadJsonCar expects parameter jCar to be object"); + rct_ride_entry_vehicle car = {}; - car.rotation_frame_mask = ObjectJsonHelpers::GetInteger(jCar, "rotationFrameMask"); - car.spacing = ObjectJsonHelpers::GetInteger(jCar, "spacing"); - car.car_mass = ObjectJsonHelpers::GetInteger(jCar, "mass"); - car.tab_height = ObjectJsonHelpers::GetInteger(jCar, "tabOffset"); - car.num_seats = ObjectJsonHelpers::GetInteger(jCar, "numSeats"); - if (ObjectJsonHelpers::GetBoolean(jCar, "seatsInPairs", true) && car.num_seats > 1) + car.rotation_frame_mask = Json::GetNumber(jCar["rotationFrameMask"]); + car.spacing = Json::GetNumber(jCar["spacing"]); + car.car_mass = Json::GetNumber(jCar["mass"]); + car.tab_height = Json::GetNumber(jCar["tabOffset"]); + car.num_seats = Json::GetNumber(jCar["numSeats"]); + if (Json::GetBoolean(jCar["seatsInPairs"], true) && car.num_seats > 1) { car.num_seats |= VEHICLE_SEAT_PAIR_FLAG; } - car.sprite_width = ObjectJsonHelpers::GetInteger(jCar, "spriteWidth"); - car.sprite_height_negative = ObjectJsonHelpers::GetInteger(jCar, "spriteHeightNegative"); - car.sprite_height_positive = ObjectJsonHelpers::GetInteger(jCar, "spriteHeightPositive"); - car.animation = ObjectJsonHelpers::GetInteger(jCar, "animation"); - car.base_num_frames = ObjectJsonHelpers::GetInteger(jCar, "baseNumFrames"); - car.no_vehicle_images = ObjectJsonHelpers::GetInteger(jCar, "numImages"); - car.no_seating_rows = ObjectJsonHelpers::GetInteger(jCar, "numSeatRows"); - car.spinning_inertia = ObjectJsonHelpers::GetInteger(jCar, "spinningInertia"); - car.spinning_friction = ObjectJsonHelpers::GetInteger(jCar, "spinningFriction"); - car.friction_sound_id = static_cast(ObjectJsonHelpers::GetInteger(jCar, "frictionSoundId", 255)); - car.log_flume_reverser_vehicle_type = ObjectJsonHelpers::GetInteger(jCar, "logFlumeReverserVehicleType"); - car.sound_range = ObjectJsonHelpers::GetInteger(jCar, "soundRange", 255); - car.double_sound_frequency = ObjectJsonHelpers::GetInteger(jCar, "doubleSoundFrequency"); - car.powered_acceleration = ObjectJsonHelpers::GetInteger(jCar, "poweredAcceleration"); - car.powered_max_speed = ObjectJsonHelpers::GetInteger(jCar, "poweredMaxSpeed"); - car.car_visual = ObjectJsonHelpers::GetInteger(jCar, "carVisual"); - car.effect_visual = ObjectJsonHelpers::GetInteger(jCar, "effectVisual", 1); - car.draw_order = ObjectJsonHelpers::GetInteger(jCar, "drawOrder"); - car.num_vertical_frames_override = ObjectJsonHelpers::GetInteger(jCar, "numVerticalFramesOverride"); + car.sprite_width = Json::GetNumber(jCar["spriteWidth"]); + car.sprite_height_negative = Json::GetNumber(jCar["spriteHeightNegative"]); + car.sprite_height_positive = Json::GetNumber(jCar["spriteHeightPositive"]); + car.animation = Json::GetNumber(jCar["animation"]); + car.base_num_frames = Json::GetNumber(jCar["baseNumFrames"]); + car.no_vehicle_images = Json::GetNumber(jCar["numImages"]); + car.no_seating_rows = Json::GetNumber(jCar["numSeatRows"]); + car.spinning_inertia = Json::GetNumber(jCar["spinningInertia"]); + car.spinning_friction = Json::GetNumber(jCar["spinningFriction"]); + car.friction_sound_id = Json::GetEnum(jCar["frictionSoundId"], SoundId::Null); + car.log_flume_reverser_vehicle_type = Json::GetNumber(jCar["logFlumeReverserVehicleType"]); + car.sound_range = Json::GetNumber(jCar["soundRange"], 255); + car.double_sound_frequency = Json::GetNumber(jCar["doubleSoundFrequency"]); + car.powered_acceleration = Json::GetNumber(jCar["poweredAcceleration"]); + car.powered_max_speed = Json::GetNumber(jCar["poweredMaxSpeed"]); + car.car_visual = Json::GetNumber(jCar["carVisual"]); + car.effect_visual = Json::GetNumber(jCar["effectVisual"], 1); + car.draw_order = Json::GetNumber(jCar["drawOrder"]); + car.num_vertical_frames_override = Json::GetNumber(jCar["numVerticalFramesOverride"]); - auto& peepLoadingPositions = car.peep_loading_positions; - auto jLoadingPositions = json_object_get(jCar, "loadingPositions"); - if (json_is_array(jLoadingPositions)) + auto jLoadingPositions = jCar["loadingPositions"]; + if (jLoadingPositions.is_array()) { - auto arr = ObjectJsonHelpers::GetJsonIntegerArray(jLoadingPositions); - for (auto x : arr) + for (auto& jPos : jLoadingPositions) { - peepLoadingPositions.push_back(x); + car.peep_loading_positions.push_back(Json::GetNumber(jPos)); } } else { - auto& peepLoadingWaypoints = car.peep_loading_waypoints; - auto jLoadingWaypoints = json_object_get(jCar, "loadingWaypoints"); - if (json_is_array(jLoadingWaypoints)) + auto jLoadingWaypoints = jCar["loadingWaypoints"]; + if (jLoadingWaypoints.is_array()) { car.flags |= VEHICLE_ENTRY_FLAG_LOADING_WAYPOINTS; + car.peep_loading_waypoint_segments = Json::GetNumber(jCar["numSegments"]); - auto numSegments = ObjectJsonHelpers::GetInteger(jCar, "numSegments"); - car.peep_loading_waypoint_segments = numSegments; - - size_t i; - json_t* route; - json_array_foreach(jLoadingWaypoints, i, route) + for (auto& jRoute : jLoadingWaypoints) { - if (json_is_array(route)) + if (jRoute.is_array()) { - size_t j; - json_t* waypoint; std::array entry; - json_array_foreach(route, j, waypoint) + + for (size_t j = 0; j < 3; ++j) { - if (json_is_array(waypoint) && json_array_size(waypoint) >= 2) + auto jWaypoint = jRoute[j]; + if (jWaypoint.is_array() && jWaypoint.size() >= 2) { - int32_t x = json_integer_value(json_array_get(waypoint, 0)); - int32_t y = json_integer_value(json_array_get(waypoint, 1)); + int32_t x = Json::GetNumber(jWaypoint[0]); + int32_t y = Json::GetNumber(jWaypoint[1]); entry[j] = { x, y }; } } - peepLoadingWaypoints.push_back(entry); + + car.peep_loading_waypoints.push_back(entry); } } } } - auto jFrames = json_object_get(jCar, "frames"); - car.sprite_flags = ObjectJsonHelpers::GetFlags( - jFrames, - { - { "flat", VEHICLE_SPRITE_FLAG_FLAT }, - { "gentleSlopes", VEHICLE_SPRITE_FLAG_GENTLE_SLOPES }, - { "steepSlopes", VEHICLE_SPRITE_FLAG_STEEP_SLOPES }, - { "verticalSlopes", VEHICLE_SPRITE_FLAG_VERTICAL_SLOPES }, - { "diagonalSlopes", VEHICLE_SPRITE_FLAG_DIAGONAL_SLOPES }, - { "flatBanked", VEHICLE_SPRITE_FLAG_FLAT_BANKED }, - { "inlineTwists", VEHICLE_SPRITE_FLAG_INLINE_TWISTS }, - { "flatToGentleSlopeBankedTransitions", VEHICLE_SPRITE_FLAG_FLAT_TO_GENTLE_SLOPE_BANKED_TRANSITIONS }, - { "diagonalGentleSlopeBankedTransitions", VEHICLE_SPRITE_FLAG_DIAGONAL_GENTLE_SLOPE_BANKED_TRANSITIONS }, - { "gentleSlopeBankedTransitions", VEHICLE_SPRITE_FLAG_GENTLE_SLOPE_BANKED_TRANSITIONS }, - { "gentleSlopeBankedTurns", VEHICLE_SPRITE_FLAG_GENTLE_SLOPE_BANKED_TURNS }, - { "flatToGentleSlopeWhileBankedTransitions", VEHICLE_SPRITE_FLAG_FLAT_TO_GENTLE_SLOPE_WHILE_BANKED_TRANSITIONS }, - { "corkscrews", VEHICLE_SPRITE_FLAG_CORKSCREWS }, - { "restraintAnimation", VEHICLE_SPRITE_FLAG_RESTRAINT_ANIMATION }, - { "curvedLiftHill", VEHICLE_SPRITE_FLAG_CURVED_LIFT_HILL }, - { "VEHICLE_SPRITE_FLAG_15", VEHICLE_SPRITE_FLAG_15 }, - }); + auto jFrames = jCar["frames"]; + if (jFrames.is_object()) + { + car.sprite_flags = Json::GetFlags( + jFrames, + { + { "flat", VEHICLE_SPRITE_FLAG_FLAT }, + { "gentleSlopes", VEHICLE_SPRITE_FLAG_GENTLE_SLOPES }, + { "steepSlopes", VEHICLE_SPRITE_FLAG_STEEP_SLOPES }, + { "verticalSlopes", VEHICLE_SPRITE_FLAG_VERTICAL_SLOPES }, + { "diagonalSlopes", VEHICLE_SPRITE_FLAG_DIAGONAL_SLOPES }, + { "flatBanked", VEHICLE_SPRITE_FLAG_FLAT_BANKED }, + { "inlineTwists", VEHICLE_SPRITE_FLAG_INLINE_TWISTS }, + { "flatToGentleSlopeBankedTransitions", VEHICLE_SPRITE_FLAG_FLAT_TO_GENTLE_SLOPE_BANKED_TRANSITIONS }, + { "diagonalGentleSlopeBankedTransitions", VEHICLE_SPRITE_FLAG_DIAGONAL_GENTLE_SLOPE_BANKED_TRANSITIONS }, + { "gentleSlopeBankedTransitions", VEHICLE_SPRITE_FLAG_GENTLE_SLOPE_BANKED_TRANSITIONS }, + { "gentleSlopeBankedTurns", VEHICLE_SPRITE_FLAG_GENTLE_SLOPE_BANKED_TURNS }, + { "flatToGentleSlopeWhileBankedTransitions", + VEHICLE_SPRITE_FLAG_FLAT_TO_GENTLE_SLOPE_WHILE_BANKED_TRANSITIONS }, + { "corkscrews", VEHICLE_SPRITE_FLAG_CORKSCREWS }, + { "restraintAnimation", VEHICLE_SPRITE_FLAG_RESTRAINT_ANIMATION }, + { "curvedLiftHill", VEHICLE_SPRITE_FLAG_CURVED_LIFT_HILL }, + { "VEHICLE_SPRITE_FLAG_15", VEHICLE_SPRITE_FLAG_15 }, + }); + } - car.flags |= ObjectJsonHelpers::GetFlags( + car.flags |= Json::GetFlags( jCar, { { "VEHICLE_ENTRY_FLAG_POWERED_RIDE_UNRESTRICTED_GRAVITY", VEHICLE_ENTRY_FLAG_POWERED_RIDE_UNRESTRICTED_GRAVITY }, @@ -856,18 +843,21 @@ rct_ride_entry_vehicle RideObject::ReadJsonCar(const json_t* jCar) { "VEHICLE_ENTRY_FLAG_GO_KART", VEHICLE_ENTRY_FLAG_GO_KART }, { "VEHICLE_ENTRY_FLAG_DODGEM_CAR_PLACEMENT", VEHICLE_ENTRY_FLAG_DODGEM_CAR_PLACEMENT }, }); + return car; } -vehicle_colour_preset_list RideObject::ReadJsonCarColours(const json_t* jCarColours) +vehicle_colour_preset_list RideObject::ReadJsonCarColours(json_t& jCarColours) { + Guard::Assert(jCarColours.is_array(), "RideObject::ReadJsonCarColours expects parameter jCarColours to be array"); + // The JSON supports multiple configurations of per car colours, but // the ride entry structure currently doesn't allow for it. Assume that // a single configuration with multiple colour entries is per car scheme. - if (json_array_size(jCarColours) == 1) + if (jCarColours.size() == 1) { - auto firstElement = json_array_get(jCarColours, 0); - auto numColours = json_array_size(firstElement); + auto firstElement = Json::AsArray(jCarColours[0]); + auto numColours = firstElement.size(); if (numColours >= 2) { // Read all colours from first config @@ -881,11 +871,9 @@ vehicle_colour_preset_list RideObject::ReadJsonCarColours(const json_t* jCarColo // Read first colour for each config vehicle_colour_preset_list list = {}; - size_t index; - const json_t* jConfiguration; - json_array_foreach(jCarColours, index, jConfiguration) + for (size_t index = 0; index < jCarColours.size(); index++) { - auto config = ReadJsonColourConfiguration(jConfiguration); + auto config = ReadJsonColourConfiguration(jCarColours[index]); if (config.size() >= 1) { list.list[index] = config[0]; @@ -901,27 +889,27 @@ vehicle_colour_preset_list RideObject::ReadJsonCarColours(const json_t* jCarColo return list; } -std::vector RideObject::ReadJsonColourConfiguration(const json_t* jColourConfig) +std::vector RideObject::ReadJsonColourConfiguration(json_t& jColourConfig) { std::vector config; - size_t index; - const json_t* jColours; - json_array_foreach(jColourConfig, index, jColours) + + for (auto& jColours : jColourConfig) { vehicle_colour carColour = {}; - auto colours = ObjectJsonHelpers::GetJsonStringArray(jColours); + + auto colours = Json::AsArray(jColours); if (colours.size() >= 1) { - carColour.main = ObjectJsonHelpers::ParseColour(colours[0]); + carColour.main = Colour::FromString(Json::GetString(colours[0])); carColour.additional_1 = carColour.main; carColour.additional_2 = carColour.main; if (colours.size() >= 2) { - carColour.additional_1 = ObjectJsonHelpers::ParseColour(colours[1]); + carColour.additional_1 = Colour::FromString(Json::GetString(colours[1])); } if (colours.size() >= 3) { - carColour.additional_2 = ObjectJsonHelpers::ParseColour(colours[2]); + carColour.additional_2 = Colour::FromString(Json::GetString(colours[2])); } } config.push_back(carColour); diff --git a/src/openrct2/object/RideObject.h b/src/openrct2/object/RideObject.h index 2448539cbc..c2217259bd 100644 --- a/src/openrct2/object/RideObject.h +++ b/src/openrct2/object/RideObject.h @@ -10,6 +10,7 @@ #pragma once #include "../core/IStream.hpp" +#include "../core/Json.hpp" #include "../ride/Ride.h" #include "Object.h" @@ -34,7 +35,7 @@ public: return &_legacyType; } - void ReadJson(IReadObjectContext* context, const json_t* root) override; + void ReadJson(IReadObjectContext* context, json_t& root) override; void ReadLegacy(IReadObjectContext* context, OpenRCT2::IStream* stream) override; void Load() override; void Unload() override; @@ -49,11 +50,11 @@ public: private: void ReadLegacyVehicle(IReadObjectContext* context, OpenRCT2::IStream* stream, rct_ride_entry_vehicle* vehicle); - void ReadJsonVehicleInfo(IReadObjectContext* context, const json_t* properties); - std::vector ReadJsonCars(const json_t* jCars); - rct_ride_entry_vehicle ReadJsonCar(const json_t* jCar); - vehicle_colour_preset_list ReadJsonCarColours(const json_t* jCarColours); - std::vector ReadJsonColourConfiguration(const json_t* jColourConfig); + void ReadJsonVehicleInfo(IReadObjectContext* context, json_t& properties); + std::vector ReadJsonCars(json_t& jCars); + rct_ride_entry_vehicle ReadJsonCar(json_t& jCar); + vehicle_colour_preset_list ReadJsonCarColours(json_t& jCarColours); + std::vector ReadJsonColourConfiguration(json_t& jColourConfig); static uint8_t CalculateNumVerticalFrames(const rct_ride_entry_vehicle* vehicleEntry); static uint8_t CalculateNumHorizontalFrames(const rct_ride_entry_vehicle* vehicleEntry); diff --git a/src/openrct2/object/SceneryGroupObject.cpp b/src/openrct2/object/SceneryGroupObject.cpp index 7c94a29969..5936bb0296 100644 --- a/src/openrct2/object/SceneryGroupObject.cpp +++ b/src/openrct2/object/SceneryGroupObject.cpp @@ -18,7 +18,6 @@ #include "../drawing/Drawing.h" #include "../localisation/Language.h" #include "../peep/Staff.h" -#include "ObjectJsonHelpers.h" #include "ObjectManager.h" #include "ObjectRepository.h" @@ -110,35 +109,29 @@ std::vector SceneryGroupObject::ReadItems(IStream* stream) return items; } -void SceneryGroupObject::ReadJson(IReadObjectContext* context, const json_t* root) +void SceneryGroupObject::ReadJson(IReadObjectContext* context, json_t& root) { - auto properties = json_object_get(root, "properties"); - _legacyType.priority = json_integer_value(json_object_get(properties, "priority")); + Guard::Assert(root.is_object(), "SceneryGroupObject::ReadJson expects parameter root to be object"); - // Entertainer costumes - auto jCostumes = json_object_get(properties, "entertainerCostumes"); - if (jCostumes != nullptr) + auto properties = root["properties"]; + + if (properties.is_object()) { - _legacyType.entertainer_costumes = ReadJsonEntertainerCostumes(jCostumes); + _legacyType.priority = Json::GetNumber(properties["priority"]); + _legacyType.entertainer_costumes = ReadJsonEntertainerCostumes(properties["entertainerCostumes"]); + + _items = ReadJsonEntries(properties["entries"]); } - auto jEntries = json_object_get(properties, "entries"); - if (jEntries != nullptr) - { - _items = ReadJsonEntries(jEntries); - } - - ObjectJsonHelpers::LoadStrings(root, GetStringTable()); - ObjectJsonHelpers::LoadImages(context, root, GetImageTable()); + PopulateTablesFromJson(context, root); } -uint32_t SceneryGroupObject::ReadJsonEntertainerCostumes(const json_t* jCostumes) +uint32_t SceneryGroupObject::ReadJsonEntertainerCostumes(json_t& jCostumes) { uint32_t costumes = 0; - auto szCostumes = ObjectJsonHelpers::GetJsonStringArray(jCostumes); - for (const auto& szCostume : szCostumes) + for (auto& jCostume : jCostumes) { - auto entertainer = ParseEntertainerCostume(szCostume); + auto entertainer = ParseEntertainerCostume(Json::GetString(jCostume)); auto peepSprite = EntertainerCostumeToSprite(entertainer); costumes |= 1 << (static_cast(peepSprite)); } @@ -172,19 +165,14 @@ EntertainerCostume SceneryGroupObject::ParseEntertainerCostume(const std::string return EntertainerCostume::Panda; } -std::vector SceneryGroupObject::ReadJsonEntries(const json_t* jEntries) +std::vector SceneryGroupObject::ReadJsonEntries(json_t& jEntries) { std::vector entries; - size_t index; - json_t* jEntry; - json_array_foreach(jEntries, index, jEntry) + + for (auto& jEntry : jEntries) { - auto entryId = json_string_value(jEntry); - if (entryId != nullptr) - { - auto entry = ObjectJsonHelpers::ParseObjectEntry(entryId); - entries.push_back(entry); - } + auto entry = ParseObjectEntry(Json::GetString(jEntry)); + entries.push_back(entry); } return entries; } diff --git a/src/openrct2/object/SceneryGroupObject.h b/src/openrct2/object/SceneryGroupObject.h index f2c9a6780e..7361e2ef5b 100644 --- a/src/openrct2/object/SceneryGroupObject.h +++ b/src/openrct2/object/SceneryGroupObject.h @@ -34,7 +34,7 @@ public: { return &_legacyType; } - void ReadJson(IReadObjectContext* context, const json_t* root) override; + void ReadJson(IReadObjectContext* context, json_t& root) override; void ReadLegacy(IReadObjectContext* context, OpenRCT2::IStream* stream) override; void Load() override; @@ -47,7 +47,7 @@ public: private: static std::vector ReadItems(OpenRCT2::IStream* stream); - static uint32_t ReadJsonEntertainerCostumes(const json_t* jCostumes); + static uint32_t ReadJsonEntertainerCostumes(json_t& jCostumes); static EntertainerCostume ParseEntertainerCostume(const std::string& s); - static std::vector ReadJsonEntries(const json_t* jEntries); + static std::vector ReadJsonEntries(json_t& jEntries); }; diff --git a/src/openrct2/object/SceneryObject.cpp b/src/openrct2/object/SceneryObject.cpp index 184abd91fa..2314162a2b 100644 --- a/src/openrct2/object/SceneryObject.cpp +++ b/src/openrct2/object/SceneryObject.cpp @@ -9,13 +9,11 @@ #include "SceneryObject.h" -#include "ObjectJsonHelpers.h" - void SceneryObject::SetPrimarySceneryGroup(const std::string& s) { if (!s.empty()) { - auto sgEntry = ObjectJsonHelpers::ParseObjectEntry(s); + auto sgEntry = ParseObjectEntry(s); SetPrimarySceneryGroup(&sgEntry); } } diff --git a/src/openrct2/object/SmallSceneryObject.cpp b/src/openrct2/object/SmallSceneryObject.cpp index d2d89c75c9..9cef4276f1 100644 --- a/src/openrct2/object/SmallSceneryObject.cpp +++ b/src/openrct2/object/SmallSceneryObject.cpp @@ -19,7 +19,6 @@ #include "../localisation/Language.h" #include "../world/Scenery.h" #include "../world/SmallScenery.h" -#include "ObjectJsonHelpers.h" #include @@ -234,96 +233,97 @@ rct_object_entry SmallSceneryObject::GetScgAbstrHeader() return Object::CreateHeader("SCGABSTR", 207140231, 932253451); } -void SmallSceneryObject::ReadJson(IReadObjectContext* context, const json_t* root) +void SmallSceneryObject::ReadJson(IReadObjectContext* context, json_t& root) { - auto properties = json_object_get(root, "properties"); + Guard::Assert(root.is_object(), "SmallSceneryObject::ReadJson expects parameter root to be object"); - _legacyType.small_scenery.height = json_integer_value(json_object_get(properties, "height")); - _legacyType.small_scenery.tool_id = ObjectJsonHelpers::ParseCursor( - ObjectJsonHelpers::GetString(properties, "cursor"), CURSOR_STATUE_DOWN); - _legacyType.small_scenery.price = json_integer_value(json_object_get(properties, "price")); - _legacyType.small_scenery.removal_price = json_integer_value(json_object_get(properties, "removalPrice")); - _legacyType.small_scenery.animation_delay = json_integer_value(json_object_get(properties, "animationDelay")); - _legacyType.small_scenery.animation_mask = json_integer_value(json_object_get(properties, "animationMask")); - _legacyType.small_scenery.num_frames = json_integer_value(json_object_get(properties, "numFrames")); + auto properties = root["properties"]; - // Flags - _legacyType.small_scenery.flags = ObjectJsonHelpers::GetFlags( - properties, - { - { "SMALL_SCENERY_FLAG_VOFFSET_CENTRE", SMALL_SCENERY_FLAG_VOFFSET_CENTRE }, - { "requiresFlatSurface", SMALL_SCENERY_FLAG_REQUIRE_FLAT_SURFACE }, - { "isRotatable", SMALL_SCENERY_FLAG_ROTATABLE }, - { "isAnimated", SMALL_SCENERY_FLAG_ANIMATED }, - { "canWither", SMALL_SCENERY_FLAG_CAN_WITHER }, - { "canBeWatered", SMALL_SCENERY_FLAG_CAN_BE_WATERED }, - { "hasOverlayImage", SMALL_SCENERY_FLAG_ANIMATED_FG }, - { "hasGlass", SMALL_SCENERY_FLAG_HAS_GLASS }, - { "hasPrimaryColour", SMALL_SCENERY_FLAG_HAS_PRIMARY_COLOUR }, - { "SMALL_SCENERY_FLAG_FOUNTAIN_SPRAY_1", SMALL_SCENERY_FLAG_FOUNTAIN_SPRAY_1 }, - { "SMALL_SCENERY_FLAG_FOUNTAIN_SPRAY_4", SMALL_SCENERY_FLAG_FOUNTAIN_SPRAY_4 }, - { "isClock", SMALL_SCENERY_FLAG_IS_CLOCK }, - { "SMALL_SCENERY_FLAG_SWAMP_GOO", SMALL_SCENERY_FLAG_SWAMP_GOO }, - { "SMALL_SCENERY_FLAG17", SMALL_SCENERY_FLAG17 }, - { "isStackable", SMALL_SCENERY_FLAG_STACKABLE }, - { "prohibitWalls", SMALL_SCENERY_FLAG_NO_WALLS }, - { "hasSecondaryColour", SMALL_SCENERY_FLAG_HAS_SECONDARY_COLOUR }, - { "hasNoSupports", SMALL_SCENERY_FLAG_NO_SUPPORTS }, - { "SMALL_SCENERY_FLAG_VISIBLE_WHEN_ZOOMED", SMALL_SCENERY_FLAG_VISIBLE_WHEN_ZOOMED }, - { "SMALL_SCENERY_FLAG_COG", SMALL_SCENERY_FLAG_COG }, - { "allowSupportsAbove", SMALL_SCENERY_FLAG_BUILD_DIRECTLY_ONTOP }, - { "supportsHavePrimaryColour", SMALL_SCENERY_FLAG_PAINT_SUPPORTS }, - { "SMALL_SCENERY_FLAG27", SMALL_SCENERY_FLAG27 }, - { "isTree", SMALL_SCENERY_FLAG_IS_TREE }, - }); - - // Determine shape flags from a shape string - auto shape = ObjectJsonHelpers::GetString(properties, "shape"); - if (!shape.empty()) + if (properties.is_object()) { - auto quarters = shape.substr(0, 3); - if (quarters == "2/4") - { - _legacyType.small_scenery.flags |= SMALL_SCENERY_FLAG_FULL_TILE | SMALL_SCENERY_FLAG_HALF_SPACE; - } - else if (quarters == "3/4") - { - _legacyType.small_scenery.flags |= SMALL_SCENERY_FLAG_FULL_TILE | SMALL_SCENERY_FLAG_THREE_QUARTERS; - } - else if (quarters == "4/4") - { - _legacyType.small_scenery.flags |= SMALL_SCENERY_FLAG_FULL_TILE; - } - if (shape.size() >= 5) - { - if ((shape.substr(3) == "+D")) + _legacyType.small_scenery.height = Json::GetNumber(properties["height"]); + _legacyType.small_scenery.tool_id = Cursor::FromString(Json::GetString(properties["cursor"]), CURSOR_STATUE_DOWN); + _legacyType.small_scenery.price = Json::GetNumber(properties["price"]); + _legacyType.small_scenery.removal_price = Json::GetNumber(properties["removalPrice"]); + _legacyType.small_scenery.animation_delay = Json::GetNumber(properties["animationDelay"]); + _legacyType.small_scenery.animation_mask = Json::GetNumber(properties["animationMask"]); + _legacyType.small_scenery.num_frames = Json::GetNumber(properties["numFrames"]); + + _legacyType.small_scenery.flags = Json::GetFlags( + properties, { - _legacyType.small_scenery.flags |= SMALL_SCENERY_FLAG_DIAGONAL; + { "SMALL_SCENERY_FLAG_VOFFSET_CENTRE", SMALL_SCENERY_FLAG_VOFFSET_CENTRE }, + { "requiresFlatSurface", SMALL_SCENERY_FLAG_REQUIRE_FLAT_SURFACE }, + { "isRotatable", SMALL_SCENERY_FLAG_ROTATABLE }, + { "isAnimated", SMALL_SCENERY_FLAG_ANIMATED }, + { "canWither", SMALL_SCENERY_FLAG_CAN_WITHER }, + { "canBeWatered", SMALL_SCENERY_FLAG_CAN_BE_WATERED }, + { "hasOverlayImage", SMALL_SCENERY_FLAG_ANIMATED_FG }, + { "hasGlass", SMALL_SCENERY_FLAG_HAS_GLASS }, + { "hasPrimaryColour", SMALL_SCENERY_FLAG_HAS_PRIMARY_COLOUR }, + { "SMALL_SCENERY_FLAG_FOUNTAIN_SPRAY_1", SMALL_SCENERY_FLAG_FOUNTAIN_SPRAY_1 }, + { "SMALL_SCENERY_FLAG_FOUNTAIN_SPRAY_4", SMALL_SCENERY_FLAG_FOUNTAIN_SPRAY_4 }, + { "isClock", SMALL_SCENERY_FLAG_IS_CLOCK }, + { "SMALL_SCENERY_FLAG_SWAMP_GOO", SMALL_SCENERY_FLAG_SWAMP_GOO }, + { "SMALL_SCENERY_FLAG17", SMALL_SCENERY_FLAG17 }, + { "isStackable", SMALL_SCENERY_FLAG_STACKABLE }, + { "prohibitWalls", SMALL_SCENERY_FLAG_NO_WALLS }, + { "hasSecondaryColour", SMALL_SCENERY_FLAG_HAS_SECONDARY_COLOUR }, + { "hasNoSupports", SMALL_SCENERY_FLAG_NO_SUPPORTS }, + { "SMALL_SCENERY_FLAG_VISIBLE_WHEN_ZOOMED", SMALL_SCENERY_FLAG_VISIBLE_WHEN_ZOOMED }, + { "SMALL_SCENERY_FLAG_COG", SMALL_SCENERY_FLAG_COG }, + { "allowSupportsAbove", SMALL_SCENERY_FLAG_BUILD_DIRECTLY_ONTOP }, + { "supportsHavePrimaryColour", SMALL_SCENERY_FLAG_PAINT_SUPPORTS }, + { "SMALL_SCENERY_FLAG27", SMALL_SCENERY_FLAG27 }, + { "isTree", SMALL_SCENERY_FLAG_IS_TREE }, + }); + + // Determine shape flags from a shape string + auto shape = Json::GetString(properties["shape"]); + if (!shape.empty()) + { + auto quarters = shape.substr(0, 3); + if (quarters == "2/4") + { + _legacyType.small_scenery.flags |= SMALL_SCENERY_FLAG_FULL_TILE | SMALL_SCENERY_FLAG_HALF_SPACE; + } + else if (quarters == "3/4") + { + _legacyType.small_scenery.flags |= SMALL_SCENERY_FLAG_FULL_TILE | SMALL_SCENERY_FLAG_THREE_QUARTERS; + } + else if (quarters == "4/4") + { + _legacyType.small_scenery.flags |= SMALL_SCENERY_FLAG_FULL_TILE; + } + if (shape.size() >= 5) + { + if ((shape.substr(3) == "+D")) + { + _legacyType.small_scenery.flags |= SMALL_SCENERY_FLAG_DIAGONAL; + } } } + + auto jFrameOffsets = properties["frameOffsets"]; + if (jFrameOffsets.is_array()) + { + _frameOffsets = ReadJsonFrameOffsets(jFrameOffsets); + _legacyType.small_scenery.flags |= SMALL_SCENERY_FLAG_HAS_FRAME_OFFSETS; + } + + SetPrimarySceneryGroup(Json::GetString(properties["sceneryGroup"])); } - auto jFrameOffsets = json_object_get(properties, "frameOffsets"); - if (jFrameOffsets != nullptr) - { - _frameOffsets = ReadJsonFrameOffsets(jFrameOffsets); - _legacyType.small_scenery.flags |= SMALL_SCENERY_FLAG_HAS_FRAME_OFFSETS; - } - - SetPrimarySceneryGroup(ObjectJsonHelpers::GetString(json_object_get(properties, "sceneryGroup"))); - - ObjectJsonHelpers::LoadStrings(root, GetStringTable()); - ObjectJsonHelpers::LoadImages(context, root, GetImageTable()); + PopulateTablesFromJson(context, root); } -std::vector SmallSceneryObject::ReadJsonFrameOffsets(const json_t* jFrameOffsets) +std::vector SmallSceneryObject::ReadJsonFrameOffsets(json_t& jFrameOffsets) { std::vector offsets; - size_t index; - const json_t* jOffset; - json_array_foreach(jFrameOffsets, index, jOffset) + + for (auto& jOffset : jFrameOffsets) { - offsets.push_back(json_integer_value(jOffset)); + offsets.push_back(Json::GetNumber(jOffset)); } return offsets; } diff --git a/src/openrct2/object/SmallSceneryObject.h b/src/openrct2/object/SmallSceneryObject.h index 0c6e950f1a..8018bf8b72 100644 --- a/src/openrct2/object/SmallSceneryObject.h +++ b/src/openrct2/object/SmallSceneryObject.h @@ -32,7 +32,7 @@ public: } void ReadLegacy(IReadObjectContext* context, OpenRCT2::IStream* stream) override; - void ReadJson(IReadObjectContext* context, const json_t* root) override; + void ReadJson(IReadObjectContext* context, json_t& root) override; void Load() override; void Unload() override; @@ -40,7 +40,7 @@ public: private: static std::vector ReadFrameOffsets(OpenRCT2::IStream* stream); - static std::vector ReadJsonFrameOffsets(const json_t* jFrameOffsets); + static std::vector ReadJsonFrameOffsets(json_t& jFrameOffsets); void PerformFixes(); rct_object_entry GetScgPiratHeader(); rct_object_entry GetScgMineHeader(); diff --git a/src/openrct2/object/StationObject.cpp b/src/openrct2/object/StationObject.cpp index dc2d989aef..2b8c37c938 100644 --- a/src/openrct2/object/StationObject.cpp +++ b/src/openrct2/object/StationObject.cpp @@ -14,7 +14,6 @@ #include "../drawing/Drawing.h" #include "../localisation/Localisation.h" #include "../world/Banner.h" -#include "ObjectJsonHelpers.h" void StationObject::Load() { @@ -78,17 +77,24 @@ void StationObject::DrawPreview(rct_drawpixelinfo* dpi, int32_t width, int32_t h } } -void StationObject::ReadJson(IReadObjectContext* context, const json_t* root) +void StationObject::ReadJson(IReadObjectContext* context, json_t& root) { - auto properties = json_object_get(root, "properties"); - Height = ObjectJsonHelpers::GetInteger(properties, "height", 0); - ScrollingMode = ObjectJsonHelpers::GetInteger(properties, "scrollingMode", SCROLLING_MODE_NONE); - Flags = ObjectJsonHelpers::GetFlags( - properties, - { { "hasPrimaryColour", STATION_OBJECT_FLAGS::HAS_PRIMARY_COLOUR }, - { "hasSecondaryColour", STATION_OBJECT_FLAGS::HAS_SECONDARY_COLOUR }, - { "isTransparent", STATION_OBJECT_FLAGS::IS_TRANSPARENT } }); + Guard::Assert(root.is_object(), "StationObject::ReadJson expects parameter root to be object"); - ObjectJsonHelpers::LoadStrings(root, GetStringTable()); - ObjectJsonHelpers::LoadImages(context, root, GetImageTable()); + auto properties = root["properties"]; + + if (properties.is_object()) + { + Height = Json::GetNumber(properties["height"]); + ScrollingMode = Json::GetNumber(properties["scrollingMode"], SCROLLING_MODE_NONE); + Flags = Json::GetFlags( + properties, + { + { "hasPrimaryColour", STATION_OBJECT_FLAGS::HAS_PRIMARY_COLOUR }, + { "hasSecondaryColour", STATION_OBJECT_FLAGS::HAS_SECONDARY_COLOUR }, + { "isTransparent", STATION_OBJECT_FLAGS::IS_TRANSPARENT }, + }); + } + + PopulateTablesFromJson(context, root); } diff --git a/src/openrct2/object/StationObject.h b/src/openrct2/object/StationObject.h index cf982033fe..66300dc11e 100644 --- a/src/openrct2/object/StationObject.h +++ b/src/openrct2/object/StationObject.h @@ -33,7 +33,7 @@ public: { } - void ReadJson(IReadObjectContext* context, const json_t* root) override; + void ReadJson(IReadObjectContext* context, json_t& root) override; void Load() override; void Unload() override; diff --git a/src/openrct2/object/TerrainEdgeObject.cpp b/src/openrct2/object/TerrainEdgeObject.cpp index ac8c7f5147..77ca225822 100644 --- a/src/openrct2/object/TerrainEdgeObject.cpp +++ b/src/openrct2/object/TerrainEdgeObject.cpp @@ -13,7 +13,6 @@ #include "../core/String.hpp" #include "../drawing/Drawing.h" #include "../localisation/Localisation.h" -#include "ObjectJsonHelpers.h" void TerrainEdgeObject::Load() { @@ -44,12 +43,17 @@ void TerrainEdgeObject::DrawPreview(rct_drawpixelinfo* dpi, int32_t width, int32 gfx_draw_sprite(dpi, imageId + 5, screenCoords + ScreenCoordsXY{ 8, 8 }, 0); } -void TerrainEdgeObject::ReadJson(IReadObjectContext* context, const json_t* root) +void TerrainEdgeObject::ReadJson(IReadObjectContext* context, json_t& root) { - auto properties = json_object_get(root, "properties"); - HasDoors = ObjectJsonHelpers::GetBoolean(properties, "hasDoors", false); + Guard::Assert(root.is_object(), "TerrainEdgeObject::ReadJson expects parameter root to be object"); - ObjectJsonHelpers::LoadStrings(root, GetStringTable()); - ObjectJsonHelpers::LoadImages(context, root, GetImageTable()); + auto properties = root["properties"]; + + if (properties.is_object()) + { + HasDoors = Json::GetBoolean(properties["hasDoors"]); + } + + PopulateTablesFromJson(context, root); NumImagesLoaded = GetImageTable().GetCount(); } diff --git a/src/openrct2/object/TerrainEdgeObject.h b/src/openrct2/object/TerrainEdgeObject.h index 20c19b641f..f275736b7e 100644 --- a/src/openrct2/object/TerrainEdgeObject.h +++ b/src/openrct2/object/TerrainEdgeObject.h @@ -26,7 +26,7 @@ public: { } - void ReadJson(IReadObjectContext* context, const json_t* root) override; + void ReadJson(IReadObjectContext* context, json_t& root) override; void Load() override; void Unload() override; diff --git a/src/openrct2/object/TerrainSurfaceObject.cpp b/src/openrct2/object/TerrainSurfaceObject.cpp index 03e9e679ba..cfba7585c9 100644 --- a/src/openrct2/object/TerrainSurfaceObject.cpp +++ b/src/openrct2/object/TerrainSurfaceObject.cpp @@ -16,7 +16,6 @@ #include "../drawing/Drawing.h" #include "../localisation/Localisation.h" #include "../world/Location.hpp" -#include "ObjectJsonHelpers.h" void TerrainSurfaceObject::Load() { @@ -74,24 +73,45 @@ void TerrainSurfaceObject::DrawPreview(rct_drawpixelinfo* dpi, int32_t width, in } } -void TerrainSurfaceObject::ReadJson(IReadObjectContext* context, const json_t* root) +void TerrainSurfaceObject::ReadJson(IReadObjectContext* context, json_t& root) { - auto properties = json_object_get(root, "properties"); - Colour = ObjectJsonHelpers::ParseColour(ObjectJsonHelpers::GetString(properties, "colour"), 255); - Rotations = ObjectJsonHelpers::GetInteger(properties, "rotations", 1); - Price = ObjectJsonHelpers::GetInteger(properties, "price", 0); - Flags = ObjectJsonHelpers::GetFlags( - properties, - { { "smoothWithSelf", TERRAIN_SURFACE_FLAGS::SMOOTH_WITH_SELF }, - { "smoothWithOther", TERRAIN_SURFACE_FLAGS::SMOOTH_WITH_OTHER }, - { "canGrow", TERRAIN_SURFACE_FLAGS::CAN_GROW } }); + Guard::Assert(root.is_object(), "TerrainSurfaceObject::ReadJson expects parameter root to be object"); - auto jDefault = json_object_get(root, "default"); - if (json_is_object(jDefault)) + auto properties = root["properties"]; + + if (properties.is_object()) { - DefaultEntry = ObjectJsonHelpers::GetInteger(properties, "normal"); - DefaultGridEntry = ObjectJsonHelpers::GetInteger(properties, "grid"); - DefaultUndergroundEntry = ObjectJsonHelpers::GetInteger(properties, "underground"); + Colour = Colour::FromString(Json::GetString(properties["colour"]), 255); + Rotations = Json::GetNumber(properties["rotations"], 1); + Price = Json::GetNumber(properties["price"]); + Flags = Json::GetFlags( + properties, + { { "smoothWithSelf", TERRAIN_SURFACE_FLAGS::SMOOTH_WITH_SELF }, + { "smoothWithOther", TERRAIN_SURFACE_FLAGS::SMOOTH_WITH_OTHER }, + { "canGrow", TERRAIN_SURFACE_FLAGS::CAN_GROW } }); + + for (auto& el : properties["special"]) + { + if (el.is_object()) + { + SpecialEntry entry; + entry.Index = Json::GetNumber(el["index"]); + entry.Length = Json::GetNumber(el["length"], -1); + entry.Rotation = Json::GetNumber(el["rotation"], -1); + entry.Variation = Json::GetNumber(el["variation"], -1); + entry.Grid = Json::GetBoolean(el["grid"]); + entry.Underground = Json::GetBoolean(el["underground"]); + SpecialEntries.push_back(std::move(entry)); + } + } + } + + auto jDefault = root["default"]; + if (jDefault.is_object()) + { + DefaultEntry = Json::GetNumber(jDefault["normal"]); + DefaultGridEntry = Json::GetNumber(jDefault["grid"]); + DefaultUndergroundEntry = Json::GetNumber(jDefault["underground"]); } else { @@ -100,26 +120,7 @@ void TerrainSurfaceObject::ReadJson(IReadObjectContext* context, const json_t* r DefaultUndergroundEntry = 2; } - auto jSpecialArray = json_object_get(properties, "special"); - if (json_is_array(jSpecialArray)) - { - size_t i; - json_t* el; - json_array_foreach(jSpecialArray, i, el) - { - SpecialEntry entry; - entry.Index = ObjectJsonHelpers::GetInteger(el, "index"); - entry.Length = ObjectJsonHelpers::GetInteger(el, "length", -1); - entry.Rotation = ObjectJsonHelpers::GetInteger(el, "rotation", -1); - entry.Variation = ObjectJsonHelpers::GetInteger(el, "variation", -1); - entry.Grid = ObjectJsonHelpers::GetBoolean(el, "grid"); - entry.Underground = ObjectJsonHelpers::GetBoolean(el, "underground"); - SpecialEntries.push_back(std::move(entry)); - } - } - - ObjectJsonHelpers::LoadStrings(root, GetStringTable()); - ObjectJsonHelpers::LoadImages(context, root, GetImageTable()); + PopulateTablesFromJson(context, root); } uint32_t TerrainSurfaceObject::GetImageId( diff --git a/src/openrct2/object/TerrainSurfaceObject.h b/src/openrct2/object/TerrainSurfaceObject.h index 5914da776b..d9fc29aa93 100644 --- a/src/openrct2/object/TerrainSurfaceObject.h +++ b/src/openrct2/object/TerrainSurfaceObject.h @@ -59,7 +59,7 @@ public: { } - void ReadJson(IReadObjectContext* context, const json_t* root) override; + void ReadJson(IReadObjectContext* context, json_t& root) override; void Load() override; void Unload() override; diff --git a/src/openrct2/object/WallObject.cpp b/src/openrct2/object/WallObject.cpp index 806c27b789..686ea03e75 100644 --- a/src/openrct2/object/WallObject.cpp +++ b/src/openrct2/object/WallObject.cpp @@ -15,7 +15,6 @@ #include "../interface/Cursors.h" #include "../localisation/Language.h" #include "../world/Banner.h" -#include "ObjectJsonHelpers.h" void WallObject::ReadLegacy(IReadObjectContext* context, OpenRCT2::IStream* stream) { @@ -94,66 +93,63 @@ void WallObject::DrawPreview(rct_drawpixelinfo* dpi, int32_t width, int32_t heig } } -void WallObject::ReadJson(IReadObjectContext* context, const json_t* root) +void WallObject::ReadJson(IReadObjectContext* context, json_t& root) { - auto properties = json_object_get(root, "properties"); + Guard::Assert(root.is_object(), "WallObject::ReadJson expects parameter root to be object"); - _legacyType.wall.tool_id = ObjectJsonHelpers::ParseCursor( - ObjectJsonHelpers::GetString(properties, "cursor"), CURSOR_FENCE_DOWN); - _legacyType.wall.height = json_integer_value(json_object_get(properties, "height")); - _legacyType.wall.price = json_integer_value(json_object_get(properties, "price")); + auto properties = root["properties"]; - auto jScrollingMode = json_object_get(properties, "scrollingMode"); - _legacyType.wall.scrolling_mode = jScrollingMode != nullptr ? json_integer_value(jScrollingMode) : SCROLLING_MODE_NONE; - - SetPrimarySceneryGroup(ObjectJsonHelpers::GetString(json_object_get(properties, "sceneryGroup"))); - - // Flags - _legacyType.wall.flags = ObjectJsonHelpers::GetFlags( - properties, - { - { "hasPrimaryColour", WALL_SCENERY_HAS_PRIMARY_COLOUR }, - { "hasSecondaryColour", WALL_SCENERY_HAS_SECONDARY_COLOUR }, - { "hasTernaryColour", WALL_SCENERY_HAS_TERNARY_COLOUR }, - { "hasGlass", WALL_SCENERY_HAS_GLASS }, - { "isBanner", WALL_SCENERY_IS_BANNER }, - { "isDoor", WALL_SCENERY_IS_DOOR }, - { "isLongDoorAnimation", WALL_SCENERY_LONG_DOOR_ANIMATION }, - }); - _legacyType.wall.flags2 = ObjectJsonHelpers::GetFlags( - properties, - { - { "isOpaque", WALL_SCENERY_2_IS_OPAQUE }, - { "isAnimated", WALL_SCENERY_2_ANIMATED }, - }); - - // HACK To avoid 'negated' properties in JSON, handle this separately until - // flag is inverted in this code base. - if (!ObjectJsonHelpers::GetBoolean(properties, "isAllowedOnSlope", false)) + if (properties.is_object()) { - _legacyType.wall.flags |= WALL_SCENERY_CANT_BUILD_ON_SLOPE; - } + _legacyType.wall.tool_id = Cursor::FromString(Json::GetString(properties["cursor"]), CURSOR_FENCE_DOWN); + _legacyType.wall.height = Json::GetNumber(properties["height"]); + _legacyType.wall.price = Json::GetNumber(properties["price"]); - // HACK WALL_SCENERY_HAS_PRIMARY_COLOUR actually means, has any colour but we simplify the - // JSON and handle this on load. We should change code base in future to reflect the JSON. - if (!(_legacyType.wall.flags & WALL_SCENERY_HAS_PRIMARY_COLOUR)) - { - if ((_legacyType.wall.flags & WALL_SCENERY_HAS_SECONDARY_COLOUR) - || (_legacyType.wall.flags & WALL_SCENERY_HAS_TERNARY_COLOUR)) + _legacyType.wall.scrolling_mode = Json::GetNumber(properties["scrollingMode"], SCROLLING_MODE_NONE); + + SetPrimarySceneryGroup(Json::GetString(properties["sceneryGroup"])); + + // clang-format off + _legacyType.wall.flags = Json::GetFlags( + properties, + { + { "hasPrimaryColour", WALL_SCENERY_HAS_PRIMARY_COLOUR, Json::FlagType::Normal }, + { "IsAllowedOnSlope", WALL_SCENERY_CANT_BUILD_ON_SLOPE, Json::FlagType::Inverted }, + { "hasSecondaryColour", WALL_SCENERY_HAS_SECONDARY_COLOUR, Json::FlagType::Normal }, + { "hasTernaryColour", WALL_SCENERY_HAS_TERNARY_COLOUR, Json::FlagType::Normal }, + { "hasGlass", WALL_SCENERY_HAS_GLASS, Json::FlagType::Normal }, + { "isBanner", WALL_SCENERY_IS_BANNER, Json::FlagType::Normal }, + { "isDoor", WALL_SCENERY_IS_DOOR, Json::FlagType::Normal }, + { "isLongDoorAnimation", WALL_SCENERY_LONG_DOOR_ANIMATION, Json::FlagType::Normal }, + }); + // clang-format on + + _legacyType.wall.flags2 = Json::GetFlags( + properties, + { + { "isOpaque", WALL_SCENERY_2_IS_OPAQUE }, + { "isAnimated", WALL_SCENERY_2_ANIMATED }, + }); + + // HACK WALL_SCENERY_HAS_PRIMARY_COLOUR actually means, has any colour but we simplify the + // JSON and handle this on load. We should change code base in future to reflect the JSON. + if (!(_legacyType.wall.flags & WALL_SCENERY_HAS_PRIMARY_COLOUR)) { - _legacyType.wall.flags |= WALL_SCENERY_HAS_PRIMARY_COLOUR; - _legacyType.wall.flags2 |= WALL_SCENERY_2_NO_SELECT_PRIMARY_COLOUR; + if (_legacyType.wall.flags & (WALL_SCENERY_HAS_SECONDARY_COLOUR | WALL_SCENERY_HAS_TERNARY_COLOUR)) + { + _legacyType.wall.flags |= WALL_SCENERY_HAS_PRIMARY_COLOUR; + _legacyType.wall.flags2 |= WALL_SCENERY_2_NO_SELECT_PRIMARY_COLOUR; + } + } + + // Door sound + auto jDoorSound = properties["doorSound"]; + if (jDoorSound.is_number()) + { + auto doorSound = Json::GetNumber(jDoorSound); + _legacyType.wall.flags2 |= (doorSound << WALL_SCENERY_2_DOOR_SOUND_SHIFT) & WALL_SCENERY_2_DOOR_SOUND_MASK; } } - // Door sound - auto jDoorSound = json_object_get(properties, "doorSound"); - if (jDoorSound != nullptr) - { - auto doorSound = json_integer_value(jDoorSound); - _legacyType.wall.flags2 |= (doorSound << WALL_SCENERY_2_DOOR_SOUND_SHIFT) & WALL_SCENERY_2_DOOR_SOUND_MASK; - } - - ObjectJsonHelpers::LoadStrings(root, GetStringTable()); - ObjectJsonHelpers::LoadImages(context, root, GetImageTable()); + PopulateTablesFromJson(context, root); } diff --git a/src/openrct2/object/WallObject.h b/src/openrct2/object/WallObject.h index 403ecd81ca..82b89ef7fa 100644 --- a/src/openrct2/object/WallObject.h +++ b/src/openrct2/object/WallObject.h @@ -29,7 +29,7 @@ public: } void ReadLegacy(IReadObjectContext* context, OpenRCT2::IStream* stream) override; - void ReadJson(IReadObjectContext* context, const json_t* root) override; + void ReadJson(IReadObjectContext* context, json_t& root) override; void Load() override; void Unload() override; diff --git a/src/openrct2/object/WaterObject.cpp b/src/openrct2/object/WaterObject.cpp index 9925372db0..69df434eb9 100644 --- a/src/openrct2/object/WaterObject.cpp +++ b/src/openrct2/object/WaterObject.cpp @@ -16,7 +16,6 @@ #include "../localisation/Language.h" #include "../localisation/StringIds.h" #include "../world/Location.hpp" -#include "ObjectJsonHelpers.h" #include @@ -55,52 +54,57 @@ void WaterObject::DrawPreview(rct_drawpixelinfo* dpi, int32_t width, int32_t hei gfx_draw_string_centred(dpi, STR_WINDOW_NO_IMAGE, screenCoords, COLOUR_BLACK, nullptr); } -void WaterObject::ReadJson([[maybe_unused]] IReadObjectContext* context, const json_t* root) +void WaterObject::ReadJson([[maybe_unused]] IReadObjectContext* context, json_t& root) { - auto properties = json_object_get(root, "properties"); - _legacyType.flags = ObjectJsonHelpers::GetFlags( - properties, - { - { "allowDucks", WATER_FLAGS_ALLOW_DUCKS }, - }); + Guard::Assert(root.is_object(), "WaterObject::ReadJson expects parameter root to be object"); - ObjectJsonHelpers::LoadStrings(root, GetStringTable()); + auto properties = root["properties"]; - // Images which are actually palette data - static const char* paletteNames[] = { - "general", "waves-0", "waves-1", "waves-2", "sparkles-0", "sparkles-1", "sparkles-2", - }; - for (auto paletteName : paletteNames) + PopulateTablesFromJson(context, root); + + if (properties.is_object()) { - auto jPalettes = json_object_get(properties, "palettes"); - if (jPalettes != nullptr) - { - auto jPalette = json_object_get(jPalettes, paletteName); - if (jPalette != nullptr) + _legacyType.flags = Json::GetFlags( + properties, { - ReadJsonPalette(jPalette); + { "allowDucks", WATER_FLAGS_ALLOW_DUCKS }, + }); + + auto jPalettes = properties["palettes"]; + if (jPalettes.is_object()) + { + // Images which are actually palette data + static const char* paletteNames[] = { + "general", "waves-0", "waves-1", "waves-2", "sparkles-0", "sparkles-1", "sparkles-2", + }; + for (auto paletteName : paletteNames) + { + auto jPalette = jPalettes[paletteName]; + if (jPalette.is_object()) + { + ReadJsonPalette(jPalette); + } } } } } -void WaterObject::ReadJsonPalette(const json_t* jPalette) +void WaterObject::ReadJsonPalette(json_t& jPalette) { - auto paletteStartIndex = json_integer_value(json_object_get(jPalette, "index")); - auto jColours = json_object_get(jPalette, "colours"); - auto numColours = json_array_size(jColours); + Guard::Assert(jPalette.is_object(), "WaterObject::ReadJsonPalette expects parameter jPalette to be object"); + auto jColours = jPalette["colours"]; + auto numColours = jColours.size(); + + // This pointer gets memcopied in ImageTable::AddImage so it's fine for the unique_ptr to go out of scope auto data = std::make_unique(numColours * 3); size_t dataIndex = 0; - size_t index; - const json_t* jColour; - json_array_foreach(jColours, index, jColour) + for (auto& jColour : jColours) { - auto szColour = json_string_value(jColour); - if (szColour != nullptr) + if (jColour.is_string()) { - auto colour = ParseColour(szColour); + auto colour = ParseColour(Json::GetString(jColour)); data[dataIndex + 0] = (colour >> 16) & 0xFF; data[dataIndex + 1] = (colour >> 8) & 0xFF; data[dataIndex + 2] = colour & 0xFF; @@ -111,7 +115,7 @@ void WaterObject::ReadJsonPalette(const json_t* jPalette) rct_g1_element g1 = {}; g1.offset = data.get(); g1.width = static_cast(numColours); - g1.x_offset = static_cast(paletteStartIndex); + g1.x_offset = Json::GetNumber(jPalette["index"]); g1.flags = G1_FLAG_PALETTE; auto& imageTable = GetImageTable(); diff --git a/src/openrct2/object/WaterObject.h b/src/openrct2/object/WaterObject.h index b7dcfad231..bac5e274b5 100644 --- a/src/openrct2/object/WaterObject.h +++ b/src/openrct2/object/WaterObject.h @@ -30,7 +30,7 @@ public: return &_legacyType; } - void ReadJson(IReadObjectContext* context, const json_t* root) override; + void ReadJson(IReadObjectContext* context, json_t& root) override; void ReadLegacy(IReadObjectContext* context, OpenRCT2::IStream* stream) override; void Load() override; void Unload() override; @@ -38,6 +38,6 @@ public: void DrawPreview(rct_drawpixelinfo* dpi, int32_t width, int32_t height) const override; private: - void ReadJsonPalette(const json_t* jPalette); + void ReadJsonPalette(json_t& jPalette); uint32_t ParseColour(const std::string& s) const; };