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:
@@ -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.
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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);
|
||||
|
||||
/**
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <cstddef>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
namespace CODE_PAGE
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user