From e666028e0274be0c3c6195e691c96ffcfb897cd5 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 22 Oct 2016 17:06:27 +0100 Subject: [PATCH] Convert track repository to C++ --- openrct2.vcxproj | 3 +- src/interface/window.h | 6 +- src/rct2.c | 3 +- src/ride/TrackDesignRepository.cpp | 367 +++++++++++++++++++++++++++++ src/ride/TrackDesignRepository.h | 60 +++++ src/ride/track_design.c | 5 +- src/ride/track_design.h | 13 - src/ride/track_design_index.c | 365 ---------------------------- src/ride/track_design_save.c | 3 +- src/windows/install_track.c | 5 +- src/windows/new_ride.c | 11 +- src/windows/track_list.c | 8 +- src/windows/track_manage.c | 19 +- src/windows/track_place.c | 1 + 14 files changed, 471 insertions(+), 398 deletions(-) create mode 100644 src/ride/TrackDesignRepository.cpp create mode 100644 src/ride/TrackDesignRepository.h delete mode 100644 src/ride/track_design_index.c diff --git a/openrct2.vcxproj b/openrct2.vcxproj index 5d52961151..68818ff390 100644 --- a/openrct2.vcxproj +++ b/openrct2.vcxproj @@ -240,11 +240,11 @@ + - @@ -492,6 +492,7 @@ + diff --git a/src/interface/window.h b/src/interface/window.h index bd90a61630..71912d85be 100644 --- a/src/interface/window.h +++ b/src/interface/window.h @@ -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); diff --git a/src/rct2.c b/src/rct2.c index 9378cb8fd7..3cb20c8d69 100644 --- a/src/rct2.c +++ b/src/rct2.c @@ -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) { diff --git a/src/ride/TrackDesignRepository.cpp b/src/ride/TrackDesignRepository.cpp new file mode 100644 index 0000000000..f545a7be8b --- /dev/null +++ b/src/ride/TrackDesignRepository.cpp @@ -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 +#include +#include +#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 _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 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(MAX_PATH); + Path::GetFileNameWithoutExtension(name, MAX_PATH, path); + name = Memory::ReallocateArray(name, String::SizeOf(name) + 1); + return name; + } +}; + +static std::unique_ptr _trackRepository; + +ITrackDesignRepository * GetTrackRepository() +{ + if (_trackRepository == nullptr) + { + _trackRepository = std::unique_ptr(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); + } +} diff --git a/src/ride/TrackDesignRepository.h b/src/ride/TrackDesignRepository.h new file mode 100644 index 0000000000..3611ff3234 --- /dev/null +++ b/src/ride/TrackDesignRepository.h @@ -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 diff --git a/src/ride/track_design.c b/src/ride/track_design.c index 8f024d94d3..191b201289 100644 --- a/src/ride/track_design.c +++ b/src/ride/track_design.c @@ -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; } } diff --git a/src/ride/track_design.h b/src/ride/track_design.h index e60c948d63..bb81486c83 100644 --- a/src/ride/track_design.h +++ b/src/ride/track_design.h @@ -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); diff --git a/src/ride/track_design_index.c b/src/ride/track_design_index.c deleted file mode 100644 index 15653345f1..0000000000 --- a/src/ride/track_design_index.c +++ /dev/null @@ -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); -} diff --git a/src/ride/track_design_save.c b/src/ride/track_design_save.c index 2860919db3..65f9ee59cc 100644 --- a/src/ride/track_design_save.c +++ b/src/ride/track_design_save.c @@ -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(); } diff --git a/src/windows/install_track.c b/src/windows/install_track.c index 6a4c86c216..af82f7563e 100644 --- a/src/windows/install_track.c +++ b/src/windows/install_track.c @@ -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); diff --git a/src/windows/new_ride.c b/src/windows/new_ride.c index c8ffa93322..cfd33cca34 100644 --- a/src/windows/new_ride.c +++ b/src/windows/new_ride.c @@ -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); } /** diff --git a/src/windows/track_list.c b/src/windows/track_list.c index 1547bed634..37229e6c2e 100644 --- a/src/windows/track_list.c +++ b/src/windows/track_list.c @@ -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) diff --git a/src/windows/track_manage.c b/src/windows/track_manage.c index 5e8c8176b7..1aa6319b4d 100644 --- a/src/windows/track_manage.c +++ b/src/windows/track_manage.c @@ -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; } diff --git a/src/windows/track_place.c b/src/windows/track_place.c index 6377166edd..e8d89ad204 100644 --- a/src/windows/track_place.c +++ b/src/windows/track_place.c @@ -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"