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:
@@ -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
|
||||
|
||||
@@ -70,7 +70,6 @@ namespace Editor
|
||||
// Reset loaded objects to just defaults
|
||||
auto& objectManager = context->GetObjectManager();
|
||||
objectManager.UnloadAll();
|
||||
objectManager.LoadDefaultObjects();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user