mirror of https://github.com/OpenRCT2/OpenRCT2.git
create new track index file format at startup
This commit is contained in:
parent
fc74e5045e
commit
5ad8fb272e
|
@ -181,6 +181,7 @@
|
|||
<ClCompile Include="src\ride\thrill\twist.c" />
|
||||
<ClCompile Include="src\ride\track.c" />
|
||||
<ClCompile Include="src\ride\track_data.c" />
|
||||
<ClCompile Include="src\ride\track_list.c" />
|
||||
<ClCompile Include="src\ride\track_paint.c" />
|
||||
<ClCompile Include="src\ride\transport\chairlift.c" />
|
||||
<ClCompile Include="src\ride\transport\lift.c" />
|
||||
|
|
|
@ -527,8 +527,8 @@ enum{
|
|||
};
|
||||
|
||||
enum{
|
||||
RCT1_RIDE_MODE_REVERSE_INCLINE_LAUNCHED_SHUTTLE = 2,
|
||||
RCT1_RIDE_MODE_POWERED_LAUNCH = 3,
|
||||
|
||||
};
|
||||
|
||||
enum {
|
||||
|
|
|
@ -158,9 +158,7 @@ int rct2_init()
|
|||
|
||||
object_list_load();
|
||||
scenario_load_list();
|
||||
|
||||
ride_list_item item = { 253, 0 };
|
||||
track_load_list(item);
|
||||
track_design_index_create();
|
||||
|
||||
font_sprite_initialise_characters();
|
||||
if (!gOpenRCT2Headless) {
|
||||
|
|
184
src/ride/track.c
184
src/ride/track.c
|
@ -5695,3 +5695,187 @@ bool track_element_is_covered(int trackElementType)
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool track_design_open_from_buffer(rct_track_td6 *td6, uint8 *src, size_t srcLength);
|
||||
|
||||
bool track_design_open(rct_track_td6 *td6, const utf8 *path)
|
||||
{
|
||||
SDL_RWops *file = SDL_RWFromFile(path, "rb");
|
||||
if (file != NULL) {
|
||||
// Read whole file into a buffer
|
||||
size_t bufferLength = (size_t)SDL_RWsize(file);
|
||||
uint8 *buffer = (uint8*)malloc(bufferLength);
|
||||
if (buffer == NULL) {
|
||||
log_error("Unable to allocate memory for track design file.");
|
||||
SDL_RWclose(file);
|
||||
return false;
|
||||
}
|
||||
SDL_RWread(file, buffer, bufferLength, 1);
|
||||
SDL_RWclose(file);
|
||||
|
||||
if (!sawyercoding_validate_track_checksum(buffer, bufferLength)) {
|
||||
log_error("Track checksum failed.");
|
||||
free(buffer);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Decode the track data
|
||||
uint8 *decoded = malloc(0x10000);
|
||||
size_t decodedLength = sawyercoding_decode_td6(buffer, decoded, bufferLength);
|
||||
free(buffer);
|
||||
decoded = realloc(decoded, decodedLength);
|
||||
if (decoded == NULL) {
|
||||
log_error("failed to realloc");
|
||||
} else {
|
||||
track_design_open_from_buffer(td6, decoded, decodedLength);
|
||||
free(decoded);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool track_design_open_from_buffer(rct_track_td6 *td6, uint8 *src, size_t srcLength)
|
||||
{
|
||||
uint8 *readPtr = src;
|
||||
|
||||
// Clear top of track_design as this is not loaded from the td4 files
|
||||
memset(&td6->track_spine_colour, 0, 67);
|
||||
|
||||
// Read start of track_design
|
||||
copy(td6, &readPtr, 32);
|
||||
|
||||
uint8 version = td6->version_and_colour_scheme >> 2;
|
||||
if (version > 2) {
|
||||
log_error("Unsupported track design.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// In TD6 there are 32 sets of two byte vehicle colour specifiers
|
||||
// In TD4 there are 12 sets so the remaining 20 need to be read
|
||||
if (version == 2) {
|
||||
copy(&td6->vehicle_colours[12], &readPtr, 40);
|
||||
}
|
||||
|
||||
copy(&td6->pad_48, &readPtr, 24);
|
||||
|
||||
// In TD4 (version AA/CF) and TD6 both start actual track data at 0xA3
|
||||
if (version > 0) {
|
||||
copy(&td6->track_spine_colour, &readPtr, version == 1 ? 140 : 67);
|
||||
}
|
||||
|
||||
// Read the actual track data to memory directly after the passed in TD6 struct
|
||||
size_t elementDataLength = srcLength - (readPtr - src);
|
||||
uint8 *elementData = malloc(elementDataLength);
|
||||
if (elementData == NULL) {
|
||||
log_error("Unable to allocate memory for TD6 element data.");
|
||||
return false;
|
||||
}
|
||||
copy(elementData, &readPtr, elementDataLength);
|
||||
td6->elements = elementData;
|
||||
td6->elementsSize = elementDataLength;
|
||||
|
||||
uint8 *final_track_element_location = elementData + elementDataLength;
|
||||
|
||||
// TD4 files require some extra work to be recognised as TD6.
|
||||
if (version < 2) {
|
||||
// Set any element passed the tracks to 0xFF
|
||||
if (td6->type == RIDE_TYPE_MAZE) {
|
||||
rct_maze_element* maze_element = (rct_maze_element*)elementData;
|
||||
while (maze_element->all != 0) {
|
||||
maze_element++;
|
||||
}
|
||||
maze_element++;
|
||||
memset(maze_element, 255, final_track_element_location - (uint8*)maze_element);
|
||||
} else {
|
||||
rct_track_element* track_element = (rct_track_element*)elementData;
|
||||
while (track_element->type != 255) {
|
||||
track_element++;
|
||||
}
|
||||
memset(((uint8*)track_element) + 1, 255, final_track_element_location - (uint8*)track_element);
|
||||
}
|
||||
|
||||
// Convert the colours from RCT1 to RCT2
|
||||
for (int i = 0; i < 32; i++) {
|
||||
rct_vehicle_colour *vehicleColour = &td6->vehicle_colours[i];
|
||||
vehicleColour->body_colour = rct1_get_colour(vehicleColour->body_colour);
|
||||
vehicleColour->trim_colour = rct1_get_colour(vehicleColour->trim_colour);
|
||||
}
|
||||
|
||||
td6->track_spine_colour_rct1 = rct1_get_colour(td6->track_spine_colour_rct1);
|
||||
td6->track_rail_colour_rct1 = rct1_get_colour(td6->track_rail_colour_rct1);
|
||||
td6->track_support_colour_rct1 = rct1_get_colour(td6->track_support_colour_rct1);
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
td6->track_spine_colour[i] = rct1_get_colour(td6->track_spine_colour[i]);
|
||||
td6->track_rail_colour[i] = rct1_get_colour(td6->track_rail_colour[i]);
|
||||
td6->track_support_colour[i] = rct1_get_colour(td6->track_support_colour[i]);
|
||||
}
|
||||
|
||||
// Highest drop height is 1bit = 3/4 a meter in TD6
|
||||
// Highest drop height is 1bit = 1/3 a meter in TD4
|
||||
// Not sure if this is correct??
|
||||
td6->highest_drop_height >>= 1;
|
||||
|
||||
// If it has boosters then sadly track has to be discarded.
|
||||
if (td4_track_has_boosters(td6, elementData)) {
|
||||
log_error("Track design contains RCT1 boosters which are not yet supported.");
|
||||
free(td6->elements);
|
||||
td6->elements = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Convert RCT1 ride type to RCT2 ride type
|
||||
uint8 rct1RideType = td6->type;
|
||||
if (rct1RideType == RCT1_RIDE_TYPE_WOODEN_ROLLER_COASTER) {
|
||||
td6->type = RIDE_TYPE_WOODEN_ROLLER_COASTER;
|
||||
} else if (rct1RideType == RCT1_RIDE_TYPE_STEEL_CORKSCREW_ROLLER_COASTER) {
|
||||
if (td6->vehicle_type == RCT1_VEHICLE_TYPE_HYPERCOASTER_TRAIN) {
|
||||
if (td6->ride_mode == RCT1_RIDE_MODE_REVERSE_INCLINE_LAUNCHED_SHUTTLE) {
|
||||
td6->ride_mode = RIDE_MODE_CONTINUOUS_CIRCUIT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// All TD4s that use powered launch use the type that doesn't pass the station.
|
||||
if (td6->ride_mode == RCT1_RIDE_MODE_POWERED_LAUNCH) {
|
||||
td6->ride_mode = RIDE_MODE_POWERED_LAUNCH;
|
||||
}
|
||||
|
||||
// Convert RCT1 vehicle type to RCT2 vehicle type
|
||||
rct_object_entry *vehicle_object;
|
||||
if (td6->type == RIDE_TYPE_MAZE) {
|
||||
vehicle_object = RCT2_ADDRESS(0x0097F66C, rct_object_entry);
|
||||
} else {
|
||||
int vehicle_type = td6->vehicle_type;
|
||||
if (vehicle_type == RCT1_VEHICLE_TYPE_INVERTED_COASTER_TRAIN &&
|
||||
td6->type == RIDE_TYPE_INVERTED_ROLLER_COASTER
|
||||
) {
|
||||
vehicle_type = RCT1_VEHICLE_TYPE_4_ACROSS_INVERTED_COASTER_TRAIN;
|
||||
}
|
||||
vehicle_object = &RCT2_ADDRESS(0x0097F0DC, rct_object_entry)[vehicle_type];
|
||||
}
|
||||
memcpy(&td6->vehicle_object, vehicle_object, sizeof(rct_object_entry));
|
||||
|
||||
// Further vehicle colour fixes
|
||||
for (int i = 0; i < 32; i++) {
|
||||
td6->vehicle_additional_colour[i] = td6->vehicle_colours[i].trim_colour;
|
||||
|
||||
// RCT1 river rapids always had black seats.
|
||||
if (rct1RideType == RCT1_RIDE_TYPE_RIVER_RAPIDS) {
|
||||
td6->vehicle_colours[i].trim_colour = COLOUR_BLACK;
|
||||
}
|
||||
}
|
||||
|
||||
td6->space_required_x = 255;
|
||||
td6->space_required_y = 255;
|
||||
td6->lift_hill_speed_num_circuits = 5;
|
||||
}
|
||||
|
||||
td6->var_50 = min(
|
||||
td6->var_50,
|
||||
RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + 5 + (td6->type * 8), uint8)
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -183,6 +183,8 @@ typedef struct {
|
|||
uint8 space_required_y; // 0x81
|
||||
uint8 vehicle_additional_colour[32]; // 0x82
|
||||
uint8 lift_hill_speed_num_circuits; // 0xA2 0bCCCL_LLLL
|
||||
void *elements; // 0xA3 (data starts here in file)
|
||||
size_t elementsSize;
|
||||
} rct_track_td6;
|
||||
|
||||
typedef struct{
|
||||
|
@ -637,4 +639,7 @@ int track_get_actual_bank_3(rct_vehicle *vehicle, rct_map_element *mapElement);
|
|||
bool track_element_is_station(rct_map_element *trackElement);
|
||||
bool track_element_is_covered(int trackElementType);
|
||||
|
||||
bool track_design_open(rct_track_td6 *td6, const utf8 *path);
|
||||
void track_design_index_create();
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,152 @@
|
|||
#include "../common.h"
|
||||
#include "../config.h"
|
||||
#include "../util/util.h"
|
||||
#include "track.h"
|
||||
|
||||
typedef struct {
|
||||
uint8 ride_type;
|
||||
char ride_entry[9];
|
||||
utf8 path[MAX_PATH];
|
||||
} td_index_item;
|
||||
|
||||
static void track_design_index_scan();
|
||||
static int track_design_index_item_compare(const void *a, const void *b);
|
||||
static void track_design_index_include(const utf8 *directory);
|
||||
static void track_design_add_file(const utf8 *path);
|
||||
static void track_design_add(const td_index_item *item);
|
||||
static void track_design_index_dispose();
|
||||
static void track_design_index_get_path(utf8 * buffer, size_t bufferLength);
|
||||
|
||||
static const uint32 TrackIndexMagicNumber = 0x58444954;
|
||||
static const uint16 TrackIndexVersion = 0;
|
||||
|
||||
static td_index_item *_tdIndex = NULL;
|
||||
static size_t _tdIndexSize = 0;
|
||||
static size_t _tdIndexCapacity = 0;
|
||||
|
||||
void track_design_index_create()
|
||||
{
|
||||
track_design_index_dispose();
|
||||
|
||||
log_verbose("saving track list index (tracks.idx)");
|
||||
|
||||
utf8 path[MAX_PATH];
|
||||
track_design_index_get_path(path, sizeof(path));
|
||||
|
||||
SDL_RWops *file = SDL_RWFromFile(path, "wb");
|
||||
if (file != NULL) {
|
||||
track_design_index_scan();
|
||||
|
||||
SDL_RWwrite(file, &TrackIndexMagicNumber, 4, 1);
|
||||
SDL_RWwrite(file, &TrackIndexVersion, 4, 1);
|
||||
SDL_RWwrite(file, &_tdIndexSize, 4, 1);
|
||||
SDL_RWwrite(file, _tdIndex, sizeof(td_index_item), _tdIndexSize);
|
||||
SDL_RWclose(file);
|
||||
track_design_index_dispose();
|
||||
}
|
||||
}
|
||||
|
||||
static void track_design_index_scan()
|
||||
{
|
||||
utf8 directory[MAX_PATH];
|
||||
|
||||
// Get track directory from RCT2
|
||||
safe_strcpy(directory, gConfigGeneral.game_path, sizeof(directory));
|
||||
safe_strcat_path(directory, "Tracks", sizeof(directory));
|
||||
track_design_index_include(directory);
|
||||
|
||||
// Get track directory from user directory
|
||||
platform_get_user_directory(directory, "tracks");
|
||||
track_design_index_include(directory);
|
||||
|
||||
// Sort items by ride type then by filename
|
||||
qsort(_tdIndex, _tdIndexSize, sizeof(td_index_item), track_design_index_item_compare);
|
||||
}
|
||||
|
||||
static int track_design_index_item_compare(const void *a, const void *b)
|
||||
{
|
||||
const td_index_item *tdA = (const td_index_item*)a;
|
||||
const td_index_item *tdB = (const td_index_item*)b;
|
||||
|
||||
if (tdA->ride_type != tdB->ride_type) {
|
||||
return tdA->ride_type - tdB->ride_type;
|
||||
}
|
||||
|
||||
const utf8 *tdAName = path_get_filename(tdA->path);
|
||||
const utf8 *tdBName = path_get_filename(tdB->path);
|
||||
return strcmp(tdAName, tdBName);
|
||||
}
|
||||
|
||||
static void track_design_index_include(const utf8 *directory)
|
||||
{
|
||||
int handle;
|
||||
file_info fileInfo;
|
||||
|
||||
// Scenarios in this directory
|
||||
utf8 pattern[MAX_PATH];
|
||||
safe_strcpy(pattern, directory, sizeof(pattern));
|
||||
safe_strcat_path(pattern, "*.td6", sizeof(pattern));
|
||||
|
||||
handle = platform_enumerate_files_begin(pattern);
|
||||
while (platform_enumerate_files_next(handle, &fileInfo)) {
|
||||
utf8 path[MAX_PATH];
|
||||
safe_strcpy(path, directory, sizeof(pattern));
|
||||
safe_strcat_path(path, fileInfo.path, sizeof(pattern));
|
||||
track_design_add_file(path);
|
||||
}
|
||||
platform_enumerate_files_end(handle);
|
||||
|
||||
// Include sub-directories
|
||||
utf8 subDirectory[MAX_PATH];
|
||||
handle = platform_enumerate_directories_begin(directory);
|
||||
while (platform_enumerate_directories_next(handle, subDirectory)) {
|
||||
utf8 path[MAX_PATH];
|
||||
safe_strcpy(path, directory, sizeof(pattern));
|
||||
safe_strcat_path(path, subDirectory, sizeof(pattern));
|
||||
track_design_index_include(path);
|
||||
}
|
||||
platform_enumerate_directories_end(handle);
|
||||
}
|
||||
|
||||
static void track_design_add_file(const utf8 *path)
|
||||
{
|
||||
rct_track_td6 td6;
|
||||
if (track_design_open(&td6, path)) {
|
||||
td_index_item tdIndexItem = { 0 };
|
||||
safe_strcpy(tdIndexItem.path, path, sizeof(tdIndexItem.path));
|
||||
memcpy(tdIndexItem.ride_entry, td6.vehicle_object.name, 8);
|
||||
tdIndexItem.ride_type = td6.type;
|
||||
track_design_add(&tdIndexItem);
|
||||
|
||||
free(td6.elements);
|
||||
}
|
||||
}
|
||||
|
||||
static void track_design_add(const td_index_item *item)
|
||||
{
|
||||
size_t nextIndex = _tdIndexSize;
|
||||
if (nextIndex >= _tdIndexCapacity) {
|
||||
_tdIndexCapacity = max(128, _tdIndexCapacity * 2);
|
||||
_tdIndex = realloc(_tdIndex, _tdIndexCapacity * sizeof(td_index_item));
|
||||
if (_tdIndex == NULL) {
|
||||
log_fatal("Unable to allocate more memory.");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
_tdIndex[nextIndex] = *item;
|
||||
_tdIndexSize++;
|
||||
}
|
||||
|
||||
static void track_design_index_dispose()
|
||||
{
|
||||
free(_tdIndex);
|
||||
_tdIndexSize = 0;
|
||||
_tdIndexCapacity = 0;
|
||||
}
|
||||
|
||||
static void track_design_index_get_path(utf8 * buffer, size_t bufferLength)
|
||||
{
|
||||
platform_get_user_directory(buffer, NULL);
|
||||
safe_strcat(buffer, "tracks.idx", bufferLength);
|
||||
}
|
||||
|
Loading…
Reference in New Issue