1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-18 04:23:20 +01:00

Reduce use of rct_object_entry

This commit is contained in:
Ted John
2021-04-14 10:36:21 +01:00
parent 23c709c197
commit 6329e8fdfe
20 changed files with 397 additions and 335 deletions

View File

@@ -249,7 +249,6 @@ enum
struct list_item
{
const ObjectRepositoryItem* repositoryItem;
rct_object_entry* entry;
std::unique_ptr<rct_object_filters> filter;
uint8_t* flags;
};
@@ -307,7 +306,6 @@ static void visible_list_refresh(rct_window* w)
list_item currentListItem;
currentListItem.repositoryItem = item;
currentListItem.entry = const_cast<rct_object_entry*>(&item->ObjectEntry);
currentListItem.filter = std::move(filter);
currentListItem.flags = &_objectSelectionFlags[i];
_listItems.push_back(std::move(currentListItem));
@@ -681,7 +679,7 @@ static void window_editor_object_selection_scroll_mousedown(
if (gScreenFlags & SCREEN_FLAGS_TRACK_MANAGER)
{
if (!window_editor_object_selection_select_object(0, INPUT_FLAG_EDITOR_OBJECT_SELECT, listItem->entry))
if (!window_editor_object_selection_select_object(0, INPUT_FLAG_EDITOR_OBJECT_SELECT, listItem->repositoryItem))
return;
// Close any other open windows such as options/colour schemes to prevent a crash.

View File

@@ -380,7 +380,7 @@ static void window_editor_object_selection_select_default_objects()
0,
INPUT_FLAG_EDITOR_OBJECT_SELECT | INPUT_FLAG_EDITOR_OBJECT_1
| INPUT_FLAG_EDITOR_OBJECT_SELECT_OBJECTS_IN_SCENERY_GROUP,
defaultSelectedObject);
ObjectEntryDescriptor(defaultSelectedObject));
}
}
}
@@ -395,7 +395,7 @@ static void SelectDesignerObjects()
0,
INPUT_FLAG_EDITOR_OBJECT_SELECT | INPUT_FLAG_EDITOR_OBJECT_1
| INPUT_FLAG_EDITOR_OBJECT_SELECT_OBJECTS_IN_SCENERY_GROUP,
designerSelectedObject);
ObjectEntryDescriptor(designerSelectedObject));
}
}
}
@@ -596,27 +596,14 @@ bool window_editor_object_selection_select_object(uint8_t isMasterObject, int32_
}
}
bool window_editor_object_selection_select_object(uint8_t isMasterObject, int32_t flags, std::string_view identifier)
bool window_editor_object_selection_select_object(
uint8_t isMasterObject, int32_t flags, const ObjectEntryDescriptor& descriptor)
{
auto& objectRepository = OpenRCT2::GetContext()->GetObjectRepository();
const auto* item = objectRepository.FindObject(identifier);
const auto* item = objectRepository.FindObject(descriptor);
return window_editor_object_selection_select_object(isMasterObject, flags, item);
}
bool window_editor_object_selection_select_object(uint8_t isMasterObject, int32_t flags, const rct_object_entry* entry)
{
const ObjectRepositoryItem* item = object_repository_find_object_by_entry(entry);
return window_editor_object_selection_select_object(isMasterObject, flags, item);
}
bool window_editor_object_selection_select_object(uint8_t isMasterObject, int32_t flags, const ObjectEntryDescriptor& entry)
{
if (entry.Generation == ObjectGeneration::DAT)
return window_editor_object_selection_select_object(isMasterObject, flags, &entry.Entry);
return window_editor_object_selection_select_object(isMasterObject, flags, entry.Identifier);
}
bool editor_check_object_group_at_least_one_selected(ObjectType checkObjectType)
{
auto numObjects = std::min(object_repository_get_items_count(), _objectSelectionFlags.size());

View File

@@ -34,8 +34,6 @@ void sub_6AB211();
void reset_selected_object_count_and_size();
void finish_object_selection();
bool window_editor_object_selection_select_object(uint8_t isMasterObject, int32_t flags, const ObjectRepositoryItem* item);
bool window_editor_object_selection_select_object(uint8_t isMasterObject, int32_t flags, std::string_view identifier);
bool window_editor_object_selection_select_object(uint8_t isMasterObject, int32_t flags, const rct_object_entry* entry);
bool window_editor_object_selection_select_object(uint8_t isMasterObject, int32_t flags, const ObjectEntryDescriptor& entry);
/**

View File

@@ -627,6 +627,50 @@ template<> struct DataSerializerTraits_t<rct_object_entry>
}
};
template<> struct DataSerializerTraits_t<ObjectEntryDescriptor>
{
static void encode(OpenRCT2::IStream* stream, const ObjectEntryDescriptor& val)
{
stream->WriteValue<uint8_t>(static_cast<uint8_t>(val.Generation));
if (val.Generation == ObjectGeneration::DAT)
{
DataSerializerTraits<rct_object_entry> s;
s.encode(stream, val.Entry);
}
else
{
stream->WriteValue<uint8_t>(static_cast<uint8_t>(val.GetType()));
stream->WriteString(val.Identifier);
}
}
static void decode(OpenRCT2::IStream* stream, ObjectEntryDescriptor& val)
{
auto generation = static_cast<ObjectGeneration>(stream->ReadValue<uint8_t>());
if (generation == ObjectGeneration::DAT)
{
DataSerializerTraits<rct_object_entry> s;
rct_object_entry entry;
s.decode(stream, entry);
val = ObjectEntryDescriptor(entry);
}
else
{
auto type = static_cast<ObjectType>(stream->ReadValue<uint8_t>());
auto identifier = stream->ReadStdString();
val = ObjectEntryDescriptor(type, identifier);
}
}
static void log(OpenRCT2::IStream* stream, const ObjectEntryDescriptor& val)
{
auto identifier = std::string(val.GetName());
char msg[128] = {};
snprintf(msg, sizeof(msg), "ObjectEntryDescriptor[%s]", identifier.c_str());
stream->Write(msg, strlen(msg));
}
};
template<> struct DataSerializerTraits_t<TrackDesignTrackElement>
{
static void encode(OpenRCT2::IStream* stream, const TrackDesignTrackElement& val)
@@ -706,7 +750,7 @@ template<> struct DataSerializerTraits_t<TrackDesignSceneryElement>
stream->Write(&val.flags);
stream->Write(&val.primary_colour);
stream->Write(&val.secondary_colour);
DataSerializerTraits<rct_object_entry> s;
DataSerializerTraits<ObjectEntryDescriptor> s;
s.encode(stream, val.scenery_object);
}
static void decode(OpenRCT2::IStream* stream, TrackDesignSceneryElement& val)
@@ -717,7 +761,7 @@ template<> struct DataSerializerTraits_t<TrackDesignSceneryElement>
stream->Read(&val.flags);
stream->Read(&val.primary_colour);
stream->Read(&val.secondary_colour);
DataSerializerTraits<rct_object_entry> s;
DataSerializerTraits<ObjectEntryDescriptor> s;
s.decode(stream, val.scenery_object);
}
static void log(OpenRCT2::IStream* stream, const TrackDesignSceneryElement& val)
@@ -727,7 +771,9 @@ template<> struct DataSerializerTraits_t<TrackDesignSceneryElement>
msg, sizeof(msg), "TrackDesignSceneryElement(x = %d, y = %d, z = %d, flags = %d, colour1 = %d, colour2 = %d)",
val.x, val.y, val.z, val.flags, val.primary_colour, val.secondary_colour);
stream->Write(msg, strlen(msg));
stream->WriteArray(val.scenery_object.name, 8);
auto identifier = val.scenery_object.GetName();
stream->WriteArray(identifier.data(), identifier.size());
}
};
@@ -750,46 +796,3 @@ template<> struct DataSerializerTraits_t<rct_vehicle_colour>
stream->Write(msg, strlen(msg));
}
};
template<> struct DataSerializerTraits_t<ObjectEntryDescriptor>
{
static void encode(OpenRCT2::IStream* stream, const ObjectEntryDescriptor& val)
{
stream->Write(&val.Generation);
if (val.Generation == ObjectGeneration::DAT)
{
DataSerializerTraits<rct_object_entry> s;
s.encode(stream, val.Entry);
}
else
{
DataSerializerTraits<std::string> s;
s.encode(stream, val.Identifier);
}
}
static void decode(OpenRCT2::IStream* stream, ObjectEntryDescriptor& val)
{
ObjectGeneration generation;
stream->Read(&generation);
if (generation == ObjectGeneration::DAT)
{
rct_object_entry obj;
DataSerializerTraits<rct_object_entry> s;
s.decode(stream, obj);
val = ObjectEntryDescriptor(obj);
}
else
{
std::string id;
DataSerializerTraits<std::string> s;
s.decode(stream, id);
val = ObjectEntryDescriptor(id);
}
}
static void log(OpenRCT2::IStream* stream, const ObjectEntryDescriptor& val)
{
char msg[128] = {};
snprintf(msg, sizeof(msg), "ObjectEntryDescriptor (Generation = %d)", static_cast<int32_t>(val.Generation));
stream->Write(msg, strlen(msg));
}
};

View File

@@ -12,9 +12,6 @@
#include "../object/Object.h"
#include "Memory.hpp"
#include "String.hpp"
#include <vector>
namespace OpenRCT2
{
utf8* IStream::ReadString()
@@ -57,6 +54,17 @@ namespace OpenRCT2
}
}
void IStream::WriteString(std::string_view str)
{
for (auto c : str)
{
if (c == '\0')
break;
WriteValue<uint8_t>(c);
}
WriteValue<uint8_t>(0);
}
void IStream::WriteString(const std::string& str)
{
WriteString(str.c_str());

View File

@@ -17,6 +17,7 @@
#include <memory>
#include <stdexcept>
#include <string>
#include <string_view>
#include <vector>
#ifdef __WARN_SUGGEST_FINAL_METHODS__
@@ -207,6 +208,7 @@ namespace OpenRCT2
utf8* ReadString();
std::string ReadStdString();
void WriteString(const utf8* str);
void WriteString(std::string_view string);
void WriteString(const std::string& string);
};

View File

@@ -15,6 +15,7 @@
#include <cstddef>
#include <optional>
#include <string>
#include <string_view>
#include <vector>
namespace CODE_PAGE

View File

@@ -90,7 +90,6 @@ struct rct_window
uint32_t highlighted_item;
uint16_t ride_colour;
ResearchItem* research_item;
rct_object_entry* object_entry;
const scenario_index_entry* highlighted_scenario;
uint16_t var_496;
};

View File

@@ -35,7 +35,7 @@ ObjectType& operator++(ObjectType& d, int)
ObjectEntryDescriptor::ObjectEntryDescriptor(const rct_object_entry& newEntry)
{
if (!object_entry_is_empty(&newEntry))
if (!newEntry.IsEmpty())
{
Generation = ObjectGeneration::DAT;
Entry = newEntry;
@@ -48,6 +48,13 @@ ObjectEntryDescriptor::ObjectEntryDescriptor(std::string_view newIdentifier)
Identifier = std::string(newIdentifier);
}
ObjectEntryDescriptor::ObjectEntryDescriptor(ObjectType type, std::string_view newIdentifier)
{
Generation = ObjectGeneration::JSON;
Identifier = std::string(newIdentifier);
Type = type;
}
ObjectEntryDescriptor::ObjectEntryDescriptor(const ObjectRepositoryItem& ori)
{
if (!ori.Identifier.empty())
@@ -77,8 +84,28 @@ std::string_view ObjectEntryDescriptor::GetName() const
return Generation == ObjectGeneration::JSON ? Identifier : Entry.GetName();
}
bool ObjectEntryDescriptor::operator==(const ObjectEntryDescriptor& rhs) const
{
if (Generation != rhs.Generation)
return false;
if (Generation == ObjectGeneration::DAT)
{
return Entry == rhs.Entry;
}
else
{
return Type == rhs.Type && Identifier == rhs.Identifier;
}
}
bool ObjectEntryDescriptor::operator!=(const ObjectEntryDescriptor& rhs) const
{
return !(*this == rhs);
}
Object::Object(const rct_object_entry& entry)
{
_type = entry.GetType();
_objectEntry = entry;
}
@@ -215,6 +242,61 @@ std::optional<uint8_t> rct_object_entry::GetSceneryType() const
}
}
bool rct_object_entry::IsEmpty() const
{
uint64_t a, b;
std::memcpy(&a, reinterpret_cast<const uint8_t*>(this), 8);
std::memcpy(&b, reinterpret_cast<const uint8_t*>(this) + 8, 8);
if (a == 0xFFFFFFFFFFFFFFFF && b == 0xFFFFFFFFFFFFFFFF)
return true;
if (a == 0 && b == 0)
return true;
return false;
}
bool rct_object_entry::operator==(const rct_object_entry& rhs) const
{
const auto a = this;
const auto b = &rhs;
// If an official object don't bother checking checksum
if ((a->flags & 0xF0) || (b->flags & 0xF0))
{
if (a->GetType() != b->GetType())
{
return false;
}
int32_t match = memcmp(a->name, b->name, 8);
if (match)
{
return false;
}
}
else
{
if (a->flags != b->flags)
{
return false;
}
int32_t match = memcmp(a->name, b->name, 8);
if (match)
{
return false;
}
if (a->checksum != b->checksum)
{
return false;
}
}
return true;
}
bool rct_object_entry::operator!=(const rct_object_entry& rhs) const
{
return !(*this == rhs);
}
/**
* Couples a zip archive and a zip item stream to ensure the lifetime of the zip archive is maintained
* for the lifetime of the stream.

View File

@@ -123,6 +123,10 @@ struct rct_object_entry
{
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);
@@ -173,10 +177,14 @@ struct ObjectEntryDescriptor
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;
@@ -243,13 +251,14 @@ struct IReadObjectContext
class Object
{
private:
ObjectType _type = ObjectType::None;
std::string _identifier;
rct_object_entry _objectEntry{};
StringTable _stringTable;
ImageTable _imageTable;
std::vector<ObjectSourceGame> _sourceGames;
std::vector<std::string> _authors;
bool _isJsonObject{};
ObjectGeneration _generation{};
protected:
StringTable& GetStringTable()
@@ -294,20 +303,29 @@ public:
void MarkAsJsonObject()
{
_isJsonObject = true;
_generation = ObjectGeneration::JSON;
}
bool IsJsonObject() const
ObjectGeneration GetGeneration() const
{
return _isJsonObject;
return _generation;
};
ObjectType GetObjectType() const
{
return _type;
}
ObjectEntryDescriptor GetDescriptor() const
{
if (_isJsonObject)
return ObjectEntryDescriptor(_identifier);
else
if (_generation == ObjectGeneration::DAT)
{
return ObjectEntryDescriptor(_objectEntry);
}
else
{
return ObjectEntryDescriptor(_type, _identifier);
}
}
// Legacy data structures
@@ -315,9 +333,9 @@ public:
{
return _objectEntry.GetName();
}
const rct_object_entry* GetObjectEntry() const
const rct_object_entry& GetObjectEntry() const
{
return &_objectEntry;
return _objectEntry;
}
virtual void* GetLegacyData();
@@ -335,10 +353,6 @@ public:
{
}
virtual ObjectType GetObjectType() const final
{
return _objectEntry.GetType();
}
virtual std::string GetName() const;
virtual std::string GetName(int32_t language) const;
@@ -372,8 +386,6 @@ public:
extern int32_t object_entry_group_counts[];
extern int32_t object_entry_group_encoding[];
bool object_entry_is_empty(const rct_object_entry* entry);
bool object_entry_compare(const rct_object_entry* a, const rct_object_entry* b);
int32_t object_calculate_checksum(const rct_object_entry* entry, const void* data, size_t dataLength);
bool find_object_in_entry_group(const rct_object_entry* entry, ObjectType* entry_type, ObjectEntryIndex* entryIndex);
void object_create_identifier_name(char* string_buffer, size_t size, const rct_object_entry* object);

View File

@@ -174,19 +174,6 @@ void ObjectList::SetObject(ObjectType type, ObjectEntryIndex index, std::string_
SetObject(index, entry);
}
bool object_entry_is_empty(const rct_object_entry* entry)
{
uint64_t a, b;
std::memcpy(&a, reinterpret_cast<const uint8_t*>(entry), 8);
std::memcpy(&b, reinterpret_cast<const uint8_t*>(entry) + 8, 8);
if (a == 0xFFFFFFFFFFFFFFFF && b == 0xFFFFFFFFFFFFFFFF)
return true;
if (a == 0 && b == 0)
return true;
return false;
}
/**
*
* rct2: 0x006AB344
@@ -218,7 +205,7 @@ bool find_object_in_entry_group(const rct_object_entry* entry, ObjectType* entry
if (loadedObj != nullptr)
{
auto thisEntry = object_entry_get_object(objectType, i)->GetObjectEntry();
if (object_entry_compare(thisEntry, entry))
if (thisEntry == *entry)
{
*entry_type = objectType;
*entryIndex = i;
@@ -251,20 +238,6 @@ void get_type_entry_index(size_t index, ObjectType* outObjectType, ObjectEntryIn
*outEntryIndex = static_cast<ObjectEntryIndex>(index);
}
const rct_object_entry* get_loaded_object_entry(size_t index)
{
ObjectType objectType;
ObjectEntryIndex entryIndex;
get_type_entry_index(index, &objectType, &entryIndex);
auto obj = object_entry_get_object(objectType, entryIndex);
if (obj == nullptr)
{
return nullptr;
}
return obj->GetObjectEntry();
}
void* get_loaded_object_chunk(size_t index)
{
ObjectType objectType;

View File

@@ -56,5 +56,4 @@ public:
};
void get_type_entry_index(size_t index, ObjectType* outObjectType, ObjectEntryIndex* outEntryIndex);
const rct_object_entry* get_loaded_object_entry(size_t index);
void* get_loaded_object_chunk(size_t index);

View File

@@ -123,17 +123,7 @@ public:
auto obj = GetLoadedObject(objectType, i);
if (obj != nullptr)
{
if (obj->IsJsonObject())
{
auto entry = ObjectEntryDescriptor(obj->GetIdentifier());
entry.Type = obj->GetObjectType();
objectList.SetObject(i, entry);
}
else
{
auto entry = ObjectEntryDescriptor(*obj->GetObjectEntry());
objectList.SetObject(i, entry);
}
objectList.SetObject(i, obj->GetDescriptor());
}
}
}
@@ -374,7 +364,7 @@ private:
object->Unload();
// TODO try to prevent doing a repository search
const ObjectRepositoryItem* ori = _objectRepository.FindObject(object->GetObjectEntry());
const auto* ori = _objectRepository.FindObject(object->GetDescriptor());
if (ori != nullptr)
{
_objectRepository.UnregisterLoadedObject(ori, object);

View File

@@ -76,7 +76,7 @@ class ObjectFileIndex final : public FileIndex<ObjectRepositoryItem>
{
private:
static constexpr uint32_t MAGIC_NUMBER = 0x5844494F; // OIDX
static constexpr uint16_t VERSION = 27;
static constexpr uint16_t VERSION = 28;
static constexpr auto PATTERN = "*.dat;*.pob;*.json;*.parkobj";
IObjectRepository& _objectRepository;
@@ -113,8 +113,10 @@ public:
if (object != nullptr)
{
ObjectRepositoryItem item = {};
item.Type = object->GetObjectType();
item.Generation = object->GetGeneration();
item.Identifier = object->GetIdentifier();
item.ObjectEntry = *object->GetObjectEntry();
item.ObjectEntry = object->GetObjectEntry();
item.Path = path;
item.Name = object->GetName();
item.Authors = object->GetAuthors();
@@ -622,7 +624,7 @@ private:
// Read object data from file
auto fs = OpenRCT2::FileStream(item->Path, OpenRCT2::FILE_MODE_OPEN);
auto fileEntry = fs.ReadValue<rct_object_entry>();
if (!object_entry_compare(entry, &fileEntry))
if (*entry != fileEntry)
{
throw std::runtime_error("Header found in object file does not match object to pack.");
}
@@ -733,40 +735,6 @@ const ObjectRepositoryItem* object_repository_find_object_by_name(const char* na
return objectRepository.FindObjectLegacy(name);
}
bool object_entry_compare(const rct_object_entry* a, const rct_object_entry* b)
{
// If an official object don't bother checking checksum
if ((a->flags & 0xF0) || (b->flags & 0xF0))
{
if (a->GetType() != b->GetType())
{
return false;
}
int32_t match = memcmp(a->name, b->name, 8);
if (match)
{
return false;
}
}
else
{
if (a->flags != b->flags)
{
return false;
}
int32_t match = memcmp(a->name, b->name, 8);
if (match)
{
return false;
}
if (a->checksum != b->checksum)
{
return false;
}
}
return true;
}
int32_t object_calculate_checksum(const rct_object_entry* entry, const void* data, size_t dataLength)
{
const uint8_t* entryBytePtr = reinterpret_cast<const uint8_t*>(entry);

View File

@@ -37,6 +37,8 @@ struct rct_drawpixelinfo;
struct ObjectRepositoryItem
{
size_t Id;
ObjectType Type;
ObjectGeneration Generation;
std::string Identifier; // e.g. rct2.c3d
rct_object_entry ObjectEntry;
std::string Path;

View File

@@ -123,7 +123,7 @@ bool T6Exporter::SaveTrack(OpenRCT2::IStream* stream)
for (const auto& sceneryElement : _trackDesign->scenery_elements)
{
tempStream.Write(&sceneryElement.scenery_object, sizeof(rct_object_entry));
tempStream.Write(&sceneryElement.scenery_object.Entry, sizeof(rct_object_entry));
tempStream.WriteValue<int8_t>(sceneryElement.x);
tempStream.WriteValue<int8_t>(sceneryElement.y);
tempStream.WriteValue<int8_t>(sceneryElement.z);

View File

@@ -202,7 +202,7 @@ public:
rct_td6_scenery_element t6SceneryElement{};
_stream.Read(&t6SceneryElement, sizeof(rct_td6_scenery_element));
TrackDesignSceneryElement sceneryElement{};
sceneryElement.scenery_object = t6SceneryElement.scenery_object;
sceneryElement.scenery_object = ObjectEntryDescriptor(t6SceneryElement.scenery_object);
sceneryElement.x = t6SceneryElement.x;
sceneryElement.y = t6SceneryElement.y;
sceneryElement.z = t6SceneryElement.z;

View File

@@ -90,11 +90,18 @@ static void track_design_preview_clear_map();
rct_string_id TrackDesign::CreateTrackDesign(const Ride& ride)
{
type = ride.type;
auto object = object_entry_get_object(ObjectType::Ride, ride.subtype);
// Note we are only copying rct_object_entry in size and
// not the extended as we don't need the chunk size.
vehicle_object = ObjectEntryDescriptor(*object->GetObjectEntry());
auto object = object_entry_get_object(ObjectType::Ride, ride.subtype);
if (object != nullptr)
{
auto entry = object->GetObjectEntry();
if (entry.IsEmpty())
{
// TODO create a new error message for `JSON objects are unsupported`
return STR_UNKNOWN_OBJECT_TYPE;
}
vehicle_object = ObjectEntryDescriptor(entry);
}
ride_mode = ride.mode;
colour_scheme = ride.colour_scheme_type & 3;
@@ -627,17 +634,22 @@ std::unique_ptr<TrackDesign> track_design_open(const utf8* path)
*/
static void track_design_load_scenery_objects(TrackDesign* td6)
{
object_manager_unload_all_objects();
auto& objectManager = OpenRCT2::GetContext()->GetObjectManager();
objectManager.UnloadAll();
// Load ride object
rct_object_entry* rideEntry = &td6->vehicle_object.Entry;
object_manager_load_object(rideEntry);
if (td6->vehicle_object.HasValue())
{
objectManager.LoadObject(td6->vehicle_object);
}
// Load scenery objects
for (const auto& scenery : td6->scenery_elements)
{
const rct_object_entry* sceneryEntry = &scenery.scenery_object;
object_manager_load_object(sceneryEntry);
if (scenery.scenery_object.HasValue())
{
objectManager.LoadObject(td6->vehicle_object);
}
}
}
@@ -647,28 +659,20 @@ static void track_design_load_scenery_objects(TrackDesign* td6)
*/
static void track_design_mirror_scenery(TrackDesign* td6)
{
auto& objectMgr = OpenRCT2::GetContext()->GetObjectManager();
for (auto& scenery : td6->scenery_elements)
{
ObjectType entry_type{ 0 };
ObjectEntryIndex entryIndex{ 0 };
if (!find_object_in_entry_group(&scenery.scenery_object, &entry_type, &entryIndex))
{
entry_type = scenery.scenery_object.GetType();
if (entry_type != ObjectType::Paths)
{
continue;
}
auto obj = objectMgr.GetLoadedObject(scenery.scenery_object);
if (obj == nullptr)
continue;
entryIndex = 0;
}
rct_scenery_entry* scenery_entry = static_cast<rct_scenery_entry*>(object_entry_get_chunk(entry_type, entryIndex));
switch (entry_type)
switch (obj->GetObjectType())
{
case ObjectType::LargeScenery:
{
auto sceneryEntry = reinterpret_cast<const rct_scenery_entry*>(obj->GetLegacyData());
int16_t x1 = 0, x2 = 0, y1 = 0, y2 = 0;
for (rct_large_scenery_tile* tile = scenery_entry->large_scenery.tiles; tile->x_offset != -1; tile++)
for (rct_large_scenery_tile* tile = sceneryEntry->large_scenery.tiles; tile->x_offset != -1; tile++)
{
if (x1 > tile->x_offset)
{
@@ -711,12 +715,13 @@ static void track_design_mirror_scenery(TrackDesign* td6)
}
case ObjectType::SmallScenery:
{
auto sceneryEntry = reinterpret_cast<const rct_scenery_entry*>(obj->GetLegacyData());
scenery.y = -scenery.y;
if (scenery_small_entry_has_flag(scenery_entry, SMALL_SCENERY_FLAG_DIAGONAL))
if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_DIAGONAL))
{
scenery.flags ^= (1 << 0);
if (!scenery_small_entry_has_flag(scenery_entry, SMALL_SCENERY_FLAG_FULL_TILE))
if (!scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_FULL_TILE))
{
scenery.flags ^= (1 << 2);
}
@@ -755,7 +760,6 @@ static void track_design_mirror_scenery(TrackDesign* td6)
break;
}
default:
// This switch processes only ObjectType for Scenery items.
break;
}
}
@@ -854,7 +858,14 @@ static void track_design_update_max_min_coordinates(const CoordsXYZ& coords)
static bool TrackDesignPlaceSceneryElementGetEntry(
ObjectType& entry_type, ObjectEntryIndex& entry_index, const TrackDesignSceneryElement& scenery)
{
if (!find_object_in_entry_group(&scenery.scenery_object, &entry_type, &entry_index))
auto& objectMgr = OpenRCT2::GetContext()->GetObjectManager();
auto obj = objectMgr.GetLoadedObject(scenery.scenery_object);
if (obj != nullptr)
{
entry_type = obj->GetObjectType();
entry_index = objectMgr.GetLoadedObjectEntryIndex(obj);
}
else
{
entry_type = scenery.scenery_object.GetType();
if (entry_type != ObjectType::Paths)

View File

@@ -30,16 +30,15 @@ struct TrackDesignEntranceElement
bool isExit;
};
/* Track Scenery entry size: 0x16 */
struct TrackDesignSceneryElement
{
rct_object_entry scenery_object; // 0x00
int8_t x; // 0x10
int8_t y; // 0x11
int8_t z; // 0x12
uint8_t flags; // 0x13 direction quadrant tertiary colour
uint8_t primary_colour; // 0x14
uint8_t secondary_colour; // 0x15
ObjectEntryDescriptor scenery_object;
int8_t x;
int8_t y;
int8_t z;
uint8_t flags;
uint8_t primary_colour;
uint8_t secondary_colour;
};
/**

View File

@@ -14,7 +14,9 @@
#include "../interface/Viewport.h"
#include "../localisation/Localisation.h"
#include "../localisation/StringIds.h"
#include "../object/LargeSceneryObject.h"
#include "../object/ObjectList.h"
#include "../object/ObjectManager.h"
#include "../util/SawyerCoding.h"
#include "../util/Util.h"
#include "../windows/Intent.h"
@@ -188,16 +190,29 @@ static void track_design_save_push_tile_element(const CoordsXY& loc, TileElement
}
}
static bool track_design_is_supported_object(const Object* obj)
{
const auto& entry = obj->GetObjectEntry();
return !entry.IsEmpty();
}
/**
*
* rct2: 0x006D2FA7
*/
static void track_design_save_push_tile_element_desc(
const rct_object_entry* entry, const CoordsXYZ& loc, uint8_t flags, uint8_t primaryColour, uint8_t secondaryColour)
const Object* obj, const CoordsXYZ& loc, uint8_t flags, uint8_t primaryColour, uint8_t secondaryColour)
{
const auto& entry = obj->GetObjectEntry();
if (entry.IsEmpty())
{
// Unsupported, should have been blocked earlier
assert(false);
}
auto tileLoc = TileCoordsXYZ(loc);
TrackDesignSceneryElement item{};
item.scenery_object = *entry;
item.scenery_object = ObjectEntryDescriptor(entry);
item.x = tileLoc.x;
item.y = tileLoc.y;
item.z = tileLoc.z;
@@ -210,105 +225,112 @@ static void track_design_save_push_tile_element_desc(
static void track_design_save_add_scenery(const CoordsXY& loc, SmallSceneryElement* sceneryElement)
{
int32_t entryType = sceneryElement->GetEntryIndex();
auto entry = object_entry_get_object(ObjectType::SmallScenery, entryType);
auto entryIndex = sceneryElement->GetEntryIndex();
auto obj = object_entry_get_object(ObjectType::SmallScenery, entryIndex);
if (obj != nullptr && track_design_is_supported_object(obj))
{
uint8_t flags = 0;
flags |= sceneryElement->GetDirection();
flags |= sceneryElement->GetSceneryQuadrant() << 2;
uint8_t flags = 0;
flags |= sceneryElement->GetDirection();
flags |= sceneryElement->GetSceneryQuadrant() << 2;
uint8_t primaryColour = sceneryElement->GetPrimaryColour();
uint8_t secondaryColour = sceneryElement->GetSecondaryColour();
uint8_t primaryColour = sceneryElement->GetPrimaryColour();
uint8_t secondaryColour = sceneryElement->GetSecondaryColour();
track_design_save_push_tile_element(loc, reinterpret_cast<TileElement*>(sceneryElement));
track_design_save_push_tile_element_desc(
entry->GetObjectEntry(), { loc.x, loc.y, sceneryElement->GetBaseZ() }, flags, primaryColour, secondaryColour);
track_design_save_push_tile_element(loc, reinterpret_cast<TileElement*>(sceneryElement));
track_design_save_push_tile_element_desc(
obj, { loc.x, loc.y, sceneryElement->GetBaseZ() }, flags, primaryColour, secondaryColour);
}
}
static void track_design_save_add_large_scenery(const CoordsXY& loc, LargeSceneryElement* tileElement)
{
rct_large_scenery_tile *sceneryTiles, *tile;
int32_t direction, sequence;
if (tileElement == nullptr)
{
log_warning("Null tile element");
return;
}
int32_t entryType = tileElement->GetEntryIndex();
auto entry = object_entry_get_object(ObjectType::LargeScenery, entryType);
sceneryTiles = get_large_scenery_entry(entryType)->large_scenery.tiles;
int32_t z = tileElement->base_height;
direction = tileElement->GetDirection();
sequence = tileElement->GetSequenceIndex();
auto sceneryOrigin = map_large_scenery_get_origin(
{ loc.x, loc.y, z << 3, static_cast<Direction>(direction) }, sequence, nullptr);
if (!sceneryOrigin)
auto entryIndex = tileElement->GetEntryIndex();
auto& objectMgr = OpenRCT2::GetContext()->GetObjectManager();
auto obj = objectMgr.GetLoadedObject(ObjectType::LargeScenery, entryIndex);
if (obj != nullptr && track_design_is_supported_object(obj))
{
return;
}
auto legacyData = reinterpret_cast<const rct_scenery_entry*>(obj->GetLegacyData());
auto sceneryTiles = legacyData->large_scenery.tiles;
// Iterate through each tile of the large scenery element
sequence = 0;
for (tile = sceneryTiles; tile->x_offset != -1; tile++, sequence++)
{
CoordsXY offsetPos{ tile->x_offset, tile->y_offset };
auto rotatedOffsetPos = offsetPos.Rotate(direction);
int32_t z = tileElement->base_height;
auto direction = tileElement->GetDirection();
auto sequence = tileElement->GetSequenceIndex();
CoordsXYZ tileLoc = { sceneryOrigin->x + rotatedOffsetPos.x, sceneryOrigin->y + rotatedOffsetPos.y,
sceneryOrigin->z + tile->z_offset };
auto largeElement = map_get_large_scenery_segment({ tileLoc, static_cast<Direction>(direction) }, sequence);
if (largeElement != nullptr)
auto sceneryOrigin = map_large_scenery_get_origin(
{ loc.x, loc.y, z << 3, static_cast<Direction>(direction) }, sequence, nullptr);
if (!sceneryOrigin)
{
if (sequence == 0)
{
uint8_t flags = largeElement->GetDirection();
uint8_t primaryColour = largeElement->GetPrimaryColour();
uint8_t secondaryColour = largeElement->GetSecondaryColour();
return;
}
track_design_save_push_tile_element_desc(
entry->GetObjectEntry(), tileLoc, flags, primaryColour, secondaryColour);
// Iterate through each tile of the large scenery element
sequence = 0;
for (auto tile = sceneryTiles; tile->x_offset != -1; tile++, sequence++)
{
CoordsXY offsetPos{ tile->x_offset, tile->y_offset };
auto rotatedOffsetPos = offsetPos.Rotate(direction);
CoordsXYZ tileLoc = { sceneryOrigin->x + rotatedOffsetPos.x, sceneryOrigin->y + rotatedOffsetPos.y,
sceneryOrigin->z + tile->z_offset };
auto largeElement = map_get_large_scenery_segment({ tileLoc, static_cast<Direction>(direction) }, sequence);
if (largeElement != nullptr)
{
if (sequence == 0)
{
uint8_t flags = largeElement->GetDirection();
uint8_t primaryColour = largeElement->GetPrimaryColour();
uint8_t secondaryColour = largeElement->GetSecondaryColour();
track_design_save_push_tile_element_desc(obj, tileLoc, flags, primaryColour, secondaryColour);
}
track_design_save_push_tile_element({ tileLoc.x, tileLoc.y }, reinterpret_cast<TileElement*>(largeElement));
}
track_design_save_push_tile_element({ tileLoc.x, tileLoc.y }, reinterpret_cast<TileElement*>(largeElement));
}
}
}
static void track_design_save_add_wall(const CoordsXY& loc, WallElement* wallElement)
{
int32_t entryType = wallElement->GetEntryIndex();
auto entry = object_entry_get_object(ObjectType::Walls, entryType);
auto entryIndex = wallElement->GetEntryIndex();
auto obj = object_entry_get_object(ObjectType::Walls, entryIndex);
if (obj != nullptr && track_design_is_supported_object(obj))
{
uint8_t flags = 0;
flags |= wallElement->GetDirection();
flags |= wallElement->GetTertiaryColour() << 2;
uint8_t flags = 0;
flags |= wallElement->GetDirection();
flags |= wallElement->GetTertiaryColour() << 2;
uint8_t secondaryColour = wallElement->GetSecondaryColour();
uint8_t primaryColour = wallElement->GetPrimaryColour();
uint8_t secondaryColour = wallElement->GetSecondaryColour();
uint8_t primaryColour = wallElement->GetPrimaryColour();
track_design_save_push_tile_element(loc, reinterpret_cast<TileElement*>(wallElement));
track_design_save_push_tile_element_desc(
entry->GetObjectEntry(), { loc.x, loc.y, wallElement->GetBaseZ() }, flags, primaryColour, secondaryColour);
track_design_save_push_tile_element(loc, reinterpret_cast<TileElement*>(wallElement));
track_design_save_push_tile_element_desc(
obj, { loc.x, loc.y, wallElement->GetBaseZ() }, flags, primaryColour, secondaryColour);
}
}
static void track_design_save_add_footpath(const CoordsXY& loc, PathElement* pathElement)
{
int32_t entryType = pathElement->GetSurfaceEntryIndex();
auto entry = object_entry_get_object(ObjectType::Paths, entryType);
auto entryIndex = pathElement->GetSurfaceEntryIndex();
auto obj = object_entry_get_object(ObjectType::Paths, entryIndex);
if (obj != nullptr && track_design_is_supported_object(obj))
{
uint8_t flags = 0;
flags |= pathElement->GetEdges();
flags |= (pathElement->GetSlopeDirection()) << 5;
if (pathElement->IsSloped())
flags |= 0b00010000;
if (pathElement->IsQueue())
flags |= 1 << 7;
uint8_t flags = 0;
flags |= pathElement->GetEdges();
flags |= (pathElement->GetSlopeDirection()) << 5;
if (pathElement->IsSloped())
flags |= 0b00010000;
if (pathElement->IsQueue())
flags |= 1 << 7;
track_design_save_push_tile_element(loc, reinterpret_cast<TileElement*>(pathElement));
track_design_save_push_tile_element_desc(entry->GetObjectEntry(), { loc.x, loc.y, pathElement->GetBaseZ() }, flags, 0, 0);
track_design_save_push_tile_element(loc, reinterpret_cast<TileElement*>(pathElement));
track_design_save_push_tile_element_desc(obj, { loc.x, loc.y, pathElement->GetBaseZ() }, flags, 0, 0);
}
}
/**
@@ -370,7 +392,7 @@ static void track_design_save_pop_tile_element(const CoordsXY& loc, TileElement*
*
* rct2: 0x006D2FDD
*/
static void track_design_save_pop_tile_element_desc(const rct_object_entry* entry, const CoordsXYZ& loc, uint8_t flags)
static void track_design_save_pop_tile_element_desc(const ObjectEntryDescriptor& entry, const CoordsXYZ& loc, uint8_t flags)
{
size_t removeIndex = SIZE_MAX;
auto tileLoc = TileCoordsXYZ(loc);
@@ -385,7 +407,7 @@ static void track_design_save_pop_tile_element_desc(const rct_object_entry* entr
continue;
if (item->flags != flags)
continue;
if (!object_entry_compare(&item->scenery_object, entry))
if (item->scenery_object != entry)
continue;
removeIndex = i;
@@ -399,93 +421,101 @@ static void track_design_save_pop_tile_element_desc(const rct_object_entry* entr
static void track_design_save_remove_scenery(const CoordsXY& loc, SmallSceneryElement* sceneryElement)
{
int32_t entryType = sceneryElement->GetEntryIndex();
auto entry = object_entry_get_object(ObjectType::SmallScenery, entryType);
auto entryIndex = sceneryElement->GetEntryIndex();
auto obj = object_entry_get_object(ObjectType::SmallScenery, entryIndex);
if (obj != nullptr)
{
uint8_t flags = 0;
flags |= sceneryElement->GetDirection();
flags |= sceneryElement->GetSceneryQuadrant() << 2;
uint8_t flags = 0;
flags |= sceneryElement->GetDirection();
flags |= sceneryElement->GetSceneryQuadrant() << 2;
track_design_save_pop_tile_element(loc, reinterpret_cast<TileElement*>(sceneryElement));
track_design_save_pop_tile_element_desc(entry->GetObjectEntry(), { loc.x, loc.y, sceneryElement->GetBaseZ() }, flags);
track_design_save_pop_tile_element(loc, reinterpret_cast<TileElement*>(sceneryElement));
track_design_save_pop_tile_element_desc(obj->GetDescriptor(), { loc.x, loc.y, sceneryElement->GetBaseZ() }, flags);
}
}
static void track_design_save_remove_large_scenery(const CoordsXY& loc, LargeSceneryElement* tileElement)
{
rct_large_scenery_tile *sceneryTiles, *tile;
int32_t direction, sequence;
if (tileElement == nullptr)
{
log_warning("Null tile element");
return;
}
int32_t entryType = tileElement->GetEntryIndex();
auto entry = object_entry_get_object(ObjectType::LargeScenery, entryType);
sceneryTiles = get_large_scenery_entry(entryType)->large_scenery.tiles;
int32_t z = tileElement->base_height;
direction = tileElement->GetDirection();
sequence = tileElement->GetSequenceIndex();
auto sceneryOrigin = map_large_scenery_get_origin(
{ loc.x, loc.y, z << 3, static_cast<Direction>(direction) }, sequence, nullptr);
if (!sceneryOrigin)
auto entryIndex = tileElement->GetEntryIndex();
auto& objectMgr = OpenRCT2::GetContext()->GetObjectManager();
auto obj = objectMgr.GetLoadedObject(ObjectType::LargeScenery, entryIndex);
if (obj != nullptr)
{
return;
}
auto legacyData = reinterpret_cast<const rct_scenery_entry*>(obj->GetLegacyData());
auto sceneryTiles = legacyData->large_scenery.tiles;
// Iterate through each tile of the large scenery element
sequence = 0;
for (tile = sceneryTiles; tile->x_offset != -1; tile++, sequence++)
{
CoordsXY offsetPos{ tile->x_offset, tile->y_offset };
auto rotatedOffsetPos = offsetPos.Rotate(direction);
int32_t z = tileElement->base_height;
auto direction = tileElement->GetDirection();
auto sequence = tileElement->GetSequenceIndex();
CoordsXYZ tileLoc = { sceneryOrigin->x + rotatedOffsetPos.x, sceneryOrigin->y + rotatedOffsetPos.y,
sceneryOrigin->z + tile->z_offset };
auto largeElement = map_get_large_scenery_segment({ tileLoc, static_cast<Direction>(direction) }, sequence);
if (largeElement != nullptr)
auto sceneryOrigin = map_large_scenery_get_origin(
{ loc.x, loc.y, z << 3, static_cast<Direction>(direction) }, sequence, nullptr);
if (!sceneryOrigin)
{
if (sequence == 0)
return;
}
// Iterate through each tile of the large scenery element
sequence = 0;
for (auto tile = sceneryTiles; tile->x_offset != -1; tile++, sequence++)
{
CoordsXY offsetPos{ tile->x_offset, tile->y_offset };
auto rotatedOffsetPos = offsetPos.Rotate(direction);
CoordsXYZ tileLoc = { sceneryOrigin->x + rotatedOffsetPos.x, sceneryOrigin->y + rotatedOffsetPos.y,
sceneryOrigin->z + tile->z_offset };
auto largeElement = map_get_large_scenery_segment({ tileLoc, static_cast<Direction>(direction) }, sequence);
if (largeElement != nullptr)
{
uint8_t flags = largeElement->GetDirection();
track_design_save_pop_tile_element_desc(entry->GetObjectEntry(), tileLoc, flags);
if (sequence == 0)
{
uint8_t flags = largeElement->GetDirection();
track_design_save_pop_tile_element_desc(obj->GetDescriptor(), tileLoc, flags);
}
track_design_save_pop_tile_element({ tileLoc.x, tileLoc.y }, reinterpret_cast<TileElement*>(largeElement));
}
track_design_save_pop_tile_element({ tileLoc.x, tileLoc.y }, reinterpret_cast<TileElement*>(largeElement));
}
}
}
static void track_design_save_remove_wall(const CoordsXY& loc, WallElement* wallElement)
{
int32_t entryType = wallElement->GetEntryIndex();
auto entry = object_entry_get_object(ObjectType::Walls, entryType);
auto entryIndex = wallElement->GetEntryIndex();
auto obj = object_entry_get_object(ObjectType::Walls, entryIndex);
if (obj != nullptr)
{
uint8_t flags = 0;
flags |= wallElement->GetDirection();
flags |= wallElement->GetTertiaryColour() << 2;
uint8_t flags = 0;
flags |= wallElement->GetDirection();
flags |= wallElement->GetTertiaryColour() << 2;
track_design_save_pop_tile_element(loc, reinterpret_cast<TileElement*>(wallElement));
track_design_save_pop_tile_element_desc(entry->GetObjectEntry(), { loc.x, loc.y, wallElement->GetBaseZ() }, flags);
track_design_save_pop_tile_element(loc, reinterpret_cast<TileElement*>(wallElement));
track_design_save_pop_tile_element_desc(obj->GetDescriptor(), { loc.x, loc.y, wallElement->GetBaseZ() }, flags);
}
}
static void track_design_save_remove_footpath(const CoordsXY& loc, PathElement* pathElement)
{
int32_t entryType = pathElement->GetSurfaceEntryIndex();
auto entry = object_entry_get_object(ObjectType::Paths, entryType);
auto entryIndex = pathElement->GetSurfaceEntryIndex();
auto obj = object_entry_get_object(ObjectType::Paths, entryIndex);
if (obj != nullptr)
{
uint8_t flags = 0;
flags |= pathElement->GetEdges();
if (pathElement->IsSloped())
flags |= (1 << 4);
flags |= (pathElement->GetSlopeDirection()) << 5;
if (pathElement->IsQueue())
flags |= (1 << 7);
uint8_t flags = 0;
flags |= pathElement->GetEdges();
if (pathElement->IsSloped())
flags |= (1 << 4);
flags |= (pathElement->GetSlopeDirection()) << 5;
if (pathElement->IsQueue())
flags |= (1 << 7);
track_design_save_pop_tile_element(loc, reinterpret_cast<TileElement*>(pathElement));
track_design_save_pop_tile_element_desc(entry->GetObjectEntry(), { loc.x, loc.y, pathElement->GetBaseZ() }, flags);
track_design_save_pop_tile_element(loc, reinterpret_cast<TileElement*>(pathElement));
track_design_save_pop_tile_element_desc(obj->GetDescriptor(), { loc.x, loc.y, pathElement->GetBaseZ() }, flags);
}
}
/**