Skip to content

Commit

Permalink
Merge branch 'master' into ags4
Browse files Browse the repository at this point in the history
# Conflicts:
#	CMakeLists.txt
#	Changes.txt
#	Common/core/def_version.h
#	Editor/AGS.Editor/AGSEditor.cs
#	Editor/AGS.Editor/Resources/agsdefns.sh
#	Editor/AGS.Editor/app.manifest
#	Editor/AGS.Types/Game.cs
#	Editor/AGS.Types/Properties/AssemblyInfo.cs
#	Engine/ac/file.cpp
#	Engine/ac/game.cpp
#	Engine/ac/gamestate.cpp
#	Engine/ac/gamestate.h
#	Engine/ac/global_api.cpp
#	Engine/ac/global_game.cpp
#	Engine/ac/global_game.h
#	Engine/ac/listbox.cpp
#	Engine/ac/runtime_defines.h
#	Engine/gui/guidialog.cpp
#	Engine/main/game_run.cpp
#	version.json
  • Loading branch information
ivan-mogilko committed Oct 7, 2024
2 parents cbbaeb5 + 4bd283a commit 6a42132
Show file tree
Hide file tree
Showing 62 changed files with 1,126 additions and 1,228 deletions.
77 changes: 76 additions & 1 deletion Common/core/assetmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
#include "core/assetmanager.h"
#include <algorithm>
#include <regex>
#include "util/directory.h"
#include "util/file.h"
#include "util/multifilelib.h"
#include "util/path.h"
Expand Down Expand Up @@ -177,6 +176,30 @@ bool AssetManager::DoesAssetExist(const String &asset_name, const String &filter
return false;
}

bool AssetManager::GetAssetTime(const String &asset_name, time_t &ft, const String &filter) const
{
for (const auto *lib : _activeLibs)
{
if (!lib->TestFilter(filter)) continue; // filter does not match

if (IsAssetLibDir(lib))
{
String filename = File::FindFileCI(lib->BaseDir, asset_name);
if (!filename.IsEmpty())
{
ft = File::GetFileTime(filename);
return true;
}
}
else
{
ft = File::GetFileTime(lib->RealLibFiles[0]);
return true;
}
}
return false;
}

void AssetManager::FindAssets(std::vector<String> &assets, const String &wildcard,
const String &filter) const
{
Expand Down Expand Up @@ -211,6 +234,58 @@ void AssetManager::FindAssets(std::vector<String> &assets, const String &wildcar
assets.erase(std::unique(assets.begin(), assets.end(), StrEqNoCase()), assets.end());
}

void AssetManager::FindAssets(std::vector<FileEntry> &assets, const String &wildcard,
const String &filter) const
{
// TODO: consider refactoring and merging this with FindAssets(std::vector<String> &assets);
// there are two separate methods now, because retrieving filename only is faster than
// full FileEntry (may require extra system calls on certain platforms).

String pattern = StrUtil::WildcardToRegex(wildcard);
const std::regex regex(pattern.GetCStr(), std::regex_constants::icase);
std::cmatch mr;

std::vector<FileEntry> lib_fileents;
for (const auto *lib : _activeLibs)
{
if (!lib->TestFilter(filter)) continue; // filter does not match

lib_fileents.clear();
if (IsAssetLibDir(lib))
{
// FIXME: do basedir/getparent(wildcard), getfilename(wildcard) instead?
// because FindFile does not support subdirs in wildcard!!
for (FindFile ff = FindFile::OpenFiles(lib->BaseDir, wildcard);
!ff.AtEnd(); ff.Next())
lib_fileents.push_back(ff.GetEntry());
}
else
{
time_t lib_time = File::GetFileTime(lib->RealLibFiles[0]);
for (const auto &a : lib->AssetInfos)
{
if (std::regex_match(a.FileName.GetCStr(), mr, regex))
lib_fileents.push_back(FileEntry(a.FileName, true, false, lib_time));
}
}

// We have to filter out matching entries and keep only ones that were found first by lib priority
if (assets.empty())
{
assets = std::move(lib_fileents);
}
else
{
for (const auto &fe : lib_fileents)
{
auto it_place = std::upper_bound(assets.begin(), assets.end(), fe, FileEntryCmpByNameCI());
if (it_place != assets.begin() && (it_place - 1)->Name.CompareNoCase(fe.Name) != 0)
assets.insert(it_place, fe);
}
}
}
}

AssetError AssetManager::RegisterAssetLib(const String &path, AssetLibEx *&out_lib)
{
// Test for a directory
Expand Down
9 changes: 9 additions & 0 deletions Common/core/assetmanager.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#include <memory>
#include <unordered_map>
#include "core/asset.h"
#include "util/directory.h"
#include "util/stream.h"
#include "util/string_types.h"

Expand Down Expand Up @@ -123,11 +124,19 @@ class AssetManager
// Tells whether asset exists in any of the registered search locations
bool DoesAssetExist(const String &asset_name, const String &filter = "") const;
inline bool DoesAssetExist(const AssetPath &apath) const { return DoesAssetExist(apath.Name, apath.Filter); }
// Tries to get asset's "file time" (last modification time).
// Note that for the assets packed within a CLIB format this will return library's time instead.
bool GetAssetTime(const String &asset_name, time_t &ft, const String &filter = "") const;
// Searches in all the registered locations and collects a list of
// assets using given wildcard pattern
// TODO: variant accepting std::regex instead of wildcard, and replace uses where convenient
void FindAssets(std::vector<String> &assets, const String &wildcard,
const String &filter = "") const;
// Searches in all the registered locations and collects a list of
// FileEntry objects corresponding to assets, using given wildcard pattern.
// NOTE: lib file assets will have their time property equal to lib's time.
void FindAssets(std::vector<FileEntry> &assets, const String &wildcard,
const String &filter = "") const;
// Open asset stream in the given work mode; returns null if asset is not found or cannot be opened
// This method only searches in libraries that do not have any defined filters
std::unique_ptr<Stream> OpenAsset(const String &asset_name) const;
Expand Down
17 changes: 17 additions & 0 deletions Common/util/directory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,23 @@ void GetFiles(const String &dir_path, std::vector<String> &files)
}
}

