mirror of https://github.com/OpenRCT2/OpenRCT2.git
Only load tracks if cache is invalid
This commit is contained in:
parent
9eaf887546
commit
712e062bcc
|
@ -57,6 +57,7 @@ struct DirectoryChild
|
||||||
uint64 LastModified;
|
uint64 LastModified;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static uint32 GetPathChecksum(const utf8 * path);
|
||||||
static bool MatchWildcard(const utf8 * fileName, const utf8 * pattern);
|
static bool MatchWildcard(const utf8 * fileName, const utf8 * pattern);
|
||||||
|
|
||||||
class FileScannerBase : public IFileScanner
|
class FileScannerBase : public IFileScanner
|
||||||
|
@ -363,6 +364,40 @@ IFileScanner * Path::ScanDirectory(const utf8 * pattern, bool recurse)
|
||||||
#endif
|
#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
|
* 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.
|
* specified. This will verify if a filename does indeed match the pattern we asked for.
|
||||||
|
|
|
@ -41,7 +41,30 @@ interface IFileScanner
|
||||||
virtual bool Next() abstract;
|
virtual bool Next() abstract;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct QueryDirectoryResult
|
||||||
|
{
|
||||||
|
uint32 TotalFiles;
|
||||||
|
uint64 TotalFileSize;
|
||||||
|
uint32 FileDateModifiedChecksum;
|
||||||
|
uint32 PathChecksum;
|
||||||
|
};
|
||||||
|
|
||||||
namespace Path
|
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);
|
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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ extern "C"
|
||||||
#include "../object_list.h"
|
#include "../object_list.h"
|
||||||
#include "../platform/platform.h"
|
#include "../platform/platform.h"
|
||||||
#include "../util/sawyercoding.h"
|
#include "../util/sawyercoding.h"
|
||||||
#include "../util/util.h"
|
#include "../util/util.h"
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr uint16 OBJECT_REPOSITORY_VERSION = 10;
|
constexpr uint16 OBJECT_REPOSITORY_VERSION = 10;
|
||||||
|
@ -65,14 +65,6 @@ struct ObjectRepositoryHeader
|
||||||
assert_struct_size(ObjectRepositoryHeader, 28);
|
assert_struct_size(ObjectRepositoryHeader, 28);
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
struct QueryDirectoryResult
|
|
||||||
{
|
|
||||||
uint32 TotalFiles;
|
|
||||||
uint64 TotalFileSize;
|
|
||||||
uint32 FileDateModifiedChecksum;
|
|
||||||
uint32 PathChecksum;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ObjectEntryHash
|
struct ObjectEntryHash
|
||||||
{
|
{
|
||||||
size_t operator()(const rct_object_entry &entry) const
|
size_t operator()(const rct_object_entry &entry) const
|
||||||
|
@ -239,22 +231,7 @@ private:
|
||||||
utf8 pattern[MAX_PATH];
|
utf8 pattern[MAX_PATH];
|
||||||
String::Set(pattern, sizeof(pattern), directory);
|
String::Set(pattern, sizeof(pattern), directory);
|
||||||
Path::Append(pattern, sizeof(pattern), "*.dat");
|
Path::Append(pattern, sizeof(pattern), "*.dat");
|
||||||
|
Path::QueryDirectory(result, 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Construct()
|
void Construct()
|
||||||
|
@ -650,21 +627,6 @@ private:
|
||||||
{
|
{
|
||||||
platform_get_user_directory(buffer, "object", bufferSize);
|
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> _objectRepository;
|
static std::unique_ptr<ObjectRepository> _objectRepository;
|
||||||
|
|
|
@ -35,6 +35,10 @@ struct TrackRepositoryHeader
|
||||||
{
|
{
|
||||||
uint32 MagicNumber;
|
uint32 MagicNumber;
|
||||||
uint16 Version;
|
uint16 Version;
|
||||||
|
uint32 TotalFiles;
|
||||||
|
uint64 TotalFileSize;
|
||||||
|
uint32 FileDateModifiedChecksum;
|
||||||
|
uint32 PathChecksum;
|
||||||
uint32 NumItems;
|
uint32 NumItems;
|
||||||
};
|
};
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
@ -60,6 +64,7 @@ class TrackDesignRepository : public ITrackDesignRepository
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
std::vector<TrackRepositoryItem> _items;
|
std::vector<TrackRepositoryItem> _items;
|
||||||
|
QueryDirectoryResult _directoryQueryResult;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~TrackDesignRepository()
|
virtual ~TrackDesignRepository()
|
||||||
|
@ -111,16 +116,24 @@ public:
|
||||||
|
|
||||||
void Scan() override
|
void Scan() override
|
||||||
{
|
{
|
||||||
utf8 directory[MAX_PATH];
|
utf8 rct2Directory[MAX_PATH];
|
||||||
|
utf8 userDirectory[MAX_PATH];
|
||||||
|
|
||||||
GetRCT2Directory(directory, sizeof(directory));
|
GetRCT2Directory(rct2Directory, sizeof(rct2Directory));
|
||||||
Scan(directory, TRIF_READ_ONLY);
|
GetUserDirectory(userDirectory, sizeof(userDirectory));
|
||||||
|
|
||||||
GetUserDirectory(directory, sizeof(directory));
|
_items.clear();
|
||||||
Scan(directory);
|
_directoryQueryResult = { 0 };
|
||||||
|
Query(rct2Directory);
|
||||||
|
Query(userDirectory);
|
||||||
|
|
||||||
SortItems();
|
if (!Load())
|
||||||
Save();
|
{
|
||||||
|
Scan(rct2Directory, TRIF_READ_ONLY);
|
||||||
|
Scan(userDirectory);
|
||||||
|
SortItems();
|
||||||
|
Save();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Delete(const utf8 * path) override
|
bool Delete(const utf8 * path) override
|
||||||
|
@ -193,6 +206,14 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
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)
|
void Scan(const utf8 * directory, uint32 flags = 0)
|
||||||
{
|
{
|
||||||
utf8 pattern[MAX_PATH];
|
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<TrackRepositoryHeader>();
|
||||||
|
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<uint8>();
|
||||||
|
item.ObjectEntry = fs.ReadString();
|
||||||
|
item.Flags = fs.ReadValue<uint32>();
|
||||||
|
_items.push_back(item);
|
||||||
|
}
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console::Error::WriteLine("Unable to write object repository index.");
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void Save() const
|
void Save() const
|
||||||
{
|
{
|
||||||
utf8 path[MAX_PATH];
|
utf8 path[MAX_PATH];
|
||||||
|
@ -253,6 +314,10 @@ private:
|
||||||
TrackRepositoryHeader header = { 0 };
|
TrackRepositoryHeader header = { 0 };
|
||||||
header.MagicNumber = TRACK_REPOSITORY_MAGIC_NUMBER;
|
header.MagicNumber = TRACK_REPOSITORY_MAGIC_NUMBER;
|
||||||
header.Version = TRACK_REPOSITORY_VERSION;
|
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();
|
header.NumItems = (uint32)_items.size();
|
||||||
fs.WriteValue(header);
|
fs.WriteValue(header);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue