Refactor objects to use new JSON library

This commit is contained in:
Simon Jarrett 2020-08-12 23:05:23 +01:00
parent 97b44a7181
commit 0c58dfa1b3
27 changed files with 666 additions and 671 deletions

View File

@ -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<uint8_t>(
properties,
{
{ "hasPrimaryColour", BANNER_ENTRY_FLAG_HAS_PRIMARY_COLOUR },
});
if (properties.is_object())
{
_legacyType.banner.scrolling_mode = Json::GetNumber<uint8_t>(properties["scrollingMode"]);
_legacyType.banner.price = Json::GetNumber<int16_t>(properties["price"]);
_legacyType.banner.flags = Json::GetFlags<uint8_t>(
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);
}

View File

@ -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;

View File

@ -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<uint8_t>(properties["scrollingMode"]);
_legacyType.text_height = Json::GetNumber<uint8_t>(properties["textHeight"]);
}
PopulateTablesFromJson(context, root);
}

View File

@ -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;

View File

@ -15,7 +15,6 @@
#include "../localisation/Localisation.h"
#include "../object/Object.h"
#include "../object/ObjectRepository.h"
#include "ObjectJsonHelpers.h"
#include "ObjectList.h"
#include <unordered_map>
@ -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<uint16_t>(
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<int16_t>(properties["price"]);
SetPrimarySceneryGroup(Json::GetString(properties["sceneryGroup"]));
// clang-format off
_legacyType.path_bit.flags = Json::GetFlags<uint16_t>(
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);
}

View File

@ -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;

View File

@ -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<uint8_t>(
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<uint8_t>(properties["scrollingMode"]);
_legacyType.flags = Json::GetFlags<uint8_t>(
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);
}

View File

@ -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;

View File

@ -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 <algorithm>
#include <iterator>
@ -121,84 +121,83 @@ std::vector<rct_large_scenery_tile> 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<uint8_t>(
properties,
_legacyType.large_scenery.price = Json::GetNumber<int16_t>(properties["price"]);
_legacyType.large_scenery.removal_price = Json::GetNumber<int16_t>(properties["removalPrice"]);
_legacyType.large_scenery.scrolling_mode = Json::GetNumber<uint8_t>(properties["scrollingMode"], SCROLLING_MODE_NONE);
_legacyType.large_scenery.flags = Json::GetFlags<uint8_t>(
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<rct_large_scenery_tile> LargeSceneryObject::ReadJsonTiles(const json_t* jTiles)
std::vector<rct_large_scenery_tile> LargeSceneryObject::ReadJsonTiles(json_t& jTiles)
{
std::vector<rct_large_scenery_tile> 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<int16_t>(jTile["x"]);
tile.y_offset = Json::GetNumber<int16_t>(jTile["y"]);
tile.z_offset = Json::GetNumber<int16_t>(jTile["z"]);
tile.z_clearance = Json::GetNumber<int8_t>(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<uint16_t>(
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<uint16_t>(jTile["corners"], 0xF);
tile.flags |= (corners & 0xFF) << 12;
auto walls = Json::GetNumber<int16_t>(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<rct_large_scenery_tile> LargeSceneryObject::ReadJsonTiles(const json
return tiles;
}
std::unique_ptr<rct_large_scenery_text> LargeSceneryObject::ReadJson3dFont(const json_t* j3dFont)
std::unique_ptr<rct_large_scenery_text> LargeSceneryObject::ReadJson3dFont(json_t& j3dFont)
{
Guard::Assert(j3dFont.is_object(), "LargeSceneryObject::ReadJson3dFont expects parameter j3dFont to be object");
auto font = std::make_unique<rct_large_scenery_text>();
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<uint8_t>(
font->max_width = Json::GetNumber<uint16_t>(j3dFont["maxWidth"]);
font->num_images = Json::GetNumber<uint8_t>(j3dFont["numImages"]);
font->flags = Json::GetFlags<uint8_t>(
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<rct_large_scenery_text> LargeSceneryObject::ReadJson3dFont(const
return font;
}
std::vector<LocationXY16> LargeSceneryObject::ReadJsonOffsets(const json_t* jOffsets)
std::vector<LocationXY16> LargeSceneryObject::ReadJsonOffsets(json_t& jOffsets)
{
std::vector<LocationXY16> 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<int16_t>(jOffset["x"]);
offset.y = Json::GetNumber<int16_t>(jOffset["y"]);
offsets.push_back(offset);
}
}
return offsets;
}
std::vector<rct_large_scenery_text_glyph> LargeSceneryObject::ReadJsonGlyphs(const json_t* jGlpyhs)
std::vector<rct_large_scenery_text_glyph> LargeSceneryObject::ReadJsonGlyphs(json_t& jGlyphs)
{
std::vector<rct_large_scenery_text_glyph> 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<uint8_t>(jGlyph["image"]);
glyph.width = Json::GetNumber<uint8_t>(jGlyph["width"]);
glyph.height = Json::GetNumber<uint8_t>(jGlyph["height"]);
glyphs.push_back(glyph);
}
}
return glyphs;
}

View File

@ -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<rct_large_scenery_tile> ReadTiles(OpenRCT2::IStream* stream);
static std::vector<rct_large_scenery_tile> ReadJsonTiles(const json_t* jTiles);
static std::unique_ptr<rct_large_scenery_text> ReadJson3dFont(const json_t* j3dFont);
static std::vector<LocationXY16> ReadJsonOffsets(const json_t* jOffsets);
static std::vector<rct_large_scenery_text_glyph> ReadJsonGlyphs(const json_t* jGlpyhs);
static std::vector<rct_large_scenery_tile> ReadJsonTiles(json_t& jTiles);
static std::unique_ptr<rct_large_scenery_text> ReadJson3dFont(json_t& j3dFont);
static std::vector<LocationXY16> ReadJsonOffsets(json_t& jOffsets);
static std::vector<rct_large_scenery_text_glyph> ReadJsonGlyphs(json_t& jGlyphs);
};

View File

@ -23,7 +23,6 @@
#include "../ride/RideData.h"
#include "../ride/ShopItem.h"
#include "../ride/Track.h"
#include "ObjectJsonHelpers.h"
#include "ObjectRepository.h"
#include <algorithm>
@ -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<uint8_t>(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<size_t>(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<int32_t>(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<int32_t>(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<int8_t>(ratingMultiplier["excitement"]);
_legacyType.intensity_multiplier = Json::GetNumber<int8_t>(ratingMultiplier["intensity"]);
_legacyType.nausea_multiplier = Json::GetNumber<int8_t>(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<size_t>(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<uint8_t>(properties["buildMenuPriority"]);
_legacyType.flags |= Json::GetFlags<uint32_t>(
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<uint32_t>(
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<uint8_t>(properties["minCarsPerTrain"], 1);
_legacyType.max_cars_in_train = Json::GetNumber<uint8_t>(properties["maxCarsPerTrain"], 1);
_legacyType.cars_per_flat_ride = Json::GetNumber<uint8_t>(properties["carsPerFlatRide"], 255);
_legacyType.zero_cars = Json::GetNumber<uint8_t>(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<uint8_t>(properties["defaultCar"]);
_legacyType.tab_vehicle = Json::GetNumber<uint8_t>(properties["tabCar"]);
float tabScale = Json::GetNumber<float>(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<uint8_t>(headCars[0], 0xFF);
_legacyType.second_vehicle = Json::GetNumber<uint8_t>(headCars[1], 0xFF);
_legacyType.third_vehicle = Json::GetNumber<uint8_t>(headCars[2], 0xFF);
_legacyType.rear_vehicle = Json::GetNumber<uint8_t>(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<rct_ride_entry_vehicle> RideObject::ReadJsonCars(const json_t* jCars)
std::vector<rct_ride_entry_vehicle> RideObject::ReadJsonCars(json_t& jCars)
{
std::vector<rct_ride_entry_vehicle> 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<uint16_t>(jCar["rotationFrameMask"]);
car.spacing = Json::GetNumber<uint32_t>(jCar["spacing"]);
car.car_mass = Json::GetNumber<uint16_t>(jCar["mass"]);
car.tab_height = Json::GetNumber<int8_t>(jCar["tabOffset"]);
car.num_seats = Json::GetNumber<uint8_t>(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<SoundId>(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<uint8_t>(jCar["spriteWidth"]);
car.sprite_height_negative = Json::GetNumber<uint8_t>(jCar["spriteHeightNegative"]);
car.sprite_height_positive = Json::GetNumber<uint8_t>(jCar["spriteHeightPositive"]);
car.animation = Json::GetNumber<uint8_t>(jCar["animation"]);
car.base_num_frames = Json::GetNumber<uint16_t>(jCar["baseNumFrames"]);
car.no_vehicle_images = Json::GetNumber<uint32_t>(jCar["numImages"]);
car.no_seating_rows = Json::GetNumber<uint8_t>(jCar["numSeatRows"]);
car.spinning_inertia = Json::GetNumber<uint8_t>(jCar["spinningInertia"]);
car.spinning_friction = Json::GetNumber<uint8_t>(jCar["spinningFriction"]);
car.friction_sound_id = Json::GetEnum<SoundId>(jCar["frictionSoundId"], SoundId::Null);
car.log_flume_reverser_vehicle_type = Json::GetNumber<uint8_t>(jCar["logFlumeReverserVehicleType"]);
car.sound_range = Json::GetNumber<uint8_t>(jCar["soundRange"], 255);
car.double_sound_frequency = Json::GetNumber<uint8_t>(jCar["doubleSoundFrequency"]);
car.powered_acceleration = Json::GetNumber<uint8_t>(jCar["poweredAcceleration"]);
car.powered_max_speed = Json::GetNumber<uint8_t>(jCar["poweredMaxSpeed"]);
car.car_visual = Json::GetNumber<uint8_t>(jCar["carVisual"]);
car.effect_visual = Json::GetNumber<uint8_t>(jCar["effectVisual"], 1);
car.draw_order = Json::GetNumber<uint8_t>(jCar["drawOrder"]);
car.num_vertical_frames_override = Json::GetNumber<uint8_t>(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<int8_t>(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<uint8_t>(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<CoordsXY, 3> 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<int32_t>(jWaypoint[0]);
int32_t y = Json::GetNumber<int32_t>(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<uint16_t>(
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<uint16_t>(
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<uint32_t>(
car.flags |= Json::GetFlags<uint32_t>(
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<vehicle_colour> RideObject::ReadJsonColourConfiguration(const json_t* jColourConfig)
std::vector<vehicle_colour> RideObject::ReadJsonColourConfiguration(json_t& jColourConfig)
{
std::vector<vehicle_colour> 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);

View File

@ -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<rct_ride_entry_vehicle> 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<vehicle_colour> ReadJsonColourConfiguration(const json_t* jColourConfig);
void ReadJsonVehicleInfo(IReadObjectContext* context, json_t& properties);
std::vector<rct_ride_entry_vehicle> ReadJsonCars(json_t& jCars);
rct_ride_entry_vehicle ReadJsonCar(json_t& jCar);
vehicle_colour_preset_list ReadJsonCarColours(json_t& jCarColours);
std::vector<vehicle_colour> ReadJsonColourConfiguration(json_t& jColourConfig);
static uint8_t CalculateNumVerticalFrames(const rct_ride_entry_vehicle* vehicleEntry);
static uint8_t CalculateNumHorizontalFrames(const rct_ride_entry_vehicle* vehicleEntry);

View File

@ -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<rct_object_entry> 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<uint8_t>(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<uint8_t>(peepSprite));
}
@ -172,19 +165,14 @@ EntertainerCostume SceneryGroupObject::ParseEntertainerCostume(const std::string
return EntertainerCostume::Panda;
}
std::vector<rct_object_entry> SceneryGroupObject::ReadJsonEntries(const json_t* jEntries)
std::vector<rct_object_entry> SceneryGroupObject::ReadJsonEntries(json_t& jEntries)
{
std::vector<rct_object_entry> 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;
}

View File

@ -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<rct_object_entry> 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<rct_object_entry> ReadJsonEntries(const json_t* jEntries);
static std::vector<rct_object_entry> ReadJsonEntries(json_t& jEntries);
};

View File

@ -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);
}
}

View File

@ -19,7 +19,6 @@
#include "../localisation/Language.h"
#include "../world/Scenery.h"
#include "../world/SmallScenery.h"
#include "ObjectJsonHelpers.h"
#include <algorithm>
@ -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<uint32_t>(
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<uint8_t>(properties["height"]);
_legacyType.small_scenery.tool_id = Cursor::FromString(Json::GetString(properties["cursor"]), CURSOR_STATUE_DOWN);
_legacyType.small_scenery.price = Json::GetNumber<uint16_t>(properties["price"]);
_legacyType.small_scenery.removal_price = Json::GetNumber<uint16_t>(properties["removalPrice"]);
_legacyType.small_scenery.animation_delay = Json::GetNumber<uint16_t>(properties["animationDelay"]);
_legacyType.small_scenery.animation_mask = Json::GetNumber<uint16_t>(properties["animationMask"]);
_legacyType.small_scenery.num_frames = Json::GetNumber<uint16_t>(properties["numFrames"]);
_legacyType.small_scenery.flags = Json::GetFlags<uint32_t>(
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<uint8_t> SmallSceneryObject::ReadJsonFrameOffsets(const json_t* jFrameOffsets)
std::vector<uint8_t> SmallSceneryObject::ReadJsonFrameOffsets(json_t& jFrameOffsets)
{
std::vector<uint8_t> 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<uint8_t>(jOffset));
}
return offsets;
}

View File

@ -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<uint8_t> ReadFrameOffsets(OpenRCT2::IStream* stream);
static std::vector<uint8_t> ReadJsonFrameOffsets(const json_t* jFrameOffsets);
static std::vector<uint8_t> ReadJsonFrameOffsets(json_t& jFrameOffsets);
void PerformFixes();
rct_object_entry GetScgPiratHeader();
rct_object_entry GetScgMineHeader();

View File

@ -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<uint32_t>(
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<int32_t>(properties["height"]);
ScrollingMode = Json::GetNumber<uint8_t>(properties["scrollingMode"], SCROLLING_MODE_NONE);
Flags = Json::GetFlags<uint32_t>(
properties,
{
{ "hasPrimaryColour", STATION_OBJECT_FLAGS::HAS_PRIMARY_COLOUR },
{ "hasSecondaryColour", STATION_OBJECT_FLAGS::HAS_SECONDARY_COLOUR },
{ "isTransparent", STATION_OBJECT_FLAGS::IS_TRANSPARENT },
});
}
PopulateTablesFromJson(context, root);
}

View File

@ -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;

View File

@ -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();
}

View File

@ -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;

View File

@ -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<TERRAIN_SURFACE_FLAGS>(
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<int8_t>(properties["rotations"], 1);
Price = Json::GetNumber<money32>(properties["price"]);
Flags = Json::GetFlags<TERRAIN_SURFACE_FLAGS>(
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<uint32_t>(el["index"]);
entry.Length = Json::GetNumber<int32_t>(el["length"], -1);
entry.Rotation = Json::GetNumber<int32_t>(el["rotation"], -1);
entry.Variation = Json::GetNumber<int32_t>(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<uint32_t>(jDefault["normal"]);
DefaultGridEntry = Json::GetNumber<uint32_t>(jDefault["grid"]);
DefaultUndergroundEntry = Json::GetNumber<uint32_t>(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(

View File

@ -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;

View File

@ -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<uint8_t>(
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<uint8_t>(
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<uint8_t>(properties["height"]);
_legacyType.wall.price = Json::GetNumber<int16_t>(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<uint8_t>(properties["scrollingMode"], SCROLLING_MODE_NONE);
SetPrimarySceneryGroup(Json::GetString(properties["sceneryGroup"]));
// clang-format off
_legacyType.wall.flags = Json::GetFlags<uint8_t>(
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<uint8_t>(
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<uint8_t>(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);
}

View File

@ -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;

View File

@ -16,7 +16,6 @@
#include "../localisation/Language.h"
#include "../localisation/StringIds.h"
#include "../world/Location.hpp"
#include "ObjectJsonHelpers.h"
#include <memory>
@ -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<uint16_t>(
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<uint16_t>(
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<uint8_t[]>(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<int16_t>(numColours);
g1.x_offset = static_cast<int16_t>(paletteStartIndex);
g1.x_offset = Json::GetNumber<int16_t>(jPalette["index"]);
g1.flags = G1_FLAG_PALETTE;
auto& imageTable = GetImageTable();

View File

@ -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;
};