void GetFiles(const String &dir_path, std::vector<String> &files, const String &wildcard)
{
for (FindFile ff = FindFile::OpenFiles(dir_path, wildcard); !ff.AtEnd(); ff.Next())
files.push_back(ff.Current());
}

void GetFiles(const String &dir_path, std::vector<FileEntry> &files, const String &wildcard)
{
for (FindFile ff = FindFile::OpenFiles(dir_path, wildcard); !ff.AtEnd(); ff.Next())
files.push_back(ff.GetEntry());
}

bool HasAnyFiles(const String &dir_path)
{
return !FindFile::OpenFiles(dir_path).AtEnd();
}

} // namespace Directory


Expand Down
106 changes: 90 additions & 16 deletions Common/util/directory.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,22 @@ namespace AGS
namespace Common
{

// FileEntry describes a single entry in the filesystem.
struct FileEntry
{
String Name;
// TODO: make flags instead?
bool IsFile = false;
bool IsDir = false;
time_t Time{};

FileEntry() = default;
FileEntry(const String &name, bool is_file, bool is_dir, const time_t &time)
: Name(name), IsFile(is_file), IsDir(is_dir), Time(time) {}

operator bool() const { return !Name.IsEmpty(); }
};

namespace Directory
{
// Creates new directory (if it does not exist)
Expand All @@ -47,25 +63,15 @@ namespace Directory
void GetDirs(const String &dir_path, std::vector<String> &dirs);
// Get list of files found in the given directory
void GetFiles(const String &dir_path, std::vector<String> &files);
// Get list of files found in the given directory using wildcard pattern
void GetFiles(const String &dir_path, std::vector<String> &files, const String &wildcard);
// Get list of file entries in the given directory using wildcard pattern
void GetFiles(const String &dir_path, std::vector<FileEntry> &files, const String &wildcard);
// Tells whether there are any files in the given directory
bool HasAnyFiles(const String &dir_path);
} // namespace Directory


// FileEntry describes a single entry in the filesystem.
struct FileEntry
{
String Name;
// TODO: make flags instead?
bool IsFile = false;
bool IsDir = false;
time_t Time{};

FileEntry() = default;
FileEntry(const String &name, bool is_file, bool is_dir, const time_t &time)
: Name(name), IsFile(is_file), IsDir(is_dir), Time(time) {}

operator bool() const { return !Name.IsEmpty(); }
};

//
// DirectoryIterator iterates entries in the directory.
// The order of iteration is undefined.
Expand Down Expand Up @@ -202,6 +208,74 @@ class FindFile
bool _doDirs = false;
};


//
// FileEntry comparators
//
struct FileEntryEqByName
{
bool operator()(const FileEntry &fe1, const FileEntry &fe2) const
{
return fe1.Name == fe2.Name;
}
};

struct FileEntryEqByNameCI
{
bool operator()(const FileEntry &fe1, const FileEntry &fe2) const
{
return fe1.Name.CompareNoCase(fe2.Name) == 0;
}
};

struct FileEntryCmpByName
{
bool operator()(const FileEntry &fe1, const FileEntry &fe2) const
{
return fe1.Name.Compare(fe2.Name) < 0;
}
};

struct FileEntryCmpByNameDsc
{
bool operator()(const FileEntry &fe1, const FileEntry &fe2) const
{
return fe2.Name.Compare(fe1.Name) < 0;
}
};

