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

Implement handling of new object types

This commit is contained in:
Ted John
2021-04-01 01:13:31 +01:00
parent 638bbebe59
commit fce02c21c3
14 changed files with 380 additions and 227 deletions

View File

@@ -107,7 +107,7 @@ static constexpr const ObjectPageDesc ObjectSelectionPages[] = {
{ STR_OBJECT_SELECTION_TERRAIN_SURFACES, SPR_G2_TAB_LAND, false },
{ STR_OBJECT_SELECTION_TERRAIN_EDGES, SPR_G2_TAB_LAND, false },
{ STR_OBJECT_SELECTION_STATIONS, SPR_TAB_PARK, false },
// { STR_OBJECT_SELECTION_MUSIC, SPR_TAB_MUSIC_0, false },
{ STR_OBJECT_SELECTION_MUSIC, SPR_TAB_MUSIC_0, false },
};
#pragma region Widgets

View File

@@ -70,7 +70,6 @@ namespace Editor
// Reset loaded objects to just defaults
auto& objectManager = context->GetObjectManager();
objectManager.UnloadAll();
objectManager.LoadDefaultObjects();
}
/**

View File

@@ -87,7 +87,7 @@ namespace OpenRCT2
class ParkFile
{
public:
std::vector<ObjectEntryDescriptor> RequiredObjects;
ObjectList RequiredObjects;
private:
std::unique_ptr<OrcaStream> _os;
@@ -96,7 +96,7 @@ namespace OpenRCT2
void Load(const std::string_view& path)
{
_os = std::make_unique<OrcaStream>(path, OrcaStream::Mode::READING);
RequiredObjects.clear();
RequiredObjects = {};
ReadWriteObjectsChunk(*_os);
}
@@ -174,59 +174,76 @@ namespace OpenRCT2
if (os.GetMode() == OrcaStream::Mode::READING)
{
std::vector<ObjectEntryDescriptor> requiredObjects;
ObjectList requiredObjects;
os.ReadWriteChunk(ParkFileChunkType::OBJECTS, [&requiredObjects](OrcaStream::ChunkStream& cs) {
cs.ReadWriteVector(requiredObjects, [&cs](ObjectEntryDescriptor& objectDesc) {
auto kind = cs.Read<uint8_t>();
switch (kind)
auto numSubLists = cs.Read<uint16_t>();
for (size_t i = 0; i < numSubLists; i++)
{
auto objectType = static_cast<ObjectType>(cs.Read<uint16_t>());
auto subListSize = static_cast<ObjectEntryIndex>(cs.Read<uint32_t>());
for (ObjectEntryIndex j = 0; j < subListSize; j++)
{
case DESCRIPTOR_NONE:
break;
case DESCRIPTOR_DAT:
objectDesc.Entry = cs.Read<rct_object_entry>();
break;
case DESCRIPTOR_JSON:
objectDesc.Type = static_cast<ObjectType>(cs.Read<uint16_t>());
objectDesc.Identifier = cs.Read<std::string>();
objectDesc.Version = cs.Read<std::string>();
break;
default:
throw std::runtime_error("Unknown object descriptor kind.");
auto kind = cs.Read<uint8_t>();
ObjectEntryDescriptor desc;
switch (kind)
{
case DESCRIPTOR_NONE:
break;
case DESCRIPTOR_DAT:
desc.Entry = cs.Read<rct_object_entry>();
requiredObjects.SetObject(j, desc);
break;
case DESCRIPTOR_JSON:
desc.Type = objectType;
desc.Identifier = cs.Read<std::string>();
desc.Version = cs.Read<std::string>();
requiredObjects.SetObject(j, desc);
break;
default:
throw std::runtime_error("Unknown object descriptor kind.");
}
}
});
}
});
RequiredObjects = requiredObjects;
RequiredObjects = std::move(requiredObjects);
}
else
{
std::vector<size_t> objectIds(OBJECT_ENTRY_COUNT);
std::iota(objectIds.begin(), objectIds.end(), 0);
os.ReadWriteChunk(ParkFileChunkType::OBJECTS, [&objectIds](OrcaStream::ChunkStream& cs) {
os.ReadWriteChunk(ParkFileChunkType::OBJECTS, [](OrcaStream::ChunkStream& cs) {
auto& objManager = GetContext()->GetObjectManager();
cs.ReadWriteVector(objectIds, [&cs, &objManager](size_t& i) {
auto obj = objManager.GetLoadedObject(i);
if (obj != nullptr)
auto objectList = objManager.GetLoadedObjects();
// Write number of object sub lists
cs.Write(static_cast<uint16_t>(ObjectType::Count));
for (auto objectType = ObjectType::Ride; objectType < ObjectType::Count; objectType++)
{
// Write sub list
const auto& list = objectList.GetList(objectType);
cs.Write(static_cast<uint16_t>(objectType));
cs.Write(static_cast<uint32_t>(list.size()));
for (const auto& entry : list)
{
if (obj->IsJsonObject())
if (entry.HasValue())
{
cs.Write(DESCRIPTOR_JSON);
cs.Write(static_cast<uint16_t>(obj->GetObjectType()));
cs.Write(obj->GetIdentifier());
cs.Write(""); // reserved for version
if (entry.Generation == ObjectGeneration::JSON)
{
cs.Write(DESCRIPTOR_JSON);
cs.Write(entry.Identifier);
cs.Write(""); // reserved for version
}
else
{
cs.Write(DESCRIPTOR_DAT);
cs.Write(entry.Entry);
}
}
else
{
auto entry = obj->GetObjectEntry();
assert(entry != nullptr);
cs.Write(DESCRIPTOR_DAT);
cs.Write(entry);
cs.Write(DESCRIPTOR_NONE);
}
}
else
{
cs.Write(DESCRIPTOR_NONE);
}
});
}
});
}
}

View File

@@ -12,6 +12,7 @@
#include "common.h"
#include "core/String.hpp"
#include "object/Object.h"
#include "object/ObjectList.h"
#include <memory>
#include <string>
@@ -19,6 +20,7 @@
struct IObjectManager;
struct IObjectRepository;
namespace OpenRCT2
{
struct IStream;
@@ -29,9 +31,9 @@ struct scenario_index_entry;
struct ParkLoadResult final
{
public:
std::vector<ObjectEntryDescriptor> RequiredObjects;
ObjectList RequiredObjects;
explicit ParkLoadResult(std::vector<ObjectEntryDescriptor>&& requiredObjects)
explicit ParkLoadResult(ObjectList&& requiredObjects)
: RequiredObjects(std::move(requiredObjects))
{
}

View File

@@ -305,6 +305,14 @@ namespace OpenRCT2
}
}
#if defined(_MSC_VER)
template<>
#endif
void Write(const std::string& v)
{
Write(std::string_view(v));
}
template<typename TVec, typename TFunc> void ReadWriteVector(TVec& vec, TFunc f)
{
if (_mode == Mode::READING)

View File

@@ -39,7 +39,11 @@ constexpr const uint16_t OBJECT_ENTRY_COUNT =
MAX_SCENERY_GROUP_OBJECTS +
MAX_PARK_ENTRANCE_OBJECTS +
MAX_WATER_OBJECTS +
MAX_SCENARIO_TEXT_OBJECTS;
MAX_SCENARIO_TEXT_OBJECTS +
MAX_TERRAIN_SURFACE_OBJECTS +
MAX_TERRAIN_EDGE_OBJECTS +
MAX_STATION_OBJECTS +
MAX_MUSIC_OBJECTS;
// clang-format on
constexpr const uint8_t DAT_NAME_LENGTH = 8;

View File

@@ -56,6 +56,123 @@ int32_t object_entry_group_encoding[] = {
};
// clang-format on
ObjectList::const_iterator::const_iterator(const ObjectList* parent, bool end)
{
_parent = parent;
_subList = _parent->_subLists.size();
_index = 0;
}
void ObjectList::const_iterator::MoveToNextEntry()
{
do
{
if (_subList < _parent->_subLists.size())
{
auto subListSize = _parent->_subLists[_subList].size();
if (_index < subListSize)
{
_index++;
if (_index == subListSize)
{
_subList++;
_index = 0;
}
}
}
else
{
break;
}
} while (!_parent->_subLists[_subList][_index].HasValue());
}
ObjectList::const_iterator& ObjectList::const_iterator::operator++()
{
MoveToNextEntry();
return *this;
}
ObjectList::const_iterator ObjectList::const_iterator::operator++(int)
{
return *this;
}
const ObjectEntryDescriptor& ObjectList::const_iterator::operator*()
{
return _parent->_subLists[_subList][_index];
}
bool ObjectList::const_iterator::operator==(const_iterator& rhs)
{
return _parent == rhs._parent && _subList == rhs._subList && _index == rhs._index;
}
bool ObjectList::const_iterator::operator!=(const_iterator& rhs)
{
return !(*this == rhs);
}
ObjectList::const_iterator ObjectList::begin() const
{
return const_iterator(this, false);
}
ObjectList::const_iterator ObjectList::end() const
{
return const_iterator(this, true);
}
std::vector<ObjectEntryDescriptor>& ObjectList::GetList(ObjectType type)
{
auto index = static_cast<size_t>(type);
while (_subLists.size() <= index)
{
_subLists.resize(static_cast<size_t>(index) + 1);
}
return _subLists[index];
}
std::vector<ObjectEntryDescriptor>& ObjectList::GetList(ObjectType type) const
{
return const_cast<ObjectList*>(this)->GetList(type);
}
const ObjectEntryDescriptor& ObjectList::GetObject(ObjectType type, ObjectEntryIndex index) const
{
const auto& subList = GetList(type);
if (subList.size() > index)
{
return subList[index];
}
static ObjectEntryDescriptor placeholder;
return placeholder;
}
void ObjectList::Add(const ObjectEntryDescriptor& entry)
{
auto& subList = GetList(entry.GetType());
subList.push_back(entry);
}
void ObjectList::SetObject(ObjectEntryIndex index, const ObjectEntryDescriptor& entry)
{
auto& subList = GetList(entry.GetType());
if (subList.size() <= index)
{
subList.resize(static_cast<size_t>(index) + 1);
}
subList[index] = entry;
}
void ObjectList::SetObject(ObjectType type, ObjectEntryIndex index, std::string_view identifier)
{
auto entry = ObjectEntryDescriptor(identifier);
entry.Type = type;
SetObject(index, entry);
}
bool object_entry_is_empty(const rct_object_entry* entry)
{
uint64_t a, b;

View File

@@ -15,8 +15,46 @@
#include "../world/Footpath.h"
#include "../world/Scenery.h"
#include "../world/Water.h"
#include "Object.h"
#include "ObjectLimits.h"
#include <vector>
class ObjectList
{
private:
std::vector<std::vector<ObjectEntryDescriptor>> _subLists;
public:
void Add(const ObjectEntryDescriptor& entry);
std::vector<ObjectEntryDescriptor>& GetList(ObjectType type);
std::vector<ObjectEntryDescriptor>& GetList(ObjectType type) const;
const ObjectEntryDescriptor& GetObject(ObjectType type, ObjectEntryIndex index) const;
void SetObject(ObjectEntryIndex index, const ObjectEntryDescriptor& entry);
void SetObject(ObjectType type, ObjectEntryIndex index, std::string_view identifier);
struct const_iterator
{
private:
const ObjectList* _parent;
size_t _subList;
size_t _index;
void MoveToNextEntry();
public:
const_iterator(const ObjectList* parent, bool end);
const ObjectEntryDescriptor& operator*();
bool operator==(const_iterator& rhs);
bool operator!=(const_iterator& rhs);
const_iterator& operator++();
const_iterator operator++(int);
};
const_iterator begin() const;
const_iterator end() const;
};
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

@@ -102,6 +102,26 @@ public:
return result;
}
ObjectList GetLoadedObjects() override
{
ObjectList objectList;
for (auto objectType = ObjectType::Ride; objectType < ObjectType::Count; objectType++)
{
auto maxObjectsOfType = static_cast<ObjectEntryIndex>(object_entry_group_counts[EnumValue(objectType)]);
for (ObjectEntryIndex i = 0; i < maxObjectsOfType; i++)
{
auto obj = GetLoadedObject(objectType, i);
if (obj != nullptr)
{
auto entry = ObjectEntryDescriptor(obj->GetIdentifier());
entry.Type = obj->GetObjectType();
objectList.SetObject(i, entry);
}
}
}
return objectList;
}
Object* LoadObject(std::string_view identifier) override
{
const ObjectRepositoryItem* ori = _objectRepository.FindObject(identifier);
@@ -114,17 +134,16 @@ public:
return RepositoryItemToObject(ori);
}
void LoadObjects(const std::vector<ObjectEntryDescriptor>& entries) override
void LoadObjects(const ObjectList& objectList) override
{
// Find all the required objects
auto requiredObjects = GetRequiredObjects(entries);
auto requiredObjects = GetRequiredObjects(objectList);
// Load the required objects
size_t numNewLoadedObjects = 0;
auto loadedObjects = LoadObjects(requiredObjects, &numNewLoadedObjects);
SetNewLoadedObjectList(std::move(loadedObjects));
LoadDefaultObjects();
UpdateSceneryGroupIndexes();
ResetTypeToRideEntryIndexMap();
log_verbose("%u / %u new objects loaded", numNewLoadedObjects, requiredObjects.size());
@@ -198,99 +217,6 @@ public:
return objects;
}
void LoadDefaultObjects() override
{
// We currently will load new object types here that apply to all
// loaded RCT1 and RCT2 save files.
// Surfaces
LoadObject("rct2.surface.grass");
LoadObject("rct2.surface.sand");
LoadObject("rct2.surface.dirt");
LoadObject("rct2.surface.rock");
LoadObject("rct2.surface.martian");
LoadObject("rct2.surface.chequerboard");
LoadObject("rct2.surface.grassclumps");
LoadObject("rct2.surface.ice");
LoadObject("rct2.surface.gridred");
LoadObject("rct2.surface.gridyellow");
LoadObject("rct2.surface.gridpurple");
LoadObject("rct2.surface.gridgreen");
LoadObject("rct2.surface.sandred");
LoadObject("rct2.surface.sandbrown");
LoadObject("rct1.aa.surface.roofred");
LoadObject("rct1.ll.surface.roofgrey");
LoadObject("rct1.ll.surface.rust");
LoadObject("rct1.ll.surface.wood");
// Edges
LoadObject("rct2.edge.rock");
LoadObject("rct2.edge.woodred");
LoadObject("rct2.edge.woodblack");
LoadObject("rct2.edge.ice");
LoadObject("rct1.edge.brick");
LoadObject("rct1.edge.iron");
LoadObject("rct1.aa.edge.grey");
LoadObject("rct1.aa.edge.yellow");
LoadObject("rct1.aa.edge.red");
LoadObject("rct1.ll.edge.purple");
LoadObject("rct1.ll.edge.green");
LoadObject("rct1.ll.edge.stonebrown");
LoadObject("rct1.ll.edge.stonegrey");
LoadObject("rct1.ll.edge.skyscrapera");
LoadObject("rct1.ll.edge.skyscraperb");
// Stations
LoadObject("rct2.station.plain");
LoadObject("rct2.station.wooden");
LoadObject("rct2.station.canvastent");
LoadObject("rct2.station.castlegrey");
LoadObject("rct2.station.castlebrown");
LoadObject("rct2.station.jungle");
LoadObject("rct2.station.log");
LoadObject("rct2.station.classical");
LoadObject("rct2.station.abstract");
LoadObject("rct2.station.snow");
LoadObject("rct2.station.pagoda");
LoadObject("rct2.station.space");
LoadObject("openrct2.station.noentrance");
// Music
auto baseIndex = GetIndexFromTypeEntry(ObjectType::Music, 0);
LoadObject(baseIndex + MUSIC_STYLE_DODGEMS_BEAT, "rct2.music.dodgems");
LoadObject(baseIndex + MUSIC_STYLE_FAIRGROUND_ORGAN, "rct2.music.fairground");
LoadObject(baseIndex + MUSIC_STYLE_ROMAN_FANFARE, "rct2.music.roman");
LoadObject(baseIndex + MUSIC_STYLE_ORIENTAL, "rct2.music.oriental");
LoadObject(baseIndex + MUSIC_STYLE_MARTIAN, "rct2.music.martian");
LoadObject(baseIndex + MUSIC_STYLE_JUNGLE_DRUMS, "rct2.music.jungle");
LoadObject(baseIndex + MUSIC_STYLE_EGYPTIAN, "rct2.music.egyptian");
LoadObject(baseIndex + MUSIC_STYLE_TOYLAND, "rct2.music.toyland");
LoadObject(baseIndex + MUSIC_STYLE_SPACE, "rct2.music.space");
LoadObject(baseIndex + MUSIC_STYLE_HORROR, "rct2.music.horror");
LoadObject(baseIndex + MUSIC_STYLE_TECHNO, "rct2.music.techno");
LoadObject(baseIndex + MUSIC_STYLE_GENTLE, "rct2.music.gentle");
LoadObject(baseIndex + MUSIC_STYLE_SUMMER, "rct2.music.summer");
LoadObject(baseIndex + MUSIC_STYLE_WATER, "rct2.music.water");
LoadObject(baseIndex + MUSIC_STYLE_WILD_WEST, "rct2.music.wildwest");
LoadObject(baseIndex + MUSIC_STYLE_JURASSIC, "rct2.music.jurassic");
LoadObject(baseIndex + MUSIC_STYLE_ROCK, "rct2.music.rock1");
LoadObject(baseIndex + MUSIC_STYLE_RAGTIME, "rct2.music.ragtime");
LoadObject(baseIndex + MUSIC_STYLE_FANTASY, "rct2.music.fantasy");
LoadObject(baseIndex + MUSIC_STYLE_ROCK_STYLE_2, "rct2.music.rock2");
LoadObject(baseIndex + MUSIC_STYLE_ICE, "rct2.music.ice");
LoadObject(baseIndex + MUSIC_STYLE_SNOW, "rct2.music.snow");
LoadObject(baseIndex + MUSIC_STYLE_CUSTOM_MUSIC_1, "rct2.music.custom1");
LoadObject(baseIndex + MUSIC_STYLE_CUSTOM_MUSIC_2, "rct2.music.custom2");
LoadObject(baseIndex + MUSIC_STYLE_MEDIEVAL, "rct2.music.medieval");
LoadObject(baseIndex + MUSIC_STYLE_URBAN, "rct2.music.urban");
LoadObject(baseIndex + MUSIC_STYLE_ORGAN, "rct2.music.organ");
LoadObject(baseIndex + MUSIC_STYLE_MECHANICAL, "rct2.music.mechanical");
LoadObject(baseIndex + MUSIC_STYLE_MODERN, "rct2.music.modern");
LoadObject(baseIndex + MUSIC_STYLE_PIRATES, "rct2.music.pirate");
LoadObject(baseIndex + MUSIC_STYLE_ROCK_STYLE_3, "rct2.music.rock3");
LoadObject(baseIndex + MUSIC_STYLE_CANDY_STYLE, "rct2.music.candy");
}
static rct_string_id GetObjectSourceGameString(const ObjectSourceGame sourceGame)
{
switch (sourceGame)
@@ -554,25 +480,29 @@ private:
return duplicate;
}
std::vector<const ObjectRepositoryItem*> GetRequiredObjects(const std::vector<ObjectEntryDescriptor>& objectList)
std::vector<const ObjectRepositoryItem*> GetRequiredObjects(const ObjectList& objectList)
{
std::vector<const ObjectRepositoryItem*> requiredObjects;
std::vector<ObjectEntryDescriptor> missingObjects;
for (size_t i = 0; i < objectList.size(); i++)
for (auto objectType = ObjectType::Ride; objectType < ObjectType::Count; objectType++)
{
const auto& entry = objectList[i];
const ObjectRepositoryItem* ori = nullptr;
if (entry.HasValue())
auto maxObjectsOfType = static_cast<ObjectEntryIndex>(object_entry_group_counts[EnumValue(objectType)]);
for (ObjectEntryIndex i = 0; i < maxObjectsOfType; i++)
{
ori = _objectRepository.FindObject(entry);
if (ori == nullptr && entry.GetType() != ObjectType::ScenarioText)
const ObjectRepositoryItem* ori = nullptr;
const auto& entry = objectList.GetObject(objectType, i);
if (entry.HasValue())
{
missingObjects.push_back(entry);
ReportMissingObject(entry);
ori = _objectRepository.FindObject(entry);
if (ori == nullptr && entry.GetType() != ObjectType::ScenarioText)
{
missingObjects.push_back(entry);
ReportMissingObject(entry);
}
}
requiredObjects.push_back(ori);
}
requiredObjects.push_back(ori);
}
if (!missingObjects.empty())

View File

@@ -16,6 +16,7 @@
struct IObjectRepository;
class Object;
class ObjectList;
struct ObjectRepositoryItem;
struct IObjectManager
@@ -28,11 +29,11 @@ struct IObjectManager
virtual Object* GetLoadedObject(ObjectType objectType, size_t index) abstract;
virtual Object* GetLoadedObject(const ObjectEntryDescriptor& entry) abstract;
virtual ObjectEntryIndex GetLoadedObjectEntryIndex(const Object* object) abstract;
virtual ObjectList GetLoadedObjects() abstract;
virtual Object* LoadObject(std::string_view identifier) abstract;
virtual Object* LoadObject(const rct_object_entry* entry) abstract;
virtual void LoadObjects(const std::vector<ObjectEntryDescriptor>& entries) abstract;
virtual void LoadDefaultObjects() abstract;
virtual void LoadObjects(const ObjectList& entries) abstract;
virtual void UnloadObjects(const std::vector<rct_object_entry>& entries) abstract;
virtual void UnloadAll() abstract;

View File

@@ -189,7 +189,6 @@ public:
Initialise();
CreateAvailableObjectMappings();
LoadObjects();
ImportRides();
ImportRideMeasurements();
@@ -339,7 +338,6 @@ private:
// Do map initialisation, same kind of stuff done when loading scenario editor
auto context = OpenRCT2::GetContext();
context->GetObjectManager().UnloadAll();
context->GetGameState()->InitAll(mapSize);
gS6Info.editor_step = EditorStep::ObjectSelection;
gParkFlags |= PARK_FLAGS_SHOW_REAL_GUEST_NAMES;
@@ -1486,83 +1484,25 @@ private:
}
}
void LoadObjects()
void AppendRequiredObjects(ObjectList& objectList, ObjectType objectType, const EntryList& entryList)
{
auto& objectManager = OpenRCT2::GetContext()->GetObjectManager();
objectManager.LoadDefaultObjects();
LoadObjects(ObjectType::Ride, _rideEntries);
LoadObjects(ObjectType::SmallScenery, _smallSceneryEntries);
LoadObjects(ObjectType::LargeScenery, _largeSceneryEntries);
LoadObjects(ObjectType::Walls, _wallEntries);
LoadObjects(ObjectType::Paths, _pathEntries);
LoadObjects(ObjectType::PathBits, _pathAdditionEntries);
LoadObjects(ObjectType::SceneryGroup, _sceneryGroupEntries);
LoadObjects(
ObjectType::Banners,
std::vector<const char*>({
"BN1 ",
"BN2 ",
"BN3 ",
"BN4 ",
"BN5 ",
"BN6 ",
"BN7 ",
"BN8 ",
"BN9 ",
}));
LoadObjects(ObjectType::ParkEntrance, std::vector<const char*>({ "PKENT1 " }));
LoadObjects(ObjectType::Water, _waterEntry);
AppendRequiredObjects(objectList, objectType, entryList.GetEntries());
}
void LoadObjects(ObjectType objectType, const EntryList& entries)
{
LoadObjects(objectType, entries.GetEntries());
}
void LoadObjects(ObjectType objectType, const std::vector<const char*>& entries)
{
auto& objectManager = OpenRCT2::GetContext()->GetObjectManager();
uint32_t entryIndex = 0;
for (const char* objectName : entries)
{
rct_object_entry entry;
entry.flags = 0x00008000 + EnumValue(objectType);
std::copy_n(objectName, 8, entry.name);
entry.checksum = 0;
Object* object = objectManager.LoadObject(&entry);
if (object == nullptr && objectType != ObjectType::SceneryGroup)
{
log_error("Failed to load %s.", objectName);
throw std::runtime_error("Failed to load object.");
}
entryIndex++;
}
}
void AppendRequiredObjects(std::vector<ObjectEntryDescriptor>& entries, ObjectType objectType, const EntryList& entryList)
{
AppendRequiredObjects(entries, objectType, entryList.GetEntries());
}
void AppendRequiredObjects(
std::vector<ObjectEntryDescriptor>& entries, ObjectType objectType, const std::vector<const char*>& objectNames)
void AppendRequiredObjects(ObjectList& objectList, ObjectType objectType, const std::vector<const char*>& objectNames)
{
for (const auto objectName : objectNames)
{
rct_object_entry entry{};
entry.flags = ((static_cast<uint8_t>(ObjectSourceGame::RCT2) << 4) & 0xF0) | (EnumValue(objectType) & 0x0F);
entry.SetName(objectName);
entries.push_back(ObjectEntryDescriptor(entry));
objectList.Add(ObjectEntryDescriptor(entry));
}
}
std::vector<ObjectEntryDescriptor> GetRequiredObjects()
ObjectList GetRequiredObjects()
{
std::vector<ObjectEntryDescriptor> result;
ObjectList result;
AppendRequiredObjects(result, ObjectType::Ride, _rideEntries);
AppendRequiredObjects(result, ObjectType::SmallScenery, _smallSceneryEntries);
AppendRequiredObjects(result, ObjectType::LargeScenery, _largeSceneryEntries);
@@ -1585,6 +1525,7 @@ private:
}));
AppendRequiredObjects(result, ObjectType::ParkEntrance, std::vector<const char*>({ "PKENT1 " }));
AppendRequiredObjects(result, ObjectType::Water, _waterEntry);
RCT12AddDefaultObjects(result);
return result;
}

View File

@@ -12,6 +12,7 @@
#include "../core/String.hpp"
#include "../localisation/Formatting.h"
#include "../localisation/Localisation.h"
#include "../object/ObjectList.h"
#include "../ride/Track.h"
#include "../world/Banner.h"
#include "../world/Footpath.h"
@@ -1347,3 +1348,93 @@ RCT12TrackType OpenRCT2FlatTrackTypeToRCT12(track_type_t origTrackType)
return origTrackType;
}
void RCT12AddDefaultObjects(ObjectList& objectList)
{
// Surfaces
objectList.SetObject(ObjectType::TerrainSurface, 0, "rct2.surface.grass");
objectList.SetObject(ObjectType::TerrainSurface, 1, "rct2.surface.sand");
objectList.SetObject(ObjectType::TerrainSurface, 2, "rct2.surface.dirt");
objectList.SetObject(ObjectType::TerrainSurface, 3, "rct2.surface.rock");
objectList.SetObject(ObjectType::TerrainSurface, 4, "rct2.surface.martian");
objectList.SetObject(ObjectType::TerrainSurface, 5, "rct2.surface.chequerboard");
objectList.SetObject(ObjectType::TerrainSurface, 6, "rct2.surface.grassclumps");
objectList.SetObject(ObjectType::TerrainSurface, 7, "rct2.surface.ice");
objectList.SetObject(ObjectType::TerrainSurface, 8, "rct2.surface.gridred");
objectList.SetObject(ObjectType::TerrainSurface, 9, "rct2.surface.gridyellow");
objectList.SetObject(ObjectType::TerrainSurface, 10, "rct2.surface.gridpurple");
objectList.SetObject(ObjectType::TerrainSurface, 11, "rct2.surface.gridgreen");
objectList.SetObject(ObjectType::TerrainSurface, 12, "rct2.surface.sandred");
objectList.SetObject(ObjectType::TerrainSurface, 13, "rct2.surface.sandbrown");
objectList.SetObject(ObjectType::TerrainSurface, 14, "rct1.aa.surface.roofred");
objectList.SetObject(ObjectType::TerrainSurface, 15, "rct1.ll.surface.roofgrey");
objectList.SetObject(ObjectType::TerrainSurface, 16, "rct1.ll.surface.rust");
objectList.SetObject(ObjectType::TerrainSurface, 17, "rct1.ll.surface.wood");
// Edges
objectList.SetObject(ObjectType::TerrainEdge, 0, "rct2.edge.rock");
objectList.SetObject(ObjectType::TerrainEdge, 1, "rct2.edge.woodred");
objectList.SetObject(ObjectType::TerrainEdge, 2, "rct2.edge.woodblack");
objectList.SetObject(ObjectType::TerrainEdge, 3, "rct2.edge.ice");
objectList.SetObject(ObjectType::TerrainEdge, 4, "rct1.edge.brick");
objectList.SetObject(ObjectType::TerrainEdge, 5, "rct1.edge.iron");
objectList.SetObject(ObjectType::TerrainEdge, 6, "rct1.aa.edge.grey");
objectList.SetObject(ObjectType::TerrainEdge, 7, "rct1.aa.edge.yellow");
objectList.SetObject(ObjectType::TerrainEdge, 8, "rct1.aa.edge.red");
objectList.SetObject(ObjectType::TerrainEdge, 9, "rct1.ll.edge.purple");
objectList.SetObject(ObjectType::TerrainEdge, 10, "rct1.ll.edge.green");
objectList.SetObject(ObjectType::TerrainEdge, 11, "rct1.ll.edge.stonebrown");
objectList.SetObject(ObjectType::TerrainEdge, 12, "rct1.ll.edge.stonegrey");
objectList.SetObject(ObjectType::TerrainEdge, 13, "rct1.ll.edge.skyscrapera");
objectList.SetObject(ObjectType::TerrainEdge, 14, "rct1.ll.edge.skyscraperb");
// Stations
objectList.SetObject(ObjectType::Station, 0, "rct2.station.plain");
objectList.SetObject(ObjectType::Station, 1, "rct2.station.wooden");
objectList.SetObject(ObjectType::Station, 2, "rct2.station.canvastent");
objectList.SetObject(ObjectType::Station, 3, "rct2.station.castlegrey");
objectList.SetObject(ObjectType::Station, 4, "rct2.station.castlebrown");
objectList.SetObject(ObjectType::Station, 5, "rct2.station.jungle");
objectList.SetObject(ObjectType::Station, 6, "rct2.station.log");
objectList.SetObject(ObjectType::Station, 7, "rct2.station.classical");
objectList.SetObject(ObjectType::Station, 8, "rct2.station.abstract");
objectList.SetObject(ObjectType::Station, 9, "rct2.station.snow");
objectList.SetObject(ObjectType::Station, 10, "rct2.station.pagoda");
objectList.SetObject(ObjectType::Station, 11, "rct2.station.space");
objectList.SetObject(ObjectType::Station, 12, "openrct2.station.noentrance");
// Music
objectList.SetObject(ObjectType::Music, 0, "rct2.music.dodgems");
objectList.SetObject(ObjectType::Music, 1, "rct2.music.fairground");
objectList.SetObject(ObjectType::Music, 2, "rct2.music.roman");
objectList.SetObject(ObjectType::Music, 3, "rct2.music.oriental");
objectList.SetObject(ObjectType::Music, 4, "rct2.music.martian");
objectList.SetObject(ObjectType::Music, 5, "rct2.music.jungle");
objectList.SetObject(ObjectType::Music, 6, "rct2.music.egyptian");
objectList.SetObject(ObjectType::Music, 7, "rct2.music.toyland");
// Original ID: 8 was circus
objectList.SetObject(ObjectType::Music, 9, "rct2.music.space");
objectList.SetObject(ObjectType::Music, 10, "rct2.music.horror");
objectList.SetObject(ObjectType::Music, 11, "rct2.music.techno");
objectList.SetObject(ObjectType::Music, 12, "rct2.music.gentle");
objectList.SetObject(ObjectType::Music, 13, "rct2.music.summer");
objectList.SetObject(ObjectType::Music, 14, "rct2.music.water");
objectList.SetObject(ObjectType::Music, 15, "rct2.music.wildwest");
objectList.SetObject(ObjectType::Music, 16, "rct2.music.jurassic");
objectList.SetObject(ObjectType::Music, 17, "rct2.music.rock1");
objectList.SetObject(ObjectType::Music, 18, "rct2.music.ragtime");
objectList.SetObject(ObjectType::Music, 19, "rct2.music.fantasy");
objectList.SetObject(ObjectType::Music, 20, "rct2.music.rock2");
objectList.SetObject(ObjectType::Music, 21, "rct2.music.ice");
objectList.SetObject(ObjectType::Music, 22, "rct2.music.snow");
objectList.SetObject(ObjectType::Music, 23, "rct2.music.custom1");
objectList.SetObject(ObjectType::Music, 24, "rct2.music.custom2");
objectList.SetObject(ObjectType::Music, 25, "rct2.music.medieval");
objectList.SetObject(ObjectType::Music, 26, "rct2.music.urban");
objectList.SetObject(ObjectType::Music, 27, "rct2.music.organ");
objectList.SetObject(ObjectType::Music, 28, "rct2.music.mechanical");
objectList.SetObject(ObjectType::Music, 29, "rct2.music.modern");
objectList.SetObject(ObjectType::Music, 30, "rct2.music.pirate");
objectList.SetObject(ObjectType::Music, 31, "rct2.music.rock3");
objectList.SetObject(ObjectType::Music, 32, "rct2.music.candy");
}

View File

@@ -18,6 +18,8 @@
#include <string>
#include <string_view>
class ObjectList;
using track_type_t = uint16_t;
using RCT12TrackType = uint8_t;
@@ -927,3 +929,4 @@ std::string ConvertFormattedStringToRCT2(std::string_view buffer, size_t maxLeng
std::string GetTruncatedRCT2String(std::string_view src, size_t maxLength);
track_type_t RCT12FlatTrackTypeToOpenRCT2(RCT12TrackType origTrackType);
RCT12TrackType OpenRCT2FlatTrackTypeToRCT12(track_type_t origTrackType);
void RCT12AddDefaultObjects(ObjectList& objectList);

View File

@@ -30,6 +30,7 @@
#include "../management/Research.h"
#include "../network/network.h"
#include "../object/ObjectLimits.h"
#include "../object/ObjectList.h"
#include "../object/ObjectManager.h"
#include "../object/ObjectRepository.h"
#include "../peep/Staff.h"
@@ -1549,23 +1550,24 @@ public:
return justText.data();
}
std::vector<ObjectEntryDescriptor> GetRequiredObjects()
ObjectList GetRequiredObjects()
{
std::vector<ObjectEntryDescriptor> result;
ObjectList objectList;
int objectIt = 0;
for (int16_t objectType = EnumValue(ObjectType::Ride); objectType <= EnumValue(ObjectType::Water); objectType++)
{
for (int16_t i = 0; i < rct2_object_entry_group_counts[objectType]; i++, objectIt++)
{
result.push_back(ObjectEntryDescriptor(_s6.objects[objectIt]));
}
for (int16_t i = rct2_object_entry_group_counts[objectType]; i < object_entry_group_counts[objectType]; i++)
{
result.push_back({});
auto entry = ObjectEntryDescriptor(_s6.objects[objectIt]);
if (entry.HasValue())
{
objectList.SetObject(i, entry);
}
}
}
return result;
RCT12AddDefaultObjects(objectList);
return objectList;
}
};