1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-02-01 11:15:13 +01:00

Convert track repository to C++

This commit is contained in:
Ted John
2016-10-22 17:06:27 +01:00
parent 91d4058850
commit e666028e02
14 changed files with 471 additions and 398 deletions

View File

@@ -240,11 +240,11 @@
<ClCompile Include="src\ride\thrill\top_spin.c" />
<ClCompile Include="src\ride\thrill\twist.c" />
<ClCompile Include="src\ride\track.c" />
<ClCompile Include="src\ride\TrackDesignRepository.cpp" />
<ClCompile Include="src\ride\track_data.c" />
<ClCompile Include="src\ride\track_data_old.c" />
<ClCompile Include="src\ride\track_design.c" />
<ClCompile Include="src\ride\track_design_save.c" />
<ClCompile Include="src\ride\track_design_index.c" />
<ClCompile Include="src\ride\track_paint.c" />
<ClCompile Include="src\ride\transport\chairlift.c" />
<ClCompile Include="src\ride\transport\lift.c" />
@@ -492,6 +492,7 @@
<ClInclude Include="src\ride\ride_ratings.h" />
<ClInclude Include="src\ride\station.h" />
<ClInclude Include="src\ride\track.h" />
<ClInclude Include="src\ride\TrackDesignRepository.h" />
<ClInclude Include="src\ride\track_data.h" />
<ClInclude Include="src\ride\track_design.h" />
<ClInclude Include="src\ride\track_paint.h" />

View File

@@ -31,6 +31,8 @@
struct rct_window;
union rct_window_event;
struct track_design_file_ref;
extern uint16 TextInputDescriptionArgs[4];
extern char gTextBoxInput[512];
extern int gMaxTextBoxInputLength;
@@ -677,7 +679,7 @@ void ride_construction_tooldown_construct(int screenX, int screenY);
void custom_currency_window_open();
void window_maze_construction_update_pressed_widgets();
void window_track_place_open(const track_design_file_ref *tdFileRef);
void window_track_place_open(const struct track_design_file_ref *tdFileRef);
rct_window *window_new_ride_open();
rct_window *window_new_ride_open_research();
void window_install_track_open(const char* path);
@@ -701,7 +703,7 @@ void window_research_funding_page_paint(rct_window *w, rct_drawpixelinfo *dpi, i
void window_scenery_open();
void window_music_credits_open();
void window_publisher_credits_open();
void window_track_manage_open(track_design_file_ref *tdFileRef);
void window_track_manage_open(struct track_design_file_ref *tdFileRef);
void window_viewport_open();
void window_themes_open();
void window_title_editor_open(int tab);

View File

@@ -42,6 +42,7 @@
#include "ride/ride.h"
#include "ride/track.h"
#include "ride/track_design.h"
#include "ride/TrackDesignRepository.h"
#include "ScenarioRepository.h"
#include "title.h"
#include "util/util.h"
@@ -166,7 +167,7 @@ bool rct2_init()
object_list_load();
scenario_repository_scan();
track_design_index_create();
track_repository_scan();
font_sprite_initialise_characters();
if (!gOpenRCT2Headless) {

View File

@@ -0,0 +1,367 @@
#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers
/*****************************************************************************
* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
*
* OpenRCT2 is the work of many authors, a full list can be found in contributors.md
* For more information, visit https://github.com/OpenRCT2/OpenRCT2
*
* OpenRCT2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* A full copy of the GNU General Public License can be found in licence.txt
*****************************************************************************/
#pragma endregion
#include <algorithm>
#include <memory>
#include <vector>
#include "../core/Console.hpp"
#include "../core/FileEnumerator.h"
#include "../core/FileStream.hpp"
#include "../core/Path.hpp"
#include "../core/String.hpp"
#include "TrackDesignRepository.h"
extern "C"
{
#include "../platform/platform.h"
#include "track_design.h"
}
#define MAX_PATH 260
#pragma pack(push, 1)
struct TrackRepositoryHeader
{
uint32 MagicNumber;
uint16 Version;
uint32 NumItems;
};
#pragma pack(pop)
#pragma pack(push, 1)
typedef struct td_index_item {
uint8 ride_type;
char ride_entry[9];
utf8 path[MAX_PATH];
} td_index_item;
// NOTE: this is our own struct and should not get packed, but it is stored in a file
// so removing packing from it would require refactoring file access
assert_struct_size(td_index_item, 1 + 9 + 260);
#pragma pack(pop)
constexpr uint32 TRACK_REPOISTORY_MAGIC_NUMBER = 0x58444954;
constexpr uint16 TRACK_REPOISTORY_VERSION = 0;
class TrackDesignRepository : public ITrackDesignRepository
{
private:
std::vector<td_index_item> _items;
public:
virtual ~TrackDesignRepository()
{
}
size_t GetCount() const override
{
return _items.size();
}
size_t GetCountForObjectEntry(uint8 rideType, const utf8 * entry) const override
{
size_t count = 0;
for (const auto item : _items)
{
if (item.ride_type == rideType &&
(entry == nullptr || String::Equals(item.ride_entry, entry, true)))
{
count++;
}
}
return count;
}
size_t GetItemsForObjectEntry(track_design_file_ref * * outRefs, uint8 rideType, const utf8 * entry) const override
{
std::vector<track_design_file_ref> refs;
for (const auto item : _items)
{
if (item.ride_type == rideType &&
(entry == nullptr || String::Equals(item.ride_entry, entry, true)))
{
track_design_file_ref ref;
ref.name = GetNameFromTrackPath(item.path);
ref.path = String::Duplicate(item.path);
refs.push_back(ref);
}
}
*outRefs = nullptr;
if (refs.size() != 0)
{
*outRefs = Memory::DuplicateArray(refs.data(), refs.size());
}
return refs.size();
}
void Scan() override
{
utf8 directory[MAX_PATH];
GetRCT2Directory(directory, sizeof(directory));
Scan(directory);
GetUserDirectory(directory, sizeof(directory));
Scan(directory);
SortItems();
Save();
}
bool Delete(const utf8 * path) override
{
bool result = false;
if (platform_file_delete(path))
{
size_t index = GetTrackIndex(path);
if (index != SIZE_MAX)
{
_items.erase(_items.begin() + index);
}
}
return result;
}
const utf8 * Rename(const utf8 * path, const utf8 * newName) override
{
utf8 * result = nullptr;
size_t index = GetTrackIndex(path);
if (index != SIZE_MAX)
{
td_index_item * item = &_items[index];
utf8 newPath[MAX_PATH];
Path::GetDirectory(newPath, sizeof(newPath), path);
Path::Append(newPath, sizeof(newPath), newName);
Path::Append(newPath, sizeof(newPath), ".td6");
if (platform_file_move(path, newPath))
{
String::Set(item->path, sizeof(item->path), newPath);
SortItems();
item = GetTrackItem(path);
if (item != nullptr)
{
result = item->path;
}
}
}
return result;
}
const utf8 * Install(const utf8 * path) override
{
const utf8 * result = nullptr;
const utf8 * fileName = Path::GetFileName(path);
utf8 newPath[MAX_PATH];
GetUserDirectory(newPath, sizeof(newPath));
Path::Append(newPath, sizeof(newPath), fileName);
if (platform_file_copy(path, newPath, false))
{
AddTrack(path);
SortItems();
const td_index_item * item = GetTrackItem(path);
if (item != nullptr)
{
result = item->path;
}
}
return result;
}
private:
void Scan(const utf8 * directory)
{
utf8 pattern[MAX_PATH];
String::Set(pattern, sizeof(pattern), directory);
Path::Append(pattern, sizeof(pattern), "*.td6");
auto fileEnumerator = FileEnumerator(pattern, true);
while (fileEnumerator.Next())
{
const utf8 * path = fileEnumerator.GetPath();
AddTrack(path);
}
}
void AddTrack(const utf8 * path)
{
rct_track_td6 * td6 = track_design_open(path);
if (td6 != nullptr)
{
td_index_item tdIndexItem = { 0 };
String::Set(tdIndexItem.path, sizeof(tdIndexItem.path), path);
memcpy(tdIndexItem.ride_entry, td6->vehicle_object.name, 8);
tdIndexItem.ride_type = td6->type;
_items.push_back(tdIndexItem);
track_design_dispose(td6);
}
}
void SortItems()
{
std::sort(_items.begin(), _items.end(), [](const td_index_item &a,
const td_index_item &b) -> bool
{
if (a.ride_type != b.ride_type)
{
return a.ride_type < b.ride_type;
}
const utf8 * nameA = Path::GetFileName(a.path);
const utf8 * nameB = Path::GetFileName(b.path);
return _stricmp(nameA, nameB) < 0;
});
}
void Save() const
{
utf8 path[MAX_PATH];
GetRepositoryPath(path, sizeof(path));
try
{
auto fs = FileStream(path, FILE_MODE_WRITE);
// Write header
TrackRepositoryHeader header = { 0 };
header.MagicNumber = TRACK_REPOISTORY_MAGIC_NUMBER;
header.Version = TRACK_REPOISTORY_VERSION;
header.NumItems = (uint32)_items.size();
fs.WriteValue(header);
// Write items
fs.WriteArray(_items.data(), _items.size());
}
catch (Exception ex)
{
Console::Error::WriteLine("Unable to write object repository index.");
}
}
size_t GetTrackIndex(const utf8 * path) const
{
for (size_t i = 0; i < _items.size(); i++)
{
if (Path::Equals(_items[i].path, path))
{
return i;
}
}
return SIZE_MAX;
}
td_index_item * GetTrackItem(const utf8 * path)
{
td_index_item * result = nullptr;
size_t index = GetTrackIndex(path);
if (index != SIZE_MAX)
{
result = &_items[index];
}
return result;
}
utf8 * GetRCT2Directory(utf8 * buffer, size_t bufferSize) const
{
String::Set(buffer, bufferSize, gRCT2AddressAppPath);
Path::Append(buffer, bufferSize, "Tracks");
return buffer;
}
utf8 * GetUserDirectory(utf8 * buffer, size_t bufferSize) const
{
platform_get_user_directory(buffer, "track", bufferSize);
return buffer;
}
utf8 * GetRepositoryPath(utf8 * buffer, size_t bufferSize) const
{
platform_get_user_directory(buffer, nullptr, bufferSize);
Path::Append(buffer, bufferSize, "tracks.idx");
return buffer;
}
public:
static utf8 * GetNameFromTrackPath(const utf8 * path)
{
utf8 * name = Memory::Allocate<utf8>(MAX_PATH);
Path::GetFileNameWithoutExtension(name, MAX_PATH, path);
name = Memory::ReallocateArray(name, String::SizeOf(name) + 1);
return name;
}
};
static std::unique_ptr<TrackDesignRepository> _trackRepository;
ITrackDesignRepository * GetTrackRepository()
{
if (_trackRepository == nullptr)
{
_trackRepository = std::unique_ptr<TrackDesignRepository>(new TrackDesignRepository());
}
return _trackRepository.get();
}
extern "C"
{
void track_repository_scan()
{
ITrackDesignRepository * repo = GetTrackRepository();
repo->Scan();
}
size_t track_repository_get_count_for_ride(uint8 rideType, const utf8 * entry)
{
ITrackDesignRepository * repo = GetTrackRepository();
return repo->GetCountForObjectEntry(rideType, entry);
}
size_t track_repository_get_items_for_ride(track_design_file_ref * * outRefs, uint8 rideType, const utf8 * entry)
{
ITrackDesignRepository * repo = GetTrackRepository();
return repo->GetItemsForObjectEntry(outRefs, rideType, entry);
}
bool track_repository_delete(const utf8 * path)
{
ITrackDesignRepository * repo = GetTrackRepository();
return repo->Delete(path);
}
const utf8 * track_repository_rename(const utf8 * path, const utf8 * newName)
{
ITrackDesignRepository * repo = GetTrackRepository();
return repo->Rename(path, newName);
}
const utf8 * track_repository_install(const utf8 * srcPath)
{
ITrackDesignRepository * repo = GetTrackRepository();
return repo->Install(srcPath);
}
utf8 * track_repository_get_name_from_path(const utf8 * path)
{
return TrackDesignRepository::GetNameFromTrackPath(path);
}
}

View File

@@ -0,0 +1,60 @@
#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers
/*****************************************************************************
* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
*
* OpenRCT2 is the work of many authors, a full list can be found in contributors.md
* For more information, visit https://github.com/OpenRCT2/OpenRCT2
*
* OpenRCT2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* A full copy of the GNU General Public License can be found in licence.txt
*****************************************************************************/
#pragma endregion
#include "../common.h"
typedef struct track_design_file_ref
{
utf8 * name;
utf8 * path;
} track_design_file_ref;
#ifdef __cplusplus
interface ITrackDesignRepository
{
virtual ~ITrackDesignRepository() = default;
virtual size_t GetCount() const abstract;
virtual size_t GetCountForObjectEntry(uint8 rideType, const utf8 * entry) const abstract;
virtual size_t GetItemsForObjectEntry(track_design_file_ref * * outRefs,
uint8 rideType,
const utf8 * entry) const abstract;
virtual void Scan() abstract;
virtual bool Delete(const utf8 * path) abstract;
virtual const utf8 * Rename(const utf8 * path, const utf8 * newName) abstract;
virtual const utf8 * Install(const utf8 * path) abstract;
};
ITrackDesignRepository * GetTrackRepository();
#endif
#ifdef __cplusplus
extern "C"
{
#endif
void track_repository_scan();
size_t track_repository_get_count_for_ride(uint8 rideType, const utf8 * entry);
size_t track_repository_get_items_for_ride(track_design_file_ref * * outRefs, uint8 rideType, const utf8 * entry);
utf8 * track_repository_get_name_from_path(const utf8 *path);
bool track_repository_delete(const utf8 *path);
const utf8 * track_repository_rename(const utf8 *path, const utf8 *newName);
const utf8 * track_repository_install(const utf8 *srcPath);
#ifdef __cplusplus
}
#endif

View File

@@ -31,9 +31,10 @@
#include "../world/scenery.h"
#include "ride.h"
#include "ride_data.h"
#include "track.h"
#include "track_data.h"
#include "track_design.h"
#include "track.h"
#include "TrackDesignRepository.h"
typedef struct map_backup {
rct_map_element map_elements[MAX_MAP_ELEMENTS];
@@ -107,7 +108,7 @@ rct_track_td6 *track_design_open(const utf8 *path)
free(decoded);
if (td6 != NULL) {
td6->name = track_design_get_name_from_path(path);
td6->name = track_repository_get_name_from_path(path);
return td6;
}
}

View File

@@ -152,11 +152,6 @@ assert_struct_size(rct_track_td6, 0xbf);
#endif
#pragma pack(pop)
typedef struct track_design_file_ref {
utf8 *name;
utf8 *path;
} track_design_file_ref;
enum {
TRACK_FLAGS2_CONTAINS_LOG_FLUME_REVERSER = (1 << 1),
TRACK_FLAGS2_SIX_FLAGS_RIDE_DEPRECATED = (1u << 31) // Not used anymore.
@@ -205,14 +200,6 @@ void track_design_mirror(rct_track_td6 *td6);
int sub_6D01B3(rct_track_td6 *td6, uint8 bl, uint8 rideIndex, int x, int y, int z);
void track_design_index_create();
size_t track_design_index_get_count_for_ride(uint8 rideType, const char *entry);
size_t track_design_index_get_for_ride(track_design_file_ref **tdRefs, uint8 rideType, const char *entry);
utf8 *track_design_get_name_from_path(const utf8 *path);
bool track_design_index_rename(const utf8 *path, const utf8 *newName);
bool track_design_index_delete(const utf8 *path);
bool track_design_index_install(const utf8 *srcPath, const utf8 *destPath);
void game_command_place_track_design(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp);
void game_command_place_maze_design(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp);

View File

@@ -1,365 +0,0 @@
#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers
/*****************************************************************************
* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
*
* OpenRCT2 is the work of many authors, a full list can be found in contributors.md
* For more information, visit https://github.com/OpenRCT2/OpenRCT2
*
* OpenRCT2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* A full copy of the GNU General Public License can be found in licence.txt
*****************************************************************************/
#pragma endregion
#include "../common.h"
#include "../config.h"
#include "../game.h"
#include "../interface/window.h"
#include "../localisation/string_ids.h"
#include "../util/util.h"
#include "track.h"
#include "track_design.h"
#pragma pack(push, 1)
typedef struct td_index_item {
uint8 ride_type;
char ride_entry[9];
utf8 path[MAX_PATH];
} td_index_item;
// NOTE: this is our own struct and should not get packed, but it is stored in a file
// so removing packing from it would require refactoring file access
assert_struct_size(td_index_item, 1 + 9 + 260);
#pragma pack(pop)
static bool track_design_index_read_header(SDL_RWops *file, uint32 *tdidxCount);
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 design 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, sizeof(TrackIndexMagicNumber), 1);
SDL_RWwrite(file, &TrackIndexVersion, sizeof(TrackIndexVersion), 1);
SDL_RWwrite(file, &_tdIndexSize, sizeof(uint32), 1);
SDL_RWwrite(file, _tdIndex, sizeof(td_index_item), _tdIndexSize);
SDL_RWclose(file);
track_design_index_dispose();
}
}
size_t track_design_index_get_count_for_ride(uint8 rideType, const char *entry)
{
log_verbose("reading track design index (tracks.idx)");
utf8 path[MAX_PATH];
track_design_index_get_path(path, sizeof(path));
// Return list
size_t refsCount = 0;
SDL_RWops *file = SDL_RWFromFile(path, "rb");
if (file != NULL) {
uint32 tdidxCount;
if (!track_design_index_read_header(file, &tdidxCount)) {
SDL_RWclose(file);
return 0;
}
for (uint32 i = 0; i < tdidxCount; i++) {
td_index_item tdItem;
SDL_RWread(file, &tdItem, sizeof(td_index_item), 1);
if (tdItem.ride_type != rideType) continue;
if (entry != NULL && _strcmpi(entry, tdItem.ride_entry) != 0) continue;
refsCount++;
}
SDL_RWclose(file);
}
return refsCount;
}
size_t track_design_index_get_for_ride(track_design_file_ref **tdRefs, uint8 rideType, const char *entry)
{
log_verbose("reading track design index (tracks.idx)");
utf8 path[MAX_PATH];
track_design_index_get_path(path, sizeof(path));
// Return list
size_t refsCount = 0;
size_t refsCapacity = 0;
track_design_file_ref *refs = NULL;
SDL_RWops *file = SDL_RWFromFile(path, "rb");
if (file != NULL) {
uint32 tdidxCount;
if (!track_design_index_read_header(file, &tdidxCount)) {
SDL_RWclose(file);
return 0;
}
for (uint32 i = 0; i < tdidxCount; i++) {
td_index_item tdItem;
SDL_RWread(file, &tdItem, sizeof(td_index_item), 1);
if (tdItem.ride_type != rideType) continue;
if (entry != NULL && _strcmpi(entry, tdItem.ride_entry) != 0) continue;
size_t nextIndex = refsCount;
if (nextIndex >= refsCapacity) {
refsCapacity = max(8, refsCapacity * 2);
refs = realloc(refs, refsCapacity * sizeof(track_design_file_ref));
if (refs == NULL) {
log_fatal("Unable to allocate more memory.");
exit(-1);
}
}
refs[nextIndex].name = track_design_get_name_from_path(tdItem.path);
refs[nextIndex].path = _strdup(tdItem.path);
refsCount++;
}
SDL_RWclose(file);
}
*tdRefs = realloc(refs, refsCount * sizeof(track_design_file_ref));
return refsCount;
}
utf8 *track_design_get_name_from_path(const utf8 *path)
{
const char *filename = path_get_filename(path);
const char *lastDot = strrchr(filename, '.');
size_t nameLength;
if (lastDot == NULL) {
nameLength = strlen(filename);
} else {
nameLength = (size_t)(lastDot - filename);
}
return strndup(filename, nameLength);
}
/**
*
* rct2: 0x006D3664
*/
bool track_design_index_rename(const utf8 *path, const utf8 *newName)
{
if (str_is_null_or_empty(newName)) {
gGameCommandErrorText = STR_CANT_RENAME_TRACK_DESIGN;
return false;
}
if (!filename_valid_characters(newName)) {
gGameCommandErrorText = STR_NEW_NAME_CONTAINS_INVALID_CHARACTERS;
return false;
}
utf8 newPath[MAX_PATH];
const char *lastPathSep = strrchr(path, *PATH_SEPARATOR);
if (lastPathSep == NULL) {
gGameCommandErrorText = STR_CANT_RENAME_TRACK_DESIGN;
return false;
}
size_t directoryLength = (size_t)(lastPathSep - path + 1);
memcpy(newPath, path, directoryLength);
safe_strcpy(newPath + directoryLength, newName, sizeof(newPath) - directoryLength);
path_append_extension(newPath, ".td6", sizeof(newPath));
if (!platform_file_move(path, newPath)) {
gGameCommandErrorText = STR_ANOTHER_FILE_EXISTS_WITH_NAME_OR_FILE_IS_WRITE_PROTECTED;
return false;
}
track_design_index_create();
rct_window *trackListWindow = window_find_by_class(WC_TRACK_DESIGN_LIST);
if (trackListWindow != NULL) {
trackListWindow->track_list.reload_track_designs = true;
}
return true;
}
/**
*
* rct2: 0x006D3761
*/
bool track_design_index_delete(const utf8 *path)
{
if (!platform_file_delete(path)) {
gGameCommandErrorText = STR_FILE_IS_WRITE_PROTECTED_OR_LOCKED;
return false;
}
track_design_index_create();
rct_window *trackListWindow = window_find_by_class(WC_TRACK_DESIGN_LIST);
if (trackListWindow != NULL) {
trackListWindow->track_list.reload_track_designs = true;
}
return true;
}
/**
*
* rct2: 0x006D40B2
*/
bool track_design_index_install(const utf8 *srcPath, const utf8 *destPath)
{
if (!platform_file_copy(srcPath, destPath, false)) {
return false;
}
track_design_index_create();
rct_window *trackListWindow = window_find_by_class(WC_TRACK_DESIGN_LIST);
if (trackListWindow != NULL) {
trackListWindow->track_list.reload_track_designs = true;
}
return true;
}
static bool track_design_index_read_header(SDL_RWops *file, uint32 *tdidxCount)
{
uint32 tdidxMagicNumber;
uint16 tdidxVersion;
SDL_RWread(file, &tdidxMagicNumber, sizeof(tdidxMagicNumber), 1);
SDL_RWread(file, &tdidxVersion, sizeof(tdidxVersion), 1);
SDL_RWread(file, tdidxCount, sizeof(uint32), 1);
if (tdidxMagicNumber != TrackIndexMagicNumber) {
log_error("invalid track index file");
return false;
}
if (tdidxVersion != TrackIndexVersion) {
log_error("unsupported track index file version");
return false;
}
return true;
}
static void track_design_index_scan()
{
utf8 directory[MAX_PATH];
// Get track directory from RCT2
safe_strcpy(directory, gRCT2AddressAppPath, 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, "track", sizeof(directory));
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 _stricmp(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 = track_design_open(path);
if (td6 != NULL) {
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);
track_design_dispose(td6);
}
}
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()
{
SafeFree(_tdIndex);
_tdIndexSize = 0;
_tdIndexCapacity = 0;
}
static void track_design_index_get_path(utf8 * buffer, size_t bufferLength)
{
platform_get_user_directory(buffer, NULL, bufferLength);
safe_strcat_path(buffer, "tracks.idx", bufferLength);
}

View File

@@ -28,6 +28,7 @@
#include "track.h"
#include "track_data.h"
#include "track_design.h"
#include "TrackDesignRepository.h"
#define TRACK_MAX_SAVED_MAP_ELEMENTS 1500
@@ -128,7 +129,7 @@ static void track_design_save_callback(int result) {
free(_trackDesign);
if (result == MODAL_RESULT_OK) {
track_design_index_create();
track_repository_scan();
}
gfx_invalidate_screen();
}

View File

@@ -23,6 +23,7 @@
#include "../ride/ride.h"
#include "../ride/track.h"
#include "../ride/track_design.h"
#include "../ride/TrackDesignRepository.h"
#include "../object/ObjectManager.h"
#include "../sprites.h"
#include "../util/util.h"
@@ -135,7 +136,7 @@ void window_install_track_open(const utf8 *path)
window_push_others_right(w);
_trackPath = _strdup(path);
_trackName = track_design_get_name_from_path(path);
_trackName = track_repository_get_name_from_path(path);
_trackDesignPreviewPixels = calloc(4, TRACK_PREVIEW_IMAGE_SIZE);
window_install_track_update_preview();
@@ -400,7 +401,7 @@ static void window_install_track_design(rct_window *w)
255
);
} else {
if (track_design_index_install(_trackPath, destPath)) {
if (track_repository_install(_trackPath)) {
window_close(w);
} else {
window_error_open(STR_CANT_SAVE_TRACK_DESIGN, STR_NONE);

View File

@@ -27,13 +27,14 @@
#include "../object.h"
#include "../rct1.h"
#include "../ride/ride.h"
#include "../ride/track.h"
#include "../ride/track_design.h"
#include "../world/scenery.h"
#include "../ride/ride_data.h"
#include "../sprites.h"
#include "../ride/track.h"
#include "../ride/track_data.h"
#include "../ride/track_design.h"
#include "../ride/TrackDesignRepository.h"
#include "../sprites.h"
#include "../util/util.h"
#include "../world/scenery.h"
static uint8 _windowNewRideCurrentTab;
static ride_list_item _windowNewRideHighlightedItem[6];
@@ -857,7 +858,7 @@ static int get_num_track_designs(ride_list_item item)
}
}
return (int)track_design_index_get_count_for_ride(item.type, entryPtr);
return (int)track_repository_get_count_for_ride(item.type, entryPtr);
}
/**

View File

@@ -25,6 +25,7 @@
#include "../ride/ride.h"
#include "../ride/track.h"
#include "../ride/track_design.h"
#include "../ride/TrackDesignRepository.h"
#include "../sprites.h"
#include "error.h"
@@ -139,7 +140,10 @@ void window_track_list_open(ride_list_item item)
w->track_list.var_480 = 0xFFFF;
w->track_list.var_484 = 0;
w->track_list.reload_track_designs = false;
w->selected_list_item = gScreenFlags & SCREEN_FLAGS_TRACK_MANAGER ? 0 : 1;
w->selected_list_item = 0;
if (_trackDesignsCount != 0 && !(gScreenFlags & SCREEN_FLAGS_TRACK_MANAGER)) {
w->selected_list_item = 1;
}
gTrackDesignSceneryToggle = false;
window_push_others_right(w);
_currentTrackPieceDirection = 2;
@@ -613,7 +617,7 @@ static void track_list_load_designs(ride_list_item item)
entryPtr = entry;
}
}
_trackDesignsCount = track_design_index_get_for_ride(&_trackDesigns, item.type, entryPtr);
_trackDesignsCount = track_repository_get_items_for_ride(&_trackDesigns, item.type, entryPtr);
}
static bool track_list_load_design_for_preview(utf8 *path)

View File

@@ -21,6 +21,7 @@
#include "../localisation/localisation.h"
#include "../ride/track.h"
#include "../ride/track_design.h"
#include "../ride/TrackDesignRepository.h"
#include "../util/util.h"
#include "error.h"
@@ -217,11 +218,21 @@ static void window_track_manage_textinput(rct_window *w, int widgetIndex, char *
return;
}
if (track_design_index_rename(_trackDesignFileReference->path, text)) {
if (str_is_null_or_empty(text)) {
window_error_open(STR_CANT_RENAME_TRACK_DESIGN, STR_NONE);
return;
}
if (!filename_valid_characters(text)) {
window_error_open(STR_CANT_RENAME_TRACK_DESIGN, STR_NEW_NAME_CONTAINS_INVALID_CHARACTERS);
return;
}
if (track_repository_rename(_trackDesignFileReference->path, text)) {
window_close_by_class(WC_TRACK_DELETE_PROMPT);
window_close(w);
} else {
window_error_open(STR_CANT_RENAME_TRACK_DESIGN, gGameCommandErrorText);
window_error_open(STR_CANT_RENAME_TRACK_DESIGN, STR_ANOTHER_FILE_EXISTS_WITH_NAME_OR_FILE_IS_WRITE_PROTECTED);
}
}
@@ -281,10 +292,10 @@ static void window_track_delete_prompt_mouseup(rct_window *w, int widgetIndex)
break;
case WIDX_PROMPT_DELETE:
window_close(w);
if (track_design_index_delete(_trackDesignFileReference->path)) {
if (track_repository_delete(_trackDesignFileReference->path)) {
window_close_by_class(WC_MANAGE_TRACK_DESIGN);
} else {
window_error_open(STR_CANT_DELETE_TRACK_DESIGN, gGameCommandErrorText);
window_error_open(STR_CANT_DELETE_TRACK_DESIGN, STR_FILE_IS_WRITE_PROTECTED_OR_LOCKED);
}
break;
}

View File

@@ -26,6 +26,7 @@
#include "../ride/track.h"
#include "../ride/track_data.h"
#include "../ride/track_design.h"
#include "../ride/TrackDesignRepository.h"
#include "../sprites.h"
#include "../util/util.h"