struct FileEntryCmpByNameCI
{
bool operator()(const FileEntry &fe1, const FileEntry &fe2) const
{
return fe1.Name.CompareNoCase(fe2.Name) < 0;
}
};

struct FileEntryCmpByNameDscCI
{
bool operator()(const FileEntry &fe1, const FileEntry &fe2) const
{
return fe2.Name.CompareNoCase(fe1.Name) < 0;
}
};

struct FileEntryCmpByTime
{
bool operator()(const FileEntry &fe1, const FileEntry &fe2) const
{
return fe1.Time < fe2.Time;
}
};

struct FileEntryCmpByTimeDsc
{
bool operator()(const FileEntry &fe1, const FileEntry &fe2) const
{
return fe2.Time < fe1.Time;
}
};

} // namespace Common
} // namespace AGS

Expand Down
6 changes: 6 additions & 0 deletions Common/util/file.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,12 @@ soff_t File::GetFileSize(const String &filename)
return size;
}

time_t File::GetFileTime(const String &filename)
{
return ags_file_time(filename.GetCStr());
// NOTE: ANDROID's AAsset storage seems to be unapplicable here
}

bool File::TestReadFile(const String &filename)
{
FILE *test_file = ags_fopen(filename.GetCStr(), "rb");
Expand Down
2 changes: 2 additions & 0 deletions Common/util/file.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ namespace File
bool IsFileOrDir(const String &filename);
// Returns size of a file, or -1 if no such file found
soff_t GetFileSize(const String &filename);
// Returns file's last writing time, or time_t() if no such file found
time_t GetFileTime(const String &filename);
// Tests if file could be opened for reading
bool TestReadFile(const String &filename);
// Opens a file for writing or creates new one if it does not exist; deletes file if it was created during test
Expand Down
41 changes: 30 additions & 11 deletions Common/util/stdio_compat.c
Original file line number Diff line number Diff line change
Expand Up @@ -126,17 +126,17 @@ int ags_directory_exists(const char *path)

int ags_path_exists(const char *path)
{
#if AGS_PLATFORM_OS_WINDOWS
WCHAR wstr[MAX_PATH_SZ];
MultiByteToWideChar(CP_UTF8, 0, path, -1, wstr, MAX_PATH_SZ);
return PathFileExistsW(wstr);
#else
struct stat path_stat;
if (stat(path, &path_stat) != 0) {
return 0;
}
return S_ISREG(path_stat.st_mode) || S_ISDIR(path_stat.st_mode);
#endif
#if AGS_PLATFORM_OS_WINDOWS
WCHAR wstr[MAX_PATH_SZ];
MultiByteToWideChar(CP_UTF8, 0, path, -1, wstr, MAX_PATH_SZ);
return PathFileExistsW(wstr);
#else
struct stat path_stat;
if (stat(path, &path_stat) != 0) {
return 0;
}
return S_ISREG(path_stat.st_mode) || S_ISDIR(path_stat.st_mode);
#endif
}

file_off_t ags_file_size(const char *path)
Expand All @@ -158,6 +158,25 @@ file_off_t ags_file_size(const char *path)
#endif
}

time_t ags_file_time(const char *path)
{
#if AGS_PLATFORM_OS_WINDOWS
WCHAR wstr[MAX_PATH_SZ];
MultiByteToWideChar(CP_UTF8, 0, path, -1, wstr, MAX_PATH_SZ);
struct _stat64 path_stat;
if (_wstat64(wstr, &path_stat) != 0) {
return -1;
}
return path_stat.st_mtime;
#else
struct stat path_stat;
if (stat(path, &path_stat) != 0) {
return -1;
}
return path_stat.st_mtime;
#endif
}

int ags_file_remove(const char *path)
{
#if AGS_PLATFORM_OS_WINDOWS
Expand Down
2 changes: 2 additions & 0 deletions Common/util/stdio_compat.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

#include <stdio.h>
#include <stdint.h>
#include <time.h>

typedef int64_t file_off_t;

Expand All @@ -38,6 +39,7 @@ int ags_file_exists(const char *path);
int ags_directory_exists(const char *path);
int ags_path_exists(const char *path);
file_off_t ags_file_size(const char *path);
time_t ags_file_time(const char *path);

int ags_file_remove(const char *path);
int ags_file_rename(const char *src, const char *dst);
Expand Down
9 changes: 9 additions & 0 deletions Common/util/string_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,15 @@ namespace Common
// Various comparison functors
//

// Test case-sensitive String equality
struct StrEq
{
bool operator()(const String &s1, const String &s2) const
{
return s1 == s2;
}
};

// Test case-insensitive String equality
struct StrEqNoCase
{
Expand Down
Loading

0 comments on commit 6a42132

Please sign in to comment.