From 712e062bcc3a811ac863c1b06e73ffbc85b8ac82 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sun, 23 Oct 2016 01:12:17 +0100 Subject: [PATCH] Only load tracks if cache is invalid --- src/core/FileScanner.cpp | 35 +++++++++++++ src/core/FileScanner.h | 23 +++++++++ src/object/ObjectRepository.cpp | 42 +--------------- src/ride/TrackDesignRepository.cpp | 79 +++++++++++++++++++++++++++--- 4 files changed, 132 insertions(+), 47 deletions(-) diff --git a/src/core/FileScanner.cpp b/src/core/FileScanner.cpp index 93ef898789..58585dd19e 100644 --- a/src/core/FileScanner.cpp +++ b/src/core/FileScanner.cpp @@ -57,6 +57,7 @@ struct DirectoryChild uint64 LastModified; }; +static uint32 GetPathChecksum(const utf8 * path); static bool MatchWildcard(const utf8 * fileName, const utf8 * pattern); class FileScannerBase : public IFileScanner @@ -363,6 +364,40 @@ IFileScanner * Path::ScanDirectory(const utf8 * pattern, bool recurse) #endif } +void Path::QueryDirectory(QueryDirectoryResult * result, const utf8 * pattern) +{ + IFileScanner * scanner = Path::ScanDirectory(pattern, true); + while (scanner->Next()) + { + const FileInfo * fileInfo = scanner->GetFileInfo(); + const utf8 * path = scanner->GetPath(); + + result->TotalFiles++; + result->TotalFileSize += fileInfo->Size; + result->FileDateModifiedChecksum ^= + (uint32)(fileInfo->LastModified >> 32) ^ + (uint32)(fileInfo->LastModified & 0xFFFFFFFF); + result->FileDateModifiedChecksum = ror32(result->FileDateModifiedChecksum, 5); + result->PathChecksum += GetPathChecksum(path); + } + delete scanner; +} + +static uint32 GetPathChecksum(const utf8 * path) +{ + uint32 hash = 0xD8430DED; + for (const utf8 * ch = path; *ch != '\0'; ch++) + { + hash += (*ch); + hash += (hash << 10); + hash ^= (hash >> 6); + } + hash += (hash << 3); + hash ^= (hash >> 11); + hash += (hash << 15); + return hash; +} + /** * Due to FindFirstFile / FindNextFile searching for DOS names as well, *.doc also matches *.docx which isn't what the pattern * specified. This will verify if a filename does indeed match the pattern we asked for. diff --git a/src/core/FileScanner.h b/src/core/FileScanner.h index f9967d0eb4..1cbf90c1e7 100644 --- a/src/core/FileScanner.h +++ b/src/core/FileScanner.h @@ -41,7 +41,30 @@ interface IFileScanner virtual bool Next() abstract; }; +struct QueryDirectoryResult +{ + uint32 TotalFiles; + uint64 TotalFileSize; + uint32 FileDateModifiedChecksum; + uint32 PathChecksum; +}; + namespace Path { + /** + * Scans a directory and optionally sub directories for files that matches the + * given pattern and returns an enumerator. + * @param pattern The path followed by a semi-colon delimited list of wildcard patterns. + * @param recurse Whether to scan sub directories or not. + * @returns A new FileScanner, this must be deleted when no longer needed. + */ IFileScanner * ScanDirectory(const utf8 * pattern, bool recurse); + + /** + * Scans a directory and all sub directories + * @param result The query result to modify. + * @param pattern The path followed by a semi-colon delimited list of wildcard patterns. + * @returns An aggregated result of all scanned files. + */ + void QueryDirectory(QueryDirectoryResult * result, const utf8 * pattern); } diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index 4d2a257ab4..6625661331 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -46,7 +46,7 @@ extern "C" #include "../object_list.h" #include "../platform/platform.h" #include "../util/sawyercoding.h" - #include "../util/util.h" + #include "../util/util.h" } constexpr uint16 OBJECT_REPOSITORY_VERSION = 10; @@ -65,14 +65,6 @@ struct ObjectRepositoryHeader assert_struct_size(ObjectRepositoryHeader, 28); #pragma pack(pop) -struct QueryDirectoryResult -{ - uint32 TotalFiles; - uint64 TotalFileSize; - uint32 FileDateModifiedChecksum; - uint32 PathChecksum; -}; - struct ObjectEntryHash { size_t operator()(const rct_object_entry &entry) const @@ -239,22 +231,7 @@ private: utf8 pattern[MAX_PATH]; String::Set(pattern, sizeof(pattern), directory); Path::Append(pattern, sizeof(pattern), "*.dat"); - - IFileScanner * scanner = Path::ScanDirectory(pattern, true); - while (scanner->Next()) - { - const FileInfo * fileInfo = scanner->GetFileInfo(); - const utf8 * path = scanner->GetPath(); - - result->TotalFiles++; - result->TotalFileSize += fileInfo->Size; - result->FileDateModifiedChecksum ^= - (uint32)(fileInfo->LastModified >> 32) ^ - (uint32)(fileInfo->LastModified & 0xFFFFFFFF); - result->FileDateModifiedChecksum = ror32(result->FileDateModifiedChecksum, 5); - result->PathChecksum += GetPathChecksum(path); - } - delete scanner; + Path::QueryDirectory(result, pattern); } void Construct() @@ -650,21 +627,6 @@ private: { platform_get_user_directory(buffer, "object", bufferSize); } - - static uint32 GetPathChecksum(const utf8 * path) - { - uint32 hash = 0xD8430DED; - for (const utf8 * ch = path; *ch != '\0'; ch++) - { - hash += (*ch); - hash += (hash << 10); - hash ^= (hash >> 6); - } - hash += (hash << 3); - hash ^= (hash >> 11); - hash += (hash << 15); - return hash; - } }; static std::unique_ptr _objectRepository; diff --git a/src/ride/TrackDesignRepository.cpp b/src/ride/TrackDesignRepository.cpp index 3372803c3a..7e42110be2 100644 --- a/src/ride/TrackDesignRepository.cpp +++ b/src/ride/TrackDesignRepository.cpp @@ -35,6 +35,10 @@ struct TrackRepositoryHeader { uint32 MagicNumber; uint16 Version; + uint32 TotalFiles; + uint64 TotalFileSize; + uint32 FileDateModifiedChecksum; + uint32 PathChecksum; uint32 NumItems; }; #pragma pack(pop) @@ -60,6 +64,7 @@ class TrackDesignRepository : public ITrackDesignRepository { private: std::vector _items; + QueryDirectoryResult _directoryQueryResult; public: virtual ~TrackDesignRepository() @@ -111,16 +116,24 @@ public: void Scan() override { - utf8 directory[MAX_PATH]; + utf8 rct2Directory[MAX_PATH]; + utf8 userDirectory[MAX_PATH]; - GetRCT2Directory(directory, sizeof(directory)); - Scan(directory, TRIF_READ_ONLY); + GetRCT2Directory(rct2Directory, sizeof(rct2Directory)); + GetUserDirectory(userDirectory, sizeof(userDirectory)); - GetUserDirectory(directory, sizeof(directory)); - Scan(directory); + _items.clear(); + _directoryQueryResult = { 0 }; + Query(rct2Directory); + Query(userDirectory); - SortItems(); - Save(); + if (!Load()) + { + Scan(rct2Directory, TRIF_READ_ONLY); + Scan(userDirectory); + SortItems(); + Save(); + } } bool Delete(const utf8 * path) override @@ -193,6 +206,14 @@ public: } private: + void Query(const utf8 * directory) + { + utf8 pattern[MAX_PATH]; + String::Set(pattern, sizeof(pattern), directory); + Path::Append(pattern, sizeof(pattern), "*.td4;*.td6"); + Path::QueryDirectory(&_directoryQueryResult, pattern); + } + void Scan(const utf8 * directory, uint32 flags = 0) { utf8 pattern[MAX_PATH]; @@ -240,6 +261,46 @@ private: }); } + bool Load() + { + utf8 path[MAX_PATH]; + GetRepositoryPath(path, sizeof(path)); + + bool result = false; + try + { + auto fs = FileStream(path, FILE_MODE_OPEN); + + // Read header, check if we need to re-scan + auto header = fs.ReadValue(); + if (header.MagicNumber == TRACK_REPOSITORY_MAGIC_NUMBER && + header.Version == TRACK_REPOSITORY_VERSION && + header.TotalFiles == _directoryQueryResult.TotalFiles && + header.TotalFileSize == _directoryQueryResult.TotalFileSize && + header.FileDateModifiedChecksum == _directoryQueryResult.FileDateModifiedChecksum && + header.PathChecksum == _directoryQueryResult.PathChecksum) + { + // Directory is the same, just read the saved items + for (uint32 i = 0; i < header.NumItems; i++) + { + TrackRepositoryItem item; + item.Name = fs.ReadString(); + item.Path = fs.ReadString(); + item.RideType = fs.ReadValue(); + item.ObjectEntry = fs.ReadString(); + item.Flags = fs.ReadValue(); + _items.push_back(item); + } + result = true; + } + } + catch (Exception ex) + { + Console::Error::WriteLine("Unable to write object repository index."); + } + return result; + } + void Save() const { utf8 path[MAX_PATH]; @@ -253,6 +314,10 @@ private: TrackRepositoryHeader header = { 0 }; header.MagicNumber = TRACK_REPOSITORY_MAGIC_NUMBER; header.Version = TRACK_REPOSITORY_VERSION; + header.TotalFiles = _directoryQueryResult.TotalFiles; + header.TotalFileSize = _directoryQueryResult.TotalFileSize; + header.FileDateModifiedChecksum = _directoryQueryResult.FileDateModifiedChecksum; + header.PathChecksum = _directoryQueryResult.PathChecksum; header.NumItems = (uint32)_items.size(); fs.WriteValue(header);