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

Refactor the ride type to entry map (#10967)

Use C++ vectors and allow larger ride entry indices (> 256)
This commit is contained in:
Ted John
2020-03-20 17:07:31 +00:00
committed by GitHub
parent 4cc2bc469a
commit c89cecb2b5
9 changed files with 126 additions and 159 deletions

View File

@@ -23,6 +23,7 @@
#include <openrct2/management/Research.h>
#include <openrct2/network/network.h>
#include <openrct2/object/ObjectLimits.h>
#include <openrct2/object/ObjectManager.h>
#include <openrct2/rct1/RCT1.h>
#include <openrct2/ride/RideData.h>
#include <openrct2/ride/RideGroupManager.h>
@@ -212,7 +213,7 @@ static void window_new_ride_scrollmouseover(rct_window *w, int32_t scrollIndex,
static void window_new_ride_invalidate(rct_window *w);
static void window_new_ride_paint(rct_window *w, rct_drawpixelinfo *dpi);
static void window_new_ride_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int32_t scrollIndex);
static void window_new_ride_list_vehicles_for(const uint8_t rideType, const rct_ride_entry * rideEntry, char * out);
static void window_new_ride_list_vehicles_for(uint8_t rideType, const rct_ride_entry* rideEntry, char* buffer, size_t bufferLen);
// 0x0098E354
static rct_window_event_list window_new_ride_events = {
@@ -346,15 +347,15 @@ static ride_list_item* window_new_ride_iterate_over_ride_group(
{
bool buttonForRideTypeCreated = false;
bool allowDrawingOverLastButton = false;
uint8_t* rideEntryIndexPtr = get_ride_entry_indices_for_ride_type(rideType);
char preferredVehicleName[DAT_NAME_LENGTH + 1];
safe_strcpy(preferredVehicleName, " ", sizeof(preferredVehicleName));
// For each ride entry for this ride type
while (*rideEntryIndexPtr != RIDE_ENTRY_INDEX_NULL)
auto& objManager = OpenRCT2::GetContext()->GetObjectManager();
auto& rideEntries = objManager.GetAllRideEntries(rideType);
for (auto rideEntryIndex : rideEntries)
{
uint8_t rideEntryIndex = *rideEntryIndexPtr++;
char rideEntryName[DAT_NAME_LENGTH + 1];
std::memcpy(rideEntryName, object_entry_get_entry(OBJECT_TYPE_RIDE, rideEntryIndex)->name, 8);
rideEntryName[DAT_NAME_LENGTH] = 0;
@@ -975,7 +976,7 @@ static void window_new_ride_paint_ride_information(
gfx_draw_string_left_wrapped(dpi, gCommonFormatArgs, x, y, width, STR_NEW_RIDE_NAME_AND_DESCRIPTION, COLOUR_BLACK);
char availabilityString[AVAILABILITY_STRING_SIZE];
window_new_ride_list_vehicles_for(item.type, rideEntry, availabilityString);
window_new_ride_list_vehicles_for(item.type, rideEntry, availabilityString, sizeof(availabilityString));
if (availabilityString[0] != 0)
{
@@ -1056,27 +1057,20 @@ static void window_new_ride_select(rct_window* w)
ride_construct_new(item);
}
static void window_new_ride_list_vehicles_for(const uint8_t rideType, const rct_ride_entry* rideEntry, char* out)
static void window_new_ride_list_vehicles_for(uint8_t rideType, const rct_ride_entry* rideEntry, char* buffer, size_t bufferLen)
{
rct_ride_entry* currentRideEntry;
const RideGroup *rideGroup, *currentRideGroup;
int32_t rideEntryIndex;
std::fill_n(buffer, bufferLen, 0);
if (RideGroupManager::RideTypeIsIndependent(rideType))
{
out[0] = 0;
return;
}
std::fill_n(out, AVAILABILITY_STRING_SIZE, 0x00);
uint8_t* rideEntryIndexPtr = get_ride_entry_indices_for_ride_type(rideType);
for (uint8_t *currentRideEntryIndex = rideEntryIndexPtr, numItems = 0; *currentRideEntryIndex != RIDE_ENTRY_INDEX_NULL;
currentRideEntryIndex++)
auto& objManager = OpenRCT2::GetContext()->GetObjectManager();
auto& rideEntries = objManager.GetAllRideEntries(rideType);
auto isFirst = true;
for (auto rideEntryIndex : rideEntries)
{
rideEntryIndex = *currentRideEntryIndex;
currentRideEntry = get_ride_entry(rideEntryIndex);
auto currentRideEntry = get_ride_entry(rideEntryIndex);
// Skip if vehicle type is not invented yet
if (!ride_entry_is_invented(rideEntryIndex) && !gCheatsIgnoreResearchStatus)
@@ -1085,22 +1079,23 @@ static void window_new_ride_list_vehicles_for(const uint8_t rideType, const rct_
// Skip if vehicle does not belong to the same ride group
if (RideGroupManager::RideTypeHasRideGroups(rideType))
{
rideGroup = RideGroupManager::GetRideGroup(rideType, (rct_ride_entry*)rideEntry);
currentRideGroup = RideGroupManager::GetRideGroup(rideType, (rct_ride_entry*)currentRideEntry);
auto rideGroup = RideGroupManager::GetRideGroup(rideType, rideEntry);
auto currentRideGroup = RideGroupManager::GetRideGroup(rideType, currentRideEntry);
if (!rideGroup->Equals(currentRideGroup))
continue;
}
const char* vehicleName = language_get_string(currentRideEntry->naming.name);
if (numItems > 0)
// Append comma if not the first iteration
if (!isFirst)
{
safe_strcat(out, ", ", AVAILABILITY_STRING_SIZE);
safe_strcat(buffer, ", ", bufferLen);
}
safe_strcat(out, vehicleName, AVAILABILITY_STRING_SIZE);
// Append vehicle name
auto vehicleName = language_get_string(currentRideEntry->naming.name);
safe_strcat(buffer, vehicleName, bufferLen);
numItems++;
isFirst = false;
}
}

View File

@@ -2321,6 +2321,7 @@ static void window_ride_show_ride_type_dropdown(rct_window* w, rct_widget* widge
static void populate_vehicle_type_dropdown(Ride* ride)
{
auto& objManager = GetContext()->GetObjectManager();
rct_ride_entry* rideEntry = ride->GetRideEntry();
bool selectionShouldBeExpanded;
@@ -2356,13 +2357,10 @@ static void populate_vehicle_type_dropdown(Ride* ride)
if (selectionShouldBeExpanded && (rideTypeIterator == RIDE_TYPE_MAZE || rideTypeIterator == RIDE_TYPE_MINI_GOLF))
continue;
uint8_t* rideEntryIndexPtr = get_ride_entry_indices_for_ride_type(rideTypeIterator);
for (uint8_t* currentRideEntryIndex = rideEntryIndexPtr; *currentRideEntryIndex != RIDE_ENTRY_INDEX_NULL;
currentRideEntryIndex++)
auto& rideEntries = objManager.GetAllRideEntries(rideTypeIterator);
for (auto rideEntryIndex : rideEntries)
{
int32_t rideEntryIndex = *currentRideEntryIndex;
rct_ride_entry* currentRideEntry = get_ride_entry(rideEntryIndex);
auto currentRideEntry = get_ride_entry(rideEntryIndex);
// Skip if vehicle type has not been invented yet
if (!ride_entry_is_invented(rideEntryIndex) && !gCheatsIgnoreResearchStatus)

View File

@@ -17,6 +17,7 @@
#include "../localisation/Localisation.h"
#include "../localisation/StringIds.h"
#include "../management/Research.h"
#include "../object/ObjectManager.h"
#include "../ride/Ride.h"
#include "../ui/UiContext.h"
#include "../ui/WindowManager.h"
@@ -247,11 +248,10 @@ private:
continue;
}
uint8_t* rideEntryIndexPtr = get_ride_entry_indices_for_ride_type(rideTypeIterator);
for (uint8_t* currentRideEntryIndex = rideEntryIndexPtr; *currentRideEntryIndex != RIDE_ENTRY_INDEX_NULL;
currentRideEntryIndex++)
auto& objManager = OpenRCT2::GetContext()->GetObjectManager();
auto& rideEntries = objManager.GetAllRideEntries(rideTypeIterator);
for (auto rideEntryIndex : rideEntries)
{
uint8_t rideEntryIndex = *currentRideEntryIndex;
if (rideEntryIndex == _value)
{
if (!ride_entry_is_invented(rideEntryIndex) && !gCheatsIgnoreResearchStatus)

View File

@@ -9,8 +9,10 @@
#include "TrackDesignAction.h"
#include "../Context.h"
#include "../management/Finance.h"
#include "../management/Research.h"
#include "../object/ObjectManager.h"
#include "../object/ObjectRepository.h"
#include "../ride/RideGroupManager.h"
#include "../ride/TrackDesign.h"
@@ -57,20 +59,20 @@ GameActionResult::Ptr TrackDesignAction::Query() const
uint8_t rideGroupIndex = ori->RideInfo.RideGroupIndex;
const RideGroup* td6RideGroup = RideGroupManager::RideGroupFind(_td.type, rideGroupIndex);
uint8_t* availableRideEntries = get_ride_entry_indices_for_ride_type(_td.type);
for (uint8_t* rei = availableRideEntries; *rei != RIDE_ENTRY_INDEX_NULL; rei++)
auto& objManager = OpenRCT2::GetContext()->GetObjectManager();
auto& rideEntries = objManager.GetAllRideEntries(_td.type);
for (auto rideEntryIndex : rideEntries)
{
rct_ride_entry* ire = get_ride_entry(*rei);
if (!ride_entry_is_invented(*rei) && !gCheatsIgnoreResearchStatus)
if (!ride_entry_is_invented(rideEntryIndex) && !gCheatsIgnoreResearchStatus)
{
continue;
}
const RideGroup* irg = RideGroupManager::GetRideGroup(_td.type, ire);
if (td6RideGroup->Equals(irg))
auto rideEntry = get_ride_entry(rideEntryIndex);
auto rideGroup = RideGroupManager::GetRideGroup(_td.type, rideEntry);
if (td6RideGroup->Equals(rideGroup))
{
entryIndex = *rei;
entryIndex = rideEntryIndex;
break;
}
}
@@ -148,20 +150,20 @@ GameActionResult::Ptr TrackDesignAction::Execute() const
uint8_t rideGroupIndex = ori->RideInfo.RideGroupIndex;
const RideGroup* td6RideGroup = RideGroupManager::RideGroupFind(_td.type, rideGroupIndex);
uint8_t* availableRideEntries = get_ride_entry_indices_for_ride_type(_td.type);
for (uint8_t* rei = availableRideEntries; *rei != RIDE_ENTRY_INDEX_NULL; rei++)
auto& objManager = OpenRCT2::GetContext()->GetObjectManager();
auto& rideEntries = objManager.GetAllRideEntries(_td.type);
for (auto rideEntryIndex : rideEntries)
{
rct_ride_entry* ire = get_ride_entry(*rei);
if (!ride_entry_is_invented(*rei) && !gCheatsIgnoreResearchStatus)
if (!ride_entry_is_invented(rideEntryIndex) && !gCheatsIgnoreResearchStatus)
{
continue;
}
const RideGroup* irg = RideGroupManager::GetRideGroup(_td.type, ire);
if (td6RideGroup->Equals(irg))
auto rideEntry = get_ride_entry(rideEntryIndex);
auto rideGroup = RideGroupManager::GetRideGroup(_td.type, rideEntry);
if (td6RideGroup->Equals(rideGroup))
{
entryIndex = *rei;
entryIndex = rideEntryIndex;
break;
}
}

View File

@@ -19,6 +19,7 @@
#include "Object.h"
#include "ObjectList.h"
#include "ObjectRepository.h"
#include "RideObject.h"
#include "SceneryGroupObject.h"
#include "SmallSceneryObject.h"
#include "WallObject.h"
@@ -35,6 +36,10 @@ class ObjectManager final : public IObjectManager
private:
IObjectRepository& _objectRepository;
std::vector<Object*> _loadedObjects;
std::array<std::vector<uint16_t>, RIDE_TYPE_COUNT> _rideTypeToObjectMap;
// Used to return a safe empty vector back from GetAllRideEntries, can be removed when std::span is available
std::vector<uint16_t> _nullRideTypeEntries;
public:
explicit ObjectManager(IObjectRepository& objectRepository)
@@ -287,6 +292,16 @@ public:
}
}
const std::vector<uint16_t>& GetAllRideEntries(uint8_t rideType) override
{
if (rideType >= RIDE_TYPE_COUNT)
{
// Return an empty vector
return _nullRideTypeEntries;
}
return _rideTypeToObjectMap[rideType];
}
private:
Object* LoadObject(const std::string& name)
{
@@ -642,7 +657,33 @@ private:
void ResetTypeToRideEntryIndexMap()
{
reset_type_to_ride_entry_index_map(*this);
// Clear all ride objects
for (auto& v : _rideTypeToObjectMap)
{
v.clear();
}
// Build object lists
auto maxRideObjects = static_cast<size_t>(object_entry_group_counts[OBJECT_TYPE_RIDE]);
for (size_t i = 0; i < maxRideObjects; i++)
{
auto rideObject = static_cast<RideObject*>(GetLoadedObject(OBJECT_TYPE_RIDE, i));
if (rideObject != nullptr)
{
const auto entry = static_cast<rct_ride_entry*>(rideObject->GetLegacyData());
if (entry != nullptr)
{
for (auto rideType : entry->ride_type)
{
if (rideType < _rideTypeToObjectMap.size())
{
auto& v = _rideTypeToObjectMap[rideType];
v.push_back(static_cast<uint16_t>(i));
}
}
}
}
}
}
static void ReportMissingObject(const rct_object_entry* entry)

View File

@@ -39,6 +39,7 @@ interface IObjectManager
virtual void ResetObjects() abstract;
virtual std::vector<const ObjectRepositoryItem*> GetPackableObjects() abstract;
virtual const std::vector<uint16_t>& GetAllRideEntries(uint8_t rideType) abstract;
};
std::unique_ptr<IObjectManager> CreateObjectManager(IObjectRepository& objectRepository);

View File

@@ -73,7 +73,6 @@
using namespace OpenRCT2;
uint8_t gTypeToRideEntryIndexMap[TYPE_TO_RIDE_ENTRY_SLOTS];
static constexpr const int32_t RideInspectionInterval[] = {
10, 20, 30, 45, 60, 120, 0, 0,
};
@@ -244,64 +243,6 @@ rct_ride_entry* Ride::GetRideEntry() const
return get_ride_entry(subtype);
}
/**
*
* rct2: 0x006DED68
*/
void reset_type_to_ride_entry_index_map(IObjectManager& objectManager)
{
size_t stride = MAX_RIDE_OBJECTS + 1;
uint8_t* entryTypeTable = (uint8_t*)malloc(RIDE_TYPE_COUNT * stride);
std::fill_n(entryTypeTable, RIDE_TYPE_COUNT * stride, 0xFF);
for (uint8_t i = 0; i < MAX_RIDE_OBJECTS; i++)
{
auto obj = objectManager.GetLoadedObject(OBJECT_TYPE_RIDE, i);
if (obj != nullptr)
{
for (uint8_t j = 0; j < MAX_RIDE_TYPES_PER_RIDE_ENTRY; j++)
{
auto rideEntry = (rct_ride_entry*)obj->GetLegacyData();
uint8_t rideType = rideEntry->ride_type[j];
if (rideType < RIDE_TYPE_COUNT)
{
uint8_t* entryArray = &entryTypeTable[rideType * stride];
uint8_t* nextEntry = (uint8_t*)memchr(entryArray, 0xFF, stride);
*nextEntry = i;
}
}
}
}
uint8_t* dst = gTypeToRideEntryIndexMap;
for (uint8_t i = 0; i < RIDE_TYPE_COUNT; i++)
{
uint8_t* entryArray = &entryTypeTable[i * stride];
uint8_t* entry = entryArray;
while (*entry != 0xFF)
{
*dst++ = *entry++;
}
*dst++ = 0xFF;
}
free(entryTypeTable);
}
uint8_t* get_ride_entry_indices_for_ride_type(uint8_t rideType)
{
uint8_t* entryIndexList = gTypeToRideEntryIndexMap;
while (rideType > 0)
{
do
{
entryIndexList++;
} while (*(entryIndexList - 1) != RIDE_ENTRY_INDEX_NULL);
rideType--;
}
return entryIndexList;
}
int32_t ride_get_count()
{
return (int32_t)GetRideManager().size();
@@ -7552,31 +7493,32 @@ int32_t ride_get_entry_index(int32_t rideType, int32_t rideSubType)
if (subType == RIDE_ENTRY_INDEX_NULL)
{
uint8_t* availableRideEntries = get_ride_entry_indices_for_ride_type(rideType);
for (uint8_t* rideEntryIndex = availableRideEntries; *rideEntryIndex != RIDE_ENTRY_INDEX_NULL; rideEntryIndex++)
auto& objManager = GetContext()->GetObjectManager();
auto& rideEntries = objManager.GetAllRideEntries(rideType);
if (rideEntries.size() > 0)
{
rct_ride_entry* rideEntry = get_ride_entry(*rideEntryIndex);
if (rideEntry == nullptr)
subType = rideEntries[0];
for (auto rideEntryIndex : rideEntries)
{
return RIDE_ENTRY_INDEX_NULL;
}
auto rideEntry = get_ride_entry(rideEntryIndex);
if (rideEntry == nullptr)
{
return RIDE_ENTRY_INDEX_NULL;
}
// Can happen in select-by-track-type mode
if (!ride_entry_is_invented(*rideEntryIndex) && !gCheatsIgnoreResearchStatus)
{
continue;
}
// Can happen in select-by-track-type mode
if (!ride_entry_is_invented(rideEntryIndex) && !gCheatsIgnoreResearchStatus)
{
continue;
}
if (!RideGroupManager::RideTypeIsIndependent(rideType))
{
subType = *rideEntryIndex;
break;
if (!RideGroupManager::RideTypeIsIndependent(rideType))
{
subType = rideEntryIndex;
break;
}
}
}
if (subType == RIDE_ENTRY_INDEX_NULL)
{
subType = availableRideEntries[0];
}
}
return subType;

View File

@@ -474,15 +474,6 @@ assert_struct_size(ride_name_args, 4);
#pragma pack(pop)
/*
* This array should probably be only 91 + 128 * 3 = 475 bytes long.
* It was originally stored at address 0x009E32F8 and continued until 0x009E34E3
* (inclusive). 0x009E34E4 is the address of s6 header, so it's likely it had
* some padding at the end as well.
*/
#define TYPE_TO_RIDE_ENTRY_SLOTS 492
extern uint8_t gTypeToRideEntryIndexMap[TYPE_TO_RIDE_ENTRY_SLOTS];
// Constants used by the lifecycle_flags property at 0x1D0
enum
{
@@ -1157,8 +1148,6 @@ TrackColour ride_get_track_colour(Ride* ride, int32_t colourScheme);
vehicle_colour ride_get_vehicle_colour(Ride* ride, int32_t vehicleIndex);
int32_t ride_get_unused_preset_vehicle_colour(uint8_t ride_sub_type);
void ride_set_vehicle_colours_to_random_preset(Ride* ride, uint8_t preset_index);
uint8_t* get_ride_entry_indices_for_ride_type(uint8_t rideType);
void reset_type_to_ride_entry_index_map(IObjectManager& objectManager);
void ride_measurements_update();
std::pair<RideMeasurement*, rct_string_id> ride_get_measurement(Ride* ride);
void ride_breakdown_add_news_item(Ride* ride);

View File

@@ -9,10 +9,12 @@
#include "RideGroupManager.h"
#include "../Context.h"
#include "../config/Config.h"
#include "../core/String.hpp"
#include "../localisation/StringIds.h"
#include "../management/Research.h"
#include "../object/ObjectManager.h"
#include "Ride.h"
#include "RideData.h"
#include "Track.h"
@@ -169,23 +171,20 @@ bool RideGroup::IsInvented() const
if (!ride_type_is_invented(this->RideType))
return false;
uint8_t* rideEntryIndexPtr = get_ride_entry_indices_for_ride_type(this->RideType);
while (*rideEntryIndexPtr != RIDE_ENTRY_INDEX_NULL)
auto& objManager = OpenRCT2::GetContext()->GetObjectManager();
auto& rideEntries = objManager.GetAllRideEntries(this->RideType);
for (auto rideEntryIndex : rideEntries)
{
uint8_t rideEntryIndex = *rideEntryIndexPtr++;
if (!ride_entry_is_invented(rideEntryIndex))
continue;
rct_ride_entry* rideEntry = get_ride_entry(rideEntryIndex);
const RideGroup* rideEntryRideGroup = RideGroupManager::GetRideGroup(this->RideType, rideEntry);
if (!this->Equals(rideEntryRideGroup))
continue;
// The ride entry is invented and belongs to the same ride group. This means the ride group is invented.
return true;
if (ride_entry_is_invented(rideEntryIndex))
{
auto rideEntry = get_ride_entry(rideEntryIndex);
auto rideEntryRideGroup = RideGroupManager::GetRideGroup(this->RideType, rideEntry);
if (this->Equals(rideEntryRideGroup))
{
// The ride entry is invented and belongs to the same ride group. This means the ride group is invented.
return true;
}
}
}
return false;