Skip to content

Commit 6a42132

Browse files
committed
Merge branch 'master' into ags4
# 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
2 parents cbbaeb5 + 4bd283a commit 6a42132

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+1126
-1228
lines changed

Common/core/assetmanager.cpp

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
#include "core/assetmanager.h"
1515
#include <algorithm>
1616
#include <regex>
17-
#include "util/directory.h"
1817
#include "util/file.h"
1918
#include "util/multifilelib.h"
2019
#include "util/path.h"
@@ -177,6 +176,30 @@ bool AssetManager::DoesAssetExist(const String &asset_name, const String &filter
177176
return false;
178177
}
179178

179+
bool AssetManager::GetAssetTime(const String &asset_name, time_t &ft, const String &filter) const
180+
{
181+
for (const auto *lib : _activeLibs)
182+
{
183+
if (!lib->TestFilter(filter)) continue; // filter does not match
184+
185+
if (IsAssetLibDir(lib))
186+
{
187+
String filename = File::FindFileCI(lib->BaseDir, asset_name);
188+
if (!filename.IsEmpty())
189+
{
190+
ft = File::GetFileTime(filename);
191+
return true;
192+
}
193+
}
194+
else
195+
{
196+
ft = File::GetFileTime(lib->RealLibFiles[0]);
197+
return true;
198+
}
199+
}
200+
return false;
201+
}
202+
180203
void AssetManager::FindAssets(std::vector<String> &assets, const String &wildcard,
181204
const String &filter) const
182205
{
@@ -211,6 +234,58 @@ void AssetManager::FindAssets(std::vector<String> &assets, const String &wildcar
211234
assets.erase(std::unique(assets.begin(), assets.end(), StrEqNoCase()), assets.end());
212235
}
213236

237+
void AssetManager::FindAssets(std::vector<FileEntry> &assets, const String &wildcard,
238+
const String &filter) const
239+
{
240+
// TODO: consider refactoring and merging this with FindAssets(std::vector<String> &assets);
241+
// there are two separate methods now, because retrieving filename only is faster than
242+
// full FileEntry (may require extra system calls on certain platforms).
243+
244+
String pattern = StrUtil::WildcardToRegex(wildcard);
245+
const std::regex regex(pattern.GetCStr(), std::regex_constants::icase);
246+
std::cmatch mr;
247+
248+
std::vector<FileEntry> lib_fileents;
249+
for (const auto *lib : _activeLibs)
250+
{
251+
if (!lib->TestFilter(filter)) continue; // filter does not match
252+
253+
lib_fileents.clear();
254+
if (IsAssetLibDir(lib))
255+
{
256+
// FIXME: do basedir/getparent(wildcard), getfilename(wildcard) instead?
257+
// because FindFile does not support subdirs in wildcard!!
258+
for (FindFile ff = FindFile::OpenFiles(lib->BaseDir, wildcard);
259+
!ff.AtEnd(); ff.Next())
260+
lib_fileents.push_back(ff.GetEntry());
261+
}
262+
else
263+
{
264+
time_t lib_time = File::GetFileTime(lib->RealLibFiles[0]);
265+
for (const auto &a : lib->AssetInfos)
266+
{
267+
if (std::regex_match(a.FileName.GetCStr(), mr, regex))
268+
lib_fileents.push_back(FileEntry(a.FileName, true, false, lib_time));
269+
}
270+
}
271+
272+
// We have to filter out matching entries and keep only ones that were found first by lib priority
273+
if (assets.empty())
274+
{
275+
assets = std::move(lib_fileents);
276+
}
277+
else
278+
{
279+
for (const auto &fe : lib_fileents)
280+
{
281+
auto it_place = std::upper_bound(assets.begin(), assets.end(), fe, FileEntryCmpByNameCI());
282+
if (it_place != assets.begin() && (it_place - 1)->Name.CompareNoCase(fe.Name) != 0)
283+
assets.insert(it_place, fe);
284+
}
285+
}
286+
}
287+
}
288+
214289
AssetError AssetManager::RegisterAssetLib(const String &path, AssetLibEx *&out_lib)
215290
{
216291
// Test for a directory

Common/core/assetmanager.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#include <memory>
4141
#include <unordered_map>
4242
#include "core/asset.h"
43+
#include "util/directory.h"
4344
#include "util/stream.h"
4445
#include "util/string_types.h"
4546

@@ -123,11 +124,19 @@ class AssetManager
123124
// Tells whether asset exists in any of the registered search locations
124125
bool DoesAssetExist(const String &asset_name, const String &filter = "") const;
125126
inline bool DoesAssetExist(const AssetPath &apath) const { return DoesAssetExist(apath.Name, apath.Filter); }
127+
// Tries to get asset's "file time" (last modification time).
128+
// Note that for the assets packed within a CLIB format this will return library's time instead.
129+
bool GetAssetTime(const String &asset_name, time_t &ft, const String &filter = "") const;
126130
// Searches in all the registered locations and collects a list of
127131
// assets using given wildcard pattern
128132
// TODO: variant accepting std::regex instead of wildcard, and replace uses where convenient
129133
void FindAssets(std::vector<String> &assets, const String &wildcard,
130134
const String &filter = "") const;
135+
// Searches in all the registered locations and collects a list of
136+
// FileEntry objects corresponding to assets, using given wildcard pattern.
137+
// NOTE: lib file assets will have their time property equal to lib's time.
138+
void FindAssets(std::vector<FileEntry> &assets, const String &wildcard,
139+
const String &filter = "") const;
131140
// Open asset stream in the given work mode; returns null if asset is not found or cannot be opened
132141
// This method only searches in libraries that do not have any defined filters
133142
std::unique_ptr<Stream> OpenAsset(const String &asset_name) const;

Common/util/directory.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,23 @@ void GetFiles(const String &dir_path, std::vector<String> &files)
129129
}
130130
}
131131

132+
void GetFiles(const String &dir_path, std::vector<String> &files, const String &wildcard)
133+
{
134+
for (FindFile ff = FindFile::OpenFiles(dir_path, wildcard); !ff.AtEnd(); ff.Next())
135+
files.push_back(ff.Current());
136+
}
137+
138+
void GetFiles(const String &dir_path, std::vector<FileEntry> &files, const String &wildcard)
139+
{
140+
for (FindFile ff = FindFile::OpenFiles(dir_path, wildcard); !ff.AtEnd(); ff.Next())
141+
files.push_back(ff.GetEntry());
142+
}
143+
144+
bool HasAnyFiles(const String &dir_path)
145+
{
146+
return !FindFile::OpenFiles(dir_path).AtEnd();
147+
}
148+
132149
} // namespace Directory
133150

134151

Common/util/directory.h

Lines changed: 90 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,22 @@ namespace AGS
3131
namespace Common
3232
{
3333

34+
// FileEntry describes a single entry in the filesystem.
35+
struct FileEntry
36+
{
37+
String Name;
38+
// TODO: make flags instead?
39+
bool IsFile = false;
40+
bool IsDir = false;
41+
time_t Time{};
42+
43+
FileEntry() = default;
44+
FileEntry(const String &name, bool is_file, bool is_dir, const time_t &time)
45+
: Name(name), IsFile(is_file), IsDir(is_dir), Time(time) {}
46+
47+
operator bool() const { return !Name.IsEmpty(); }
48+
};
49+
3450
namespace Directory
3551
{
3652
// Creates new directory (if it does not exist)
@@ -47,25 +63,15 @@ namespace Directory
4763
void GetDirs(const String &dir_path, std::vector<String> &dirs);
4864
// Get list of files found in the given directory
4965
void GetFiles(const String &dir_path, std::vector<String> &files);
66+
// Get list of files found in the given directory using wildcard pattern
67+
void GetFiles(const String &dir_path, std::vector<String> &files, const String &wildcard);
68+
// Get list of file entries in the given directory using wildcard pattern
69+
void GetFiles(const String &dir_path, std::vector<FileEntry> &files, const String &wildcard);
70+
// Tells whether there are any files in the given directory
71+
bool HasAnyFiles(const String &dir_path);
5072
} // namespace Directory
5173

5274

53-
// FileEntry describes a single entry in the filesystem.
54-
struct FileEntry
55-
{
56-
String Name;
57-
// TODO: make flags instead?
58-
bool IsFile = false;
59-
bool IsDir = false;
60-
time_t Time{};
61-
62-
FileEntry() = default;
63-
FileEntry(const String &name, bool is_file, bool is_dir, const time_t &time)
64-
: Name(name), IsFile(is_file), IsDir(is_dir), Time(time) {}
65-
66-
operator bool() const { return !Name.IsEmpty(); }
67-
};
68-
6975
//
7076
// DirectoryIterator iterates entries in the directory.
7177
// The order of iteration is undefined.
@@ -202,6 +208,74 @@ class FindFile
202208
bool _doDirs = false;
203209
};
204210

211+
212+
//
213+
// FileEntry comparators
214+
//
215+
struct FileEntryEqByName
216+
{
217+
bool operator()(const FileEntry &fe1, const FileEntry &fe2) const
218+
{
219+
return fe1.Name == fe2.Name;
220+
}
221+
};
222+
223+
struct FileEntryEqByNameCI
224+
{
225+
bool operator()(const FileEntry &fe1, const FileEntry &fe2) const
226+
{
227+
return fe1.Name.CompareNoCase(fe2.Name) == 0;
228+
}
229+
};
230+
231+
struct FileEntryCmpByName
232+
{
233+
bool operator()(const FileEntry &fe1, const FileEntry &fe2) const
234+
{
235+
return fe1.Name.Compare(fe2.Name) < 0;
236+
}
237+
};
238+
239+
struct FileEntryCmpByNameDsc
240+
{
241+
bool operator()(const FileEntry &fe1, const FileEntry &fe2) const
242+
{
243+
return fe2.Name.Compare(fe1.Name) < 0;
244+
}
245+
};
246+
247+
struct FileEntryCmpByNameCI
248+
{
249+
bool operator()(const FileEntry &fe1, const FileEntry &fe2) const
250+
{
251+
return fe1.Name.CompareNoCase(fe2.Name) < 0;
252+
}
253+
};
254+
255+
struct FileEntryCmpByNameDscCI
256+
{
257+
bool operator()(const FileEntry &fe1, const FileEntry &fe2) const
258+
{
259+
return fe2.Name.CompareNoCase(fe1.Name) < 0;
260+
}
261+
};
262+
263+
struct FileEntryCmpByTime
264+
{
265+
bool operator()(const FileEntry &fe1, const FileEntry &fe2) const
266+
{
267+
return fe1.Time < fe2.Time;
268+
}
269+
};
270+
271+
struct FileEntryCmpByTimeDsc
272+
{
273+
bool operator()(const FileEntry &fe1, const FileEntry &fe2) const
274+
{
275+
return fe2.Time < fe1.Time;
276+
}
277+
};
278+
205279
} // namespace Common
206280
} // namespace AGS
207281

Common/util/file.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,12 @@ soff_t File::GetFileSize(const String &filename)
7373
return size;
7474
}
7575

76+
time_t File::GetFileTime(const String &filename)
77+
{
78+
return ags_file_time(filename.GetCStr());
79+
// NOTE: ANDROID's AAsset storage seems to be unapplicable here
80+
}
81+
7682
bool File::TestReadFile(const String &filename)
7783
{
7884
FILE *test_file = ags_fopen(filename.GetCStr(), "rb");

Common/util/file.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ namespace File
5858
bool IsFileOrDir(const String &filename);
5959
// Returns size of a file, or -1 if no such file found
6060
soff_t GetFileSize(const String &filename);
61+
// Returns file's last writing time, or time_t() if no such file found
62+
time_t GetFileTime(const String &filename);
6163
// Tests if file could be opened for reading
6264
bool TestReadFile(const String &filename);
6365
// Opens a file for writing or creates new one if it does not exist; deletes file if it was created during test

Common/util/stdio_compat.c

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -126,17 +126,17 @@ int ags_directory_exists(const char *path)
126126

127127
int ags_path_exists(const char *path)
128128
{
129-
#if AGS_PLATFORM_OS_WINDOWS
130-
WCHAR wstr[MAX_PATH_SZ];
131-
MultiByteToWideChar(CP_UTF8, 0, path, -1, wstr, MAX_PATH_SZ);
132-
return PathFileExistsW(wstr);
133-
#else
134-
struct stat path_stat;
135-
if (stat(path, &path_stat) != 0) {
136-
return 0;
137-
}
138-
return S_ISREG(path_stat.st_mode) || S_ISDIR(path_stat.st_mode);
139-
#endif
129+
#if AGS_PLATFORM_OS_WINDOWS
130+
WCHAR wstr[MAX_PATH_SZ];
131+
MultiByteToWideChar(CP_UTF8, 0, path, -1, wstr, MAX_PATH_SZ);
132+
return PathFileExistsW(wstr);
133+
#else
134+
struct stat path_stat;
135+
if (stat(path, &path_stat) != 0) {
136+
return 0;
137+
}
138+
return S_ISREG(path_stat.st_mode) || S_ISDIR(path_stat.st_mode);
139+
#endif
140140
}
141141

142142
file_off_t ags_file_size(const char *path)
@@ -158,6 +158,25 @@ file_off_t ags_file_size(const char *path)
158158
#endif
159159
}
160160

161+
time_t ags_file_time(const char *path)
162+
{
163+
#if AGS_PLATFORM_OS_WINDOWS
164+
WCHAR wstr[MAX_PATH_SZ];
165+
MultiByteToWideChar(CP_UTF8, 0, path, -1, wstr, MAX_PATH_SZ);
166+
struct _stat64 path_stat;
167+
if (_wstat64(wstr, &path_stat) != 0) {
168+
return -1;
169+
}
170+
return path_stat.st_mtime;
171+
#else
172+
struct stat path_stat;
173+
if (stat(path, &path_stat) != 0) {
174+
return -1;
175+
}
176+
return path_stat.st_mtime;
177+
#endif
178+
}
179+
161180
int ags_file_remove(const char *path)
162181
{
163182
#if AGS_PLATFORM_OS_WINDOWS

Common/util/stdio_compat.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include <stdio.h>
1818
#include <stdint.h>
19+
#include <time.h>
1920

2021
typedef int64_t file_off_t;
2122

@@ -38,6 +39,7 @@ int ags_file_exists(const char *path);
3839
int ags_directory_exists(const char *path);
3940
int ags_path_exists(const char *path);
4041
file_off_t ags_file_size(const char *path);
42+
time_t ags_file_time(const char *path);
4143

4244
int ags_file_remove(const char *path);
4345
int ags_file_rename(const char *src, const char *dst);

Common/util/string_types.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,15 @@ namespace Common
7070
// Various comparison functors
7171
//
7272

73+
// Test case-sensitive String equality
74+
struct StrEq
75+
{
76+
bool operator()(const String &s1, const String &s2) const
77+
{
78+
return s1 == s2;
79+
}
80+
};
81+
7382
// Test case-insensitive String equality
7483
struct StrEqNoCase
7584
{

0 commit comments

Comments
 (0)