mirror of https://github.com/OpenRCT2/OpenRCT2.git
396 lines
9.7 KiB
C++
396 lines
9.7 KiB
C++
/*****************************************************************************
|
|
* Copyright (c) 2014-2021 OpenRCT2 developers
|
|
*
|
|
* For a complete list of all authors, please refer to contributors.md
|
|
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
|
|
*
|
|
* OpenRCT2 is licensed under the GNU General Public License version 3.
|
|
*****************************************************************************/
|
|
|
|
#pragma once
|
|
|
|
#include "../common.h"
|
|
#include "../core/JsonFwd.hpp"
|
|
#include "../util/Util.h"
|
|
#include "ImageTable.h"
|
|
#include "StringTable.h"
|
|
|
|
#include <limits>
|
|
#include <memory>
|
|
#include <optional>
|
|
#include <string_view>
|
|
#include <vector>
|
|
|
|
using ObjectEntryIndex = uint16_t;
|
|
constexpr const ObjectEntryIndex OBJECT_ENTRY_INDEX_NULL = std::numeric_limits<ObjectEntryIndex>::max();
|
|
struct ObjectRepositoryItem;
|
|
|
|
// First 0xF of rct_object_entry->flags
|
|
enum class ObjectType : uint8_t
|
|
{
|
|
Ride,
|
|
SmallScenery,
|
|
LargeScenery,
|
|
Walls,
|
|
Banners,
|
|
Paths,
|
|
PathBits,
|
|
SceneryGroup,
|
|
ParkEntrance,
|
|
Water,
|
|
ScenarioText,
|
|
TerrainSurface,
|
|
TerrainEdge,
|
|
Station,
|
|
Music,
|
|
FootpathSurface,
|
|
FootpathRailings,
|
|
|
|
Count,
|
|
None = 255
|
|
};
|
|
|
|
ObjectType& operator++(ObjectType& d, int);
|
|
|
|
enum OBJECT_SELECTION_FLAGS
|
|
{
|
|
OBJECT_SELECTION_FLAG_SELECTED = (1 << 0),
|
|
OBJECT_SELECTION_FLAG_2 = (1 << 1),
|
|
OBJECT_SELECTION_FLAG_IN_USE = (1 << 2),
|
|
// OBJECT_SELECTION_FLAG_REQUIRED = (1 << 3), // Unused feature
|
|
OBJECT_SELECTION_FLAG_ALWAYS_REQUIRED = (1 << 4),
|
|
OBJECT_SELECTION_FLAG_6 = (1 << 5),
|
|
OBJECT_SELECTION_FLAG_7 = (1 << 6),
|
|
OBJECT_SELECTION_FLAG_8 = (1 << 7),
|
|
OBJECT_SELECTION_FLAG_ALL = 0xFF,
|
|
};
|
|
|
|
#define OBJECT_SELECTION_NOT_SELECTED_OR_REQUIRED 0
|
|
|
|
enum class ObjectSourceGame : uint8_t
|
|
{
|
|
Custom,
|
|
WackyWorlds,
|
|
TimeTwister,
|
|
OpenRCT2Official,
|
|
RCT1,
|
|
AddedAttractions,
|
|
LoopyLandscapes,
|
|
RCT2 = 8
|
|
};
|
|
|
|
#pragma pack(push, 1)
|
|
/**
|
|
* Object entry structure.
|
|
* size: 0x10
|
|
*/
|
|
struct rct_object_entry
|
|
{
|
|
union
|
|
{
|
|
uint8_t end_flag; // needed not to read past allocated buffer.
|
|
uint32_t flags;
|
|
};
|
|
union
|
|
{
|
|
char nameWOC[12];
|
|
struct
|
|
{
|
|
char name[8];
|
|
uint32_t checksum;
|
|
};
|
|
};
|
|
|
|
std::string_view GetName() const
|
|
{
|
|
return std::string_view(name, std::size(name));
|
|
}
|
|
|
|
void SetName(std::string_view value);
|
|
|
|
ObjectType GetType() const
|
|
{
|
|
return static_cast<ObjectType>(flags & 0x0F);
|
|
}
|
|
|
|
void SetType(ObjectType newType)
|
|
{
|
|
flags &= ~0x0F;
|
|
flags |= (static_cast<uint8_t>(newType) & 0x0F);
|
|
}
|
|
|
|
ObjectSourceGame GetSourceGame() const
|
|
{
|
|
return static_cast<ObjectSourceGame>((flags & 0xF0) >> 4);
|
|
}
|
|
|
|
bool IsEmpty() const;
|
|
bool operator==(const rct_object_entry& rhs) const;
|
|
bool operator!=(const rct_object_entry& rhs) const;
|
|
};
|
|
assert_struct_size(rct_object_entry, 0x10);
|
|
|
|
struct rct_object_entry_group
|
|
{
|
|
void** chunks;
|
|
rct_object_entry* entries;
|
|
};
|
|
#ifdef PLATFORM_32BIT
|
|
assert_struct_size(rct_object_entry_group, 8);
|
|
#endif
|
|
|
|
struct rct_ride_filters
|
|
{
|
|
uint8_t category[2];
|
|
uint8_t ride_type;
|
|
};
|
|
assert_struct_size(rct_ride_filters, 3);
|
|
|
|
struct rct_object_filters
|
|
{
|
|
union
|
|
{
|
|
rct_ride_filters ride;
|
|
};
|
|
};
|
|
assert_struct_size(rct_object_filters, 3);
|
|
#pragma pack(pop)
|
|
|
|
enum class ObjectGeneration : uint8_t
|
|
{
|
|
DAT,
|
|
JSON,
|
|
};
|
|
|
|
struct ObjectEntryDescriptor
|
|
{
|
|
ObjectGeneration Generation = ObjectGeneration::JSON;
|
|
|
|
// DAT
|
|
rct_object_entry Entry{};
|
|
|
|
// JSON
|
|
ObjectType Type{};
|
|
std::string Identifier;
|
|
std::string Version;
|
|
|
|
ObjectEntryDescriptor() = default;
|
|
explicit ObjectEntryDescriptor(const rct_object_entry& newEntry);
|
|
explicit ObjectEntryDescriptor(std::string_view newIdentifier);
|
|
explicit ObjectEntryDescriptor(ObjectType type, std::string_view newIdentifier);
|
|
explicit ObjectEntryDescriptor(const ObjectRepositoryItem& ori);
|
|
bool HasValue() const;
|
|
ObjectType GetType() const;
|
|
std::string_view GetName() const;
|
|
|
|
bool operator==(const ObjectEntryDescriptor& rhs) const;
|
|
bool operator!=(const ObjectEntryDescriptor& rhs) const;
|
|
};
|
|
|
|
struct IObjectRepository;
|
|
namespace OpenRCT2
|
|
{
|
|
struct IStream;
|
|
}
|
|
struct ObjectRepositoryItem;
|
|
struct rct_drawpixelinfo;
|
|
|
|
enum class ObjectError : uint32_t
|
|
{
|
|
Ok,
|
|
Unknown,
|
|
BadEncoding,
|
|
InvalidProperty,
|
|
BadStringTable,
|
|
BadImageTable,
|
|
UnexpectedEOF,
|
|
};
|
|
|
|
class ObjectAsset
|
|
{
|
|
private:
|
|
std::string _zipPath;
|
|
std::string _path;
|
|
|
|
public:
|
|
ObjectAsset() = default;
|
|
ObjectAsset(std::string_view path)
|
|
: _path(path)
|
|
{
|
|
}
|
|
ObjectAsset(std::string_view zipPath, std::string_view path)
|
|
: _zipPath(zipPath)
|
|
, _path(path)
|
|
{
|
|
}
|
|
|
|
[[nodiscard]] bool IsAvailable() const;
|
|
[[nodiscard]] uint64_t GetSize() const;
|
|
[[nodiscard]] std::unique_ptr<OpenRCT2::IStream> GetStream() const;
|
|
};
|
|
|
|
struct IReadObjectContext
|
|
{
|
|
virtual ~IReadObjectContext() = default;
|
|
|
|
virtual std::string_view GetObjectIdentifier() abstract;
|
|
virtual IObjectRepository& GetObjectRepository() abstract;
|
|
virtual bool ShouldLoadImages() abstract;
|
|
virtual std::vector<uint8_t> GetData(std::string_view path) abstract;
|
|
virtual ObjectAsset GetAsset(std::string_view path) abstract;
|
|
|
|
virtual void LogVerbose(ObjectError code, const utf8* text) abstract;
|
|
virtual void LogWarning(ObjectError code, const utf8* text) abstract;
|
|
virtual void LogError(ObjectError code, const utf8* text) abstract;
|
|
};
|
|
|
|
#ifdef __WARN_SUGGEST_FINAL_TYPES__
|
|
# pragma GCC diagnostic push
|
|
# pragma GCC diagnostic ignored "-Wsuggest-final-types"
|
|
# pragma GCC diagnostic ignored "-Wsuggest-final-methods"
|
|
#endif
|
|
class Object
|
|
{
|
|
private:
|
|
std::string _identifier;
|
|
ObjectEntryDescriptor _descriptor{};
|
|
StringTable _stringTable;
|
|
ImageTable _imageTable;
|
|
std::vector<ObjectSourceGame> _sourceGames;
|
|
std::vector<std::string> _authors;
|
|
ObjectGeneration _generation{};
|
|
|
|
protected:
|
|
StringTable& GetStringTable()
|
|
{
|
|
return _stringTable;
|
|
}
|
|
const StringTable& GetStringTable() const
|
|
{
|
|
return _stringTable;
|
|
}
|
|
ImageTable& GetImageTable()
|
|
{
|
|
return _imageTable;
|
|
}
|
|
|
|
/**
|
|
* Populates the image and string tables from a JSON object
|
|
* @param context
|
|
* @param root JSON node of type object containing image and string info
|
|
* @note root is deliberately left non-const: json_t behaviour changes when const
|
|
*/
|
|
void PopulateTablesFromJson(IReadObjectContext* context, json_t& root);
|
|
|
|
static rct_object_entry ParseObjectEntry(const std::string& s);
|
|
|
|
std::string GetOverrideString(uint8_t index) const;
|
|
std::string GetString(ObjectStringID index) const;
|
|
std::string GetString(int32_t language, ObjectStringID index) const;
|
|
|
|
public:
|
|
virtual ~Object() = default;
|
|
|
|
std::string_view GetIdentifier() const
|
|
{
|
|
return _identifier;
|
|
}
|
|
void SetIdentifier(std::string_view identifier)
|
|
{
|
|
_identifier = identifier;
|
|
}
|
|
|
|
void MarkAsJsonObject()
|
|
{
|
|
_generation = ObjectGeneration::JSON;
|
|
}
|
|
|
|
ObjectGeneration GetGeneration() const
|
|
{
|
|
return _generation;
|
|
};
|
|
|
|
ObjectType GetObjectType() const
|
|
{
|
|
return _descriptor.GetType();
|
|
}
|
|
|
|
ObjectEntryDescriptor GetDescriptor() const
|
|
{
|
|
return _descriptor;
|
|
}
|
|
void SetDescriptor(const ObjectEntryDescriptor& value)
|
|
{
|
|
_descriptor = value;
|
|
}
|
|
|
|
// Legacy data structures
|
|
std::string_view GetLegacyIdentifier() const
|
|
{
|
|
return _descriptor.GetName();
|
|
}
|
|
|
|
// TODO remove this, we should no longer assume objects have a legacy object entry
|
|
const rct_object_entry& GetObjectEntry() const
|
|
{
|
|
return _descriptor.Entry;
|
|
}
|
|
virtual void* GetLegacyData();
|
|
|
|
/**
|
|
* @note root is deliberately left non-const: json_t behaviour changes when const
|
|
*/
|
|
virtual void ReadJson(IReadObjectContext* /*context*/, json_t& /*root*/)
|
|
{
|
|
}
|
|
virtual void ReadLegacy(IReadObjectContext* context, OpenRCT2::IStream* stream);
|
|
virtual void Load() abstract;
|
|
virtual void Unload() abstract;
|
|
|
|
virtual void DrawPreview(rct_drawpixelinfo* /*dpi*/, int32_t /*width*/, int32_t /*height*/) const
|
|
{
|
|
}
|
|
|
|
virtual std::string GetName() const;
|
|
virtual std::string GetName(int32_t language) const;
|
|
|
|
virtual void SetRepositoryItem(ObjectRepositoryItem* /*item*/) const
|
|
{
|
|
}
|
|
std::vector<ObjectSourceGame> GetSourceGames();
|
|
void SetSourceGames(const std::vector<ObjectSourceGame>& sourceGames);
|
|
|
|
const std::vector<std::string>& GetAuthors() const;
|
|
void SetAuthors(std::vector<std::string>&& authors);
|
|
|
|
const ImageTable& GetImageTable() const
|
|
{
|
|
return _imageTable;
|
|
}
|
|
|
|
ObjectEntryDescriptor GetScgWallsHeader() const;
|
|
ObjectEntryDescriptor GetScgPathXHeader() const;
|
|
rct_object_entry CreateHeader(const char name[9], uint32_t flags, uint32_t checksum);
|
|
|
|
uint32_t GetNumImages() const
|
|
{
|
|
return GetImageTable().GetCount();
|
|
}
|
|
};
|
|
#ifdef __WARN_SUGGEST_FINAL_TYPES__
|
|
# pragma GCC diagnostic pop
|
|
#endif
|
|
|
|
extern int32_t object_entry_group_counts[];
|
|
extern int32_t object_entry_group_encoding[];
|
|
|
|
int32_t object_calculate_checksum(const rct_object_entry* entry, const void* data, size_t dataLength);
|
|
void object_create_identifier_name(char* string_buffer, size_t size, const rct_object_entry* object);
|
|
|
|
const rct_object_entry* object_list_find(rct_object_entry* entry);
|
|
|
|
void object_entry_get_name_fixed(utf8* buffer, size_t bufferSize, const rct_object_entry* entry);
|
|
|
|
void* object_entry_get_chunk(ObjectType objectType, ObjectEntryIndex index);
|
|
const Object* object_entry_get_object(ObjectType objectType, ObjectEntryIndex index);
|