Revert 4bb31f084e
4bb31f084e
led to an issue in windows-specific code not detected by the
tests. I'll debug later.
This was SVN commit r25105.
This commit is contained in:
parent
4bb31f084e
commit
5d1899785a
@ -48,6 +48,7 @@ RL client:
|
||||
Configuration:
|
||||
-conf=KEY:VALUE set a config value
|
||||
-nosound disable audio
|
||||
-noUserMod disable loading of the user mod
|
||||
-shadows enable shadows
|
||||
-vsync enable VSync, i.e. lock FPS to monitor refresh rate
|
||||
-xres=N set screen X resolution to 'N'
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2021 Wildfire Games.
|
||||
/* Copyright (C) 2017 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -62,7 +62,11 @@ class TestMeshManager : public CxxTest::TestSuite
|
||||
|
||||
TS_ASSERT_OK(g_VFS->Mount(L"", MOD_PATH));
|
||||
TS_ASSERT_OK(g_VFS->Mount(L"collada/", DataDir()/"tests"/"collada", VFS_MOUNT_MUST_EXIST));
|
||||
TS_ASSERT_OK(g_VFS->Mount(L"cache/", CACHE_PATH, 0, VFS_MAX_PRIORITY));
|
||||
|
||||
// Mount _testcache onto virtual /cache - don't use the normal cache
|
||||
// directory because that's full of loads of cached files from the
|
||||
// proper game and takes a long time to load.
|
||||
TS_ASSERT_OK(g_VFS->Mount(L"cache/", CACHE_PATH));
|
||||
}
|
||||
|
||||
void deinitVfs()
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2021 Wildfire Games.
|
||||
/* Copyright (C) 2017 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -36,7 +36,7 @@ public:
|
||||
|
||||
m_VFS = CreateVfs();
|
||||
TS_ASSERT_OK(m_VFS->Mount(L"", DataDir()/"mods"/"_test.tex", VFS_MOUNT_MUST_EXIST));
|
||||
TS_ASSERT_OK(m_VFS->Mount(L"cache/", DataDir()/"_testcache", 0, VFS_MAX_PRIORITY));
|
||||
TS_ASSERT_OK(m_VFS->Mount(L"cache/", DataDir()/"_testcache"));
|
||||
}
|
||||
|
||||
void tearDown()
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2021 Wildfire Games.
|
||||
/* Copyright (C) 2017 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -37,7 +37,7 @@ public:
|
||||
|
||||
m_VFS = CreateVfs();
|
||||
TS_ASSERT_OK(m_VFS->Mount(L"", DataDir()/"mods"/"_test.tex", VFS_MOUNT_MUST_EXIST));
|
||||
TS_ASSERT_OK(m_VFS->Mount(L"cache/", DataDir()/"_testcache", 0, VFS_MAX_PRIORITY));
|
||||
TS_ASSERT_OK(m_VFS->Mount(L"cache/", DataDir()/"_testcache"));
|
||||
|
||||
h_mgr_init();
|
||||
|
||||
|
@ -35,7 +35,7 @@ public:
|
||||
{
|
||||
g_VFS = CreateVfs();
|
||||
TS_ASSERT_OK(g_VFS->Mount(L"", DataDir()/"mods"/"_test.gui", VFS_MOUNT_MUST_EXIST));
|
||||
TS_ASSERT_OK(g_VFS->Mount(L"cache", DataDir()/"_testcache", 0, VFS_MAX_PRIORITY));
|
||||
TS_ASSERT_OK(g_VFS->Mount(L"cache", DataDir()/"_testcache"));
|
||||
|
||||
configDB = new CConfigDB;
|
||||
|
||||
|
@ -1,190 +0,0 @@
|
||||
/* Copyright (C) 2021 Wildfire Games.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "lib/self_test.h"
|
||||
|
||||
#include "lib/file/vfs/vfs_populate.h"
|
||||
#include "lib/os_path.h"
|
||||
|
||||
static OsPath TEST_FOLDER(DataDir()/"_test.temp");
|
||||
|
||||
extern PIVFS g_VFS;
|
||||
|
||||
class TestVfsPopulate : public CxxTest::TestSuite
|
||||
{
|
||||
void initVfs()
|
||||
{
|
||||
g_VFS = CreateVfs();
|
||||
}
|
||||
|
||||
void deinitVfs()
|
||||
{
|
||||
if(DirectoryExists(TEST_FOLDER))
|
||||
DeleteDirectory(TEST_FOLDER);
|
||||
|
||||
g_VFS.reset();
|
||||
}
|
||||
|
||||
void createRealDir(const OsPath& path)
|
||||
{
|
||||
if(DirectoryExists(path))
|
||||
DeleteDirectory(path);
|
||||
CreateDirectories(path, 0700, false);
|
||||
}
|
||||
|
||||
public:
|
||||
void setUp()
|
||||
{
|
||||
initVfs();
|
||||
}
|
||||
|
||||
void tearDown()
|
||||
{
|
||||
deinitVfs();
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a regression test. Before priorities were used for real directories, things were... Rather undefined.
|
||||
* The new spec is that the path is relative to the highest priority subdirectory in the path.
|
||||
* The order remains undefined in case of equal priority.
|
||||
* (see below for tests on that).
|
||||
*/
|
||||
void test_write_path_hijacking()
|
||||
{
|
||||
createRealDir(TEST_FOLDER / "cache" / "some_folder");
|
||||
createRealDir(TEST_FOLDER / "some_mod" / "cache" / "some_mod");
|
||||
|
||||
shared_ptr<u8> buf(new u8(1));
|
||||
|
||||
g_VFS->Mount(L"", TEST_FOLDER / "some_mod", 0, 0);
|
||||
|
||||
// Access the subfolder, creating subdirectories in the VFS.
|
||||
g_VFS->CreateFile(L"cache/some_mod/peek.txt", buf, 0);
|
||||
|
||||
g_VFS->Mount(L"cache/", TEST_FOLDER / "cache", 0, 1);
|
||||
|
||||
OsPath realPath;
|
||||
g_VFS->GetDirectoryRealPath(L"cache/", realPath);
|
||||
TS_ASSERT_EQUALS(realPath, TEST_FOLDER / "cache");
|
||||
g_VFS->CreateFile(L"cache/test.txt", buf, 0);
|
||||
g_VFS->GetRealPath(L"cache/test.txt", realPath);
|
||||
TS_ASSERT_EQUALS(realPath, TEST_FOLDER / "cache" / "test.txt");
|
||||
|
||||
g_VFS->GetDirectoryRealPath(L"cache/some_mod/", realPath);
|
||||
TS_ASSERT_EQUALS(realPath, TEST_FOLDER / "cache" / "some_mod");
|
||||
g_VFS->CreateFile(L"cache/some_mod/test.txt", buf, 0);
|
||||
g_VFS->GetRealPath(L"cache/some_mod/test.txt", realPath);
|
||||
TS_ASSERT_EQUALS(realPath, TEST_FOLDER / "cache" / "some_mod" / "test.txt");
|
||||
};
|
||||
|
||||
void test_priority()
|
||||
{
|
||||
createRealDir(TEST_FOLDER / "mod_a");
|
||||
createRealDir(TEST_FOLDER / "mod_b");
|
||||
|
||||
// Check that the real directory points to the highest priority mod.
|
||||
g_VFS->Mount(L"mod", TEST_FOLDER / "mod_a", 0, 1);
|
||||
g_VFS->Mount(L"mod", TEST_FOLDER / "mod_b", 0, 0);
|
||||
|
||||
// For consistency, populate everything.
|
||||
g_VFS->TextRepresentation().c_str();
|
||||
|
||||
OsPath realPath;
|
||||
g_VFS->GetDirectoryRealPath(L"mod", realPath);
|
||||
TS_ASSERT_EQUALS(realPath, TEST_FOLDER / "mod_a");
|
||||
};
|
||||
|
||||
void test_real_path_0()
|
||||
{
|
||||
createRealDir(TEST_FOLDER / "mod_0" / "folder_a");
|
||||
createRealDir(TEST_FOLDER / "mod_0" / "folder_a" / "subfolder");
|
||||
createRealDir(TEST_FOLDER / "mod_0" / "folder_b");
|
||||
createRealDir(TEST_FOLDER / "mod_1" / "folder_a");
|
||||
createRealDir(TEST_FOLDER / "folder_a");
|
||||
|
||||
g_VFS->Mount(L"folder_a/", TEST_FOLDER / "folder_a", 0, 2);
|
||||
g_VFS->Mount(L"", TEST_FOLDER / "mod_1", 0, 1);
|
||||
g_VFS->Mount(L"", TEST_FOLDER / "mod_0", 0, 0);
|
||||
|
||||
OsPath realPath;
|
||||
g_VFS->GetDirectoryRealPath(L"folder_a/", realPath);
|
||||
TS_ASSERT_EQUALS(realPath, TEST_FOLDER / "folder_a");
|
||||
// Despite being lower priority, we still load non-conflicting files of mod_0
|
||||
g_VFS->GetDirectoryRealPath(L"folder_b/", realPath);
|
||||
// However their real path is rewritten to mod_1.
|
||||
TS_ASSERT_EQUALS(realPath, TEST_FOLDER / "mod_1" / "folder_b");
|
||||
|
||||
// (including sub-subfolders)
|
||||
g_VFS->GetDirectoryRealPath(L"folder_a/subfolder/", realPath);
|
||||
// However their real path is rewritten.
|
||||
TS_ASSERT_EQUALS(realPath, TEST_FOLDER / "folder_a" / "subfolder");
|
||||
};
|
||||
|
||||
void test_real_path_1()
|
||||
{
|
||||
createRealDir(TEST_FOLDER / "mod_0" / "folder_a");
|
||||
createRealDir(TEST_FOLDER / "mod_1" / "folder_a");
|
||||
createRealDir(TEST_FOLDER / "folder_a");
|
||||
|
||||
// Equal priority, the order is undetermined.
|
||||
OsPath realPath;
|
||||
g_VFS->Mount(L"", TEST_FOLDER / "mod_0", 0, 1);
|
||||
g_VFS->Mount(L"folder_a/", TEST_FOLDER / "folder_a", 0, 1);
|
||||
g_VFS->Mount(L"", TEST_FOLDER / "mod_1", 0, 0);
|
||||
|
||||
g_VFS->GetDirectoryRealPath(L"folder_a/", realPath);
|
||||
TS_ASSERT_EQUALS(realPath, TEST_FOLDER / "folder_a");
|
||||
};
|
||||
|
||||
// Same as test_real_path_1, but invert the mounting order
|
||||
// (may or may not result in different behaviour).
|
||||
void test_real_path_2()
|
||||
{
|
||||
createRealDir(TEST_FOLDER / "mod_0" / "folder_a");
|
||||
createRealDir(TEST_FOLDER / "mod_1" / "folder_a");
|
||||
createRealDir(TEST_FOLDER / "folder_a");
|
||||
|
||||
// Equal priority, the order is undetermined.
|
||||
OsPath realPath;
|
||||
g_VFS->Mount(L"folder_a/", TEST_FOLDER / "folder_a", 0, 1);
|
||||
g_VFS->Mount(L"", TEST_FOLDER / "mod_1", 0, 0);
|
||||
g_VFS->Mount(L"", TEST_FOLDER / "mod_0", 0, 1);
|
||||
|
||||
g_VFS->GetDirectoryRealPath(L"folder_a/", realPath);
|
||||
TS_ASSERT_EQUALS(realPath, TEST_FOLDER / "folder_a");
|
||||
};
|
||||
|
||||
void test_real_path_subpath()
|
||||
{
|
||||
createRealDir(TEST_FOLDER / "mod_0" / "folder" / "subfolder");
|
||||
createRealDir(TEST_FOLDER / "mod_1" / "folder" / "subfolder");
|
||||
createRealDir(TEST_FOLDER / "other_folder");
|
||||
|
||||
g_VFS->Mount(L"", TEST_FOLDER / "mod_0", 0, 0);
|
||||
g_VFS->Mount(L"", TEST_FOLDER / "mod_1", 0, 1);
|
||||
g_VFS->Mount(L"folder/subfolder/", TEST_FOLDER / "other_folder", 0, 2);
|
||||
|
||||
OsPath realPath;
|
||||
g_VFS->GetDirectoryRealPath(L"folder/subfolder/", realPath);
|
||||
TS_ASSERT_EQUALS(realPath, TEST_FOLDER / "other_folder");
|
||||
};
|
||||
};
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2021 Wildfire Games.
|
||||
/* Copyright (C) 2019 Wildfire Games.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
@ -47,7 +47,11 @@ class TestVfsUtil : public CxxTest::TestSuite
|
||||
g_VFS = CreateVfs();
|
||||
|
||||
TS_ASSERT_OK(g_VFS->Mount(L"", MOD_PATH));
|
||||
TS_ASSERT_OK(g_VFS->Mount(L"cache/", CACHE_PATH, 0, VFS_MAX_PRIORITY));
|
||||
|
||||
// Mount _testcache onto virtual /cache - don't use the normal cache
|
||||
// directory because that's full of loads of cached files from the
|
||||
// proper game and takes a long time to load.
|
||||
TS_ASSERT_OK(g_VFS->Mount(L"cache/", CACHE_PATH));
|
||||
}
|
||||
|
||||
void deinitVfs()
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2021 Wildfire Games.
|
||||
/* Copyright (C) 2017 Wildfire Games.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
@ -129,7 +129,7 @@ public:
|
||||
std::lock_guard<std::mutex> lock(vfs_mutex);
|
||||
VfsDirectory* directory;
|
||||
Status st;
|
||||
st = vfs_Lookup(pathname, &m_rootDirectory, directory, 0, VFS_LOOKUP_ADD|VFS_LOOKUP_REAL_PATH);
|
||||
st = vfs_Lookup(pathname, &m_rootDirectory, directory, 0, VFS_LOOKUP_ADD|VFS_LOOKUP_CREATE|VFS_LOOKUP_CREATE_ALWAYS);
|
||||
if (st == ERR::FILE_ACCESS)
|
||||
return ERR::FILE_ACCESS;
|
||||
|
||||
@ -146,6 +146,32 @@ public:
|
||||
return INFO::OK;
|
||||
}
|
||||
|
||||
virtual Status ReplaceFile(const VfsPath& pathname, const shared_ptr<u8>& fileContents, size_t size)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(vfs_mutex);
|
||||
VfsDirectory* directory;
|
||||
VfsFile* file;
|
||||
Status st;
|
||||
st = vfs_Lookup(pathname, &m_rootDirectory, directory, &file, VFS_LOOKUP_ADD|VFS_LOOKUP_CREATE);
|
||||
|
||||
// There is no such file, create it.
|
||||
if (st == ERR::VFS_FILE_NOT_FOUND)
|
||||
{
|
||||
lock.unlock();
|
||||
return CreateFile(pathname, fileContents, size);
|
||||
}
|
||||
|
||||
WARN_RETURN_STATUS_IF_ERR(st);
|
||||
|
||||
RealDirectory realDirectory(file->Loader()->Path(), file->Priority(), directory->AssociatedDirectory()->Flags());
|
||||
RETURN_STATUS_IF_ERR(realDirectory.Store(pathname.Filename(), fileContents, size));
|
||||
|
||||
directory->AddFile(*file);
|
||||
|
||||
m_trace->NotifyStore(pathname, size);
|
||||
return INFO::OK;
|
||||
}
|
||||
|
||||
virtual Status LoadFile(const VfsPath& pathname, shared_ptr<u8>& fileContents, size_t& size)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(vfs_mutex);
|
||||
@ -177,7 +203,7 @@ public:
|
||||
return textRepresentation;
|
||||
}
|
||||
|
||||
virtual Status GetOriginalPath(const VfsPath& pathname, OsPath& realPathname)
|
||||
virtual Status GetRealPath(const VfsPath& pathname, OsPath& realPathname)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(vfs_mutex);
|
||||
VfsDirectory* directory; VfsFile* file;
|
||||
@ -186,24 +212,11 @@ public:
|
||||
return INFO::OK;
|
||||
}
|
||||
|
||||
virtual Status GetRealPath(const VfsPath& pathname, OsPath& realPathname, bool createMissingDirectories)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(vfs_mutex);
|
||||
VfsDirectory* directory; VfsFile* file;
|
||||
size_t flags = VFS_LOOKUP_REAL_PATH | (createMissingDirectories ? VFS_LOOKUP_ADD : 0);
|
||||
WARN_RETURN_STATUS_IF_ERR(vfs_Lookup(pathname, &m_rootDirectory, directory, &file, flags));
|
||||
ENSURE(directory->AssociatedDirectory());
|
||||
realPathname = directory->AssociatedDirectory()->Path() / pathname.Filename();
|
||||
return INFO::OK;
|
||||
}
|
||||
|
||||
virtual Status GetDirectoryRealPath(const VfsPath& pathname, OsPath& realPathname, bool createMissingDirectories)
|
||||
virtual Status GetDirectoryRealPath(const VfsPath& pathname, OsPath& realPathname)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(vfs_mutex);
|
||||
VfsDirectory* directory;
|
||||
size_t flags = VFS_LOOKUP_REAL_PATH | (createMissingDirectories ? VFS_LOOKUP_ADD : 0);
|
||||
WARN_RETURN_STATUS_IF_ERR(vfs_Lookup(pathname, &m_rootDirectory, directory, NULL, flags));
|
||||
ENSURE(directory->AssociatedDirectory());
|
||||
WARN_RETURN_STATUS_IF_ERR(vfs_Lookup(pathname, &m_rootDirectory, directory, NULL));
|
||||
realPathname = directory->AssociatedDirectory()->Path();
|
||||
return INFO::OK;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2021 Wildfire Games.
|
||||
/* Copyright (C) 2017 Wildfire Games.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
@ -31,9 +31,6 @@
|
||||
#include "lib/file/file_system.h" // CFileInfo
|
||||
#include "lib/file/vfs/vfs_path.h"
|
||||
|
||||
constexpr size_t VFS_MIN_PRIORITY = 0;
|
||||
constexpr size_t VFS_MAX_PRIORITY = std::numeric_limits<size_t>::max();
|
||||
|
||||
namespace ERR
|
||||
{
|
||||
const Status VFS_DIR_NOT_FOUND = -110100;
|
||||
@ -68,7 +65,16 @@ enum VfsMountFlags
|
||||
* ".DELETED" suffix will still apply.
|
||||
* (the default behavior is to hide both the suffixed and unsuffixed files)
|
||||
**/
|
||||
VFS_MOUNT_KEEP_DELETED = 8
|
||||
VFS_MOUNT_KEEP_DELETED = 8,
|
||||
|
||||
/**
|
||||
* mark a directory replaceable, so that when writing a file to this path
|
||||
* new real directories will be created instead of reusing already existing
|
||||
* ones mounted at a subpath of the VFS path.
|
||||
* (the default behaviour is to write to the real directory associated
|
||||
* with the VFS directory that was last mounted to this path (or subpath))
|
||||
**/
|
||||
VFS_MOUNT_REPLACEABLE = 16
|
||||
};
|
||||
|
||||
// (member functions are thread-safe after the instance has been
|
||||
@ -89,11 +95,6 @@ struct IVFS
|
||||
* if files are encountered that already exist in the VFS (sub)directories,
|
||||
* the most recent / highest priority/precedence version is preferred.
|
||||
*
|
||||
* Note that the 'real directory' associated with a VFS Path
|
||||
* will be relative to the highest priority subdirectory in the path,
|
||||
* and that in case of equal priority, the order is _undefined_,
|
||||
* and will depend on the exact order of populate() calls.
|
||||
*
|
||||
* if files with archive extensions are seen, their contents are added
|
||||
* as well.
|
||||
**/
|
||||
@ -142,6 +143,17 @@ struct IVFS
|
||||
**/
|
||||
virtual Status CreateFile(const VfsPath& pathname, const shared_ptr<u8>& fileContents, size_t size) = 0;
|
||||
|
||||
/**
|
||||
* Replace a file with the given contents.
|
||||
*
|
||||
* @see CreateFile
|
||||
*
|
||||
* Used to replace a file if it is already present (even if the file is not
|
||||
* in the attached vfs directory). Calls CreateFile if the file doesn't yet
|
||||
* exist.
|
||||
**/
|
||||
virtual Status ReplaceFile(const VfsPath& pathname, const shared_ptr<u8>& fileContents, size_t size) = 0;
|
||||
|
||||
/**
|
||||
* Read an entire file into memory.
|
||||
*
|
||||
@ -158,32 +170,18 @@ struct IVFS
|
||||
virtual std::wstring TextRepresentation() const = 0;
|
||||
|
||||
/**
|
||||
* Retrieve the POSIX pathname a VFS file was loaded from.
|
||||
* This is distinct from the current 'real' path, since that depends on the parent directory's real path,
|
||||
* which may have been overwritten by a mod or another call to Mount().
|
||||
* retrieve the real (POSIX) pathname underlying a VFS file.
|
||||
*
|
||||
* This is used by the caching to split by mod, and you also ought to call this to delete a file.
|
||||
* (note that deleting has other issues, see below).
|
||||
* this is useful for passing paths to external libraries.
|
||||
**/
|
||||
virtual Status GetOriginalPath(const VfsPath& filename, OsPath& loadedPathname) = 0;
|
||||
virtual Status GetRealPath(const VfsPath& pathname, OsPath& realPathname) = 0;
|
||||
|
||||
/**
|
||||
* Retrieve the real (POSIX) pathname underlying a VFS file.
|
||||
* This is useful for passing paths to external libraries.
|
||||
* Note that this returns the real path relative to the highest priority VFS subpath.
|
||||
* @param createMissingDirectories - if true, create subdirectories on the file system as required.
|
||||
* (this defaults to true because, in general, this function is then used to create new files).
|
||||
* retrieve the real (POSIX) pathname underlying a VFS directory.
|
||||
*
|
||||
* this is useful for passing paths to external libraries.
|
||||
**/
|
||||
virtual Status GetRealPath(const VfsPath& pathname, OsPath& realPathname, bool createMissingDirectories = true) = 0;
|
||||
|
||||
/**
|
||||
* Retrieve the real (POSIX) pathname underlying a VFS directory.
|
||||
* This is useful for passing paths to external libraries.
|
||||
* Note that this returns the real path relative to the highest priority VFS subpath.
|
||||
* @param createMissingDirectories - if true, create subdirectories on the file system as required.
|
||||
* (this defaults to true because, in general, this function is then used to create new files).
|
||||
**/
|
||||
virtual Status GetDirectoryRealPath(const VfsPath& pathname, OsPath& realPathname, bool createMissingDirectories = true) = 0;
|
||||
virtual Status GetDirectoryRealPath(const VfsPath& pathname, OsPath& realPathname) = 0;
|
||||
|
||||
/**
|
||||
* retrieve the VFS pathname that corresponds to a real file.
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2021 Wildfire Games.
|
||||
/* Copyright (C) 2013 Wildfire Games.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
@ -47,12 +47,14 @@ static Status CreateDirectory(const OsPath& path)
|
||||
return INFO::OK;
|
||||
}
|
||||
|
||||
// Failed because the directory already exists.
|
||||
// Return 'success' to attach the existing directory.
|
||||
// failed because the directory already exists. this can happen
|
||||
// when the first vfs_Lookup has addMissingDirectories &&
|
||||
// !createMissingDirectories, and the directory is subsequently
|
||||
// created. return 'success' to attach the existing directory..
|
||||
if(errno == EEXIST)
|
||||
{
|
||||
// But first ensure it's really a directory
|
||||
// (otherwise, a file is "in the way" and needs to be deleted).
|
||||
// but first ensure it's really a directory (otherwise, a
|
||||
// file is "in the way" and needs to be deleted)
|
||||
struct stat s;
|
||||
const int ret = wstat(path, &s);
|
||||
ENSURE(ret == 0); // (wmkdir said it existed)
|
||||
@ -74,23 +76,22 @@ Status vfs_Lookup(const VfsPath& pathname, VfsDirectory* startDirectory, VfsDire
|
||||
{
|
||||
// extract and validate flags (ensure no unknown bits are set)
|
||||
const bool addMissingDirectories = (flags & VFS_LOOKUP_ADD) != 0;
|
||||
const bool createMissingDirectories = (flags & VFS_LOOKUP_CREATE) != 0;
|
||||
const bool skipPopulate = (flags & VFS_LOOKUP_SKIP_POPULATE) != 0;
|
||||
const bool realPath = (flags & VFS_LOOKUP_REAL_PATH) != 0;
|
||||
ENSURE((flags & ~(VFS_LOOKUP_ADD|VFS_LOOKUP_SKIP_POPULATE|VFS_LOOKUP_REAL_PATH)) == 0);
|
||||
const bool createAlways = (flags & VFS_LOOKUP_CREATE_ALWAYS) != 0;
|
||||
ENSURE((flags & ~(VFS_LOOKUP_ADD|VFS_LOOKUP_CREATE|VFS_LOOKUP_SKIP_POPULATE|VFS_LOOKUP_CREATE_ALWAYS)) == 0);
|
||||
|
||||
directory = startDirectory;
|
||||
if (pfile)
|
||||
if(pfile)
|
||||
*pfile = 0;
|
||||
|
||||
if (!skipPopulate)
|
||||
if(!skipPopulate)
|
||||
RETURN_STATUS_IF_ERR(vfs_Populate(directory));
|
||||
|
||||
// early-out for pathname == "" when mounting into VFS root
|
||||
if (pathname.empty()) // (prevent iterator error in loop end condition)
|
||||
if(pathname.empty()) // (prevent iterator error in loop end condition)
|
||||
{
|
||||
// Preserve a guarantee that if pfile then we either return an error or set *pfile,
|
||||
// and if looking for a real path ensure an associated directory.
|
||||
if (pfile || (realPath && !directory->AssociatedDirectory()))
|
||||
if(pfile) // preserve a guarantee that if pfile then we either return an error or set *pfile
|
||||
return ERR::VFS_FILE_NOT_FOUND;
|
||||
else
|
||||
return INFO::OK;
|
||||
@ -101,60 +102,46 @@ Status vfs_Lookup(const VfsPath& pathname, VfsDirectory* startDirectory, VfsDire
|
||||
for(;;)
|
||||
{
|
||||
const size_t nextSlash = pathname.string().find_first_of('/', pos);
|
||||
if (nextSlash == VfsPath::String::npos)
|
||||
if(nextSlash == VfsPath::String::npos)
|
||||
break;
|
||||
const VfsPath subdirectoryName = pathname.string().substr(pos, nextSlash-pos);
|
||||
pos = nextSlash+1;
|
||||
|
||||
VfsDirectory* subdirectory = directory->GetSubdirectory(subdirectoryName);
|
||||
if (!subdirectory)
|
||||
if(!subdirectory)
|
||||
{
|
||||
if (addMissingDirectories)
|
||||
if(addMissingDirectories)
|
||||
subdirectory = directory->AddSubdirectory(subdirectoryName);
|
||||
else
|
||||
return ERR::VFS_DIR_NOT_FOUND; // NOWARN
|
||||
}
|
||||
// When looking for a real path, we need to keep the path of the highest priority subdirectory.
|
||||
// If the current directory has an associated directory, and the subdir does not / is lower priority,
|
||||
// we will overwrite it.
|
||||
PRealDirectory realDir = directory->AssociatedDirectory();
|
||||
if (realPath && realDir &&
|
||||
(!subdirectory->AssociatedDirectory() ||
|
||||
realDir->Priority() > subdirectory->AssociatedDirectory()->Priority()))
|
||||
|
||||
if(createMissingDirectories && (!subdirectory->AssociatedDirectory()
|
||||
|| (createAlways && (subdirectory->AssociatedDirectory()->Flags() & VFS_MOUNT_REPLACEABLE) != 0)))
|
||||
{
|
||||
OsPath currentPath = directory->AssociatedDirectory()->Path();
|
||||
OsPath currentPath;
|
||||
if(directory->AssociatedDirectory()) // (is NULL when mounting into root)
|
||||
currentPath = directory->AssociatedDirectory()->Path();
|
||||
currentPath = currentPath / subdirectoryName;
|
||||
|
||||
// Only actually create the directory if we're in LOOKUP_ADD mode.
|
||||
if (addMissingDirectories)
|
||||
RETURN_STATUS_IF_ERR(CreateDirectory(currentPath));
|
||||
else if (!DirectoryExists(currentPath))
|
||||
return ERR::VFS_DIR_NOT_FOUND;
|
||||
RETURN_STATUS_IF_ERR(CreateDirectory(currentPath));
|
||||
|
||||
// Propagate priority and flags to the subdirectory.
|
||||
// If it already existed, it will be replaced & the memory freed.
|
||||
PRealDirectory realDirectory(new RealDirectory(currentPath,
|
||||
realDir ? realDir->Priority() : 0,
|
||||
realDir ? realDir->Flags() : 0)
|
||||
);
|
||||
PRealDirectory realDirectory(new RealDirectory(currentPath, 0, 0));
|
||||
RETURN_STATUS_IF_ERR(vfs_Attach(subdirectory, realDirectory));
|
||||
}
|
||||
|
||||
if (!skipPopulate)
|
||||
if(!skipPopulate)
|
||||
RETURN_STATUS_IF_ERR(vfs_Populate(subdirectory));
|
||||
|
||||
directory = subdirectory;
|
||||
}
|
||||
|
||||
if (realPath && !directory->AssociatedDirectory())
|
||||
return ERR::VFS_DIR_NOT_FOUND;
|
||||
|
||||
if (pfile)
|
||||
if(pfile)
|
||||
{
|
||||
ENSURE(!pathname.IsDirectory());
|
||||
const VfsPath filename = pathname.string().substr(pos);
|
||||
*pfile = directory->GetFile(filename);
|
||||
if (!*pfile)
|
||||
if(!*pfile)
|
||||
return ERR::VFS_FILE_NOT_FOUND; // NOWARN
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2021 Wildfire Games.
|
||||
/* Copyright (C) 2013 Wildfire Games.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
@ -37,24 +37,24 @@ class VfsDirectory;
|
||||
|
||||
enum VfsLookupFlags
|
||||
{
|
||||
// Add (if they do not already exist) subdirectory components
|
||||
// add (if they do not already exist) subdirectory components
|
||||
// encountered in the path[name].
|
||||
// If subdirectores do not exist on disk, they will be created.
|
||||
VFS_LOOKUP_ADD = 1,
|
||||
|
||||
// Don't populate the directories encountered. This makes sense
|
||||
// if VFS directories encountered are not already associated
|
||||
// with a real directory, do so (creating the directories
|
||||
// if they do not already exist).
|
||||
VFS_LOOKUP_CREATE = 2,
|
||||
|
||||
// don't populate the directories encountered. this makes sense
|
||||
// when adding files from an archive, which would otherwise
|
||||
// cause nearly every directory to be populated.
|
||||
VFS_LOOKUP_SKIP_POPULATE = 2,
|
||||
VFS_LOOKUP_SKIP_POPULATE = 4,
|
||||
|
||||
// Perform a 'real path' lookup.
|
||||
// Because the VFS maps multiple 'disk paths' to a single tree of paths,
|
||||
// the 'real directory' of a VFS directory at any given time may be almost anything,
|
||||
// in particular not its real parent directory on disk.
|
||||
// To make writing predictable, we'll return a path relative to the 'disk path' of the
|
||||
// highest priority subdirectory found in the lookup path.
|
||||
// See test_vfs_real_paths.h for examples of this behaviour.
|
||||
VFS_LOOKUP_REAL_PATH = 4
|
||||
// even create directories if they are already present, this is
|
||||
// useful to write new files to the directory that was attached
|
||||
// last, if the directory wasn't mounted with VFS_MOUNT_REPLACEABLE
|
||||
VFS_LOOKUP_CREATE_ALWAYS = 8
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2021 Wildfire Games.
|
||||
/* Copyright (C) 2020 Wildfire Games.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
@ -168,29 +168,7 @@ Status vfs_Populate(VfsDirectory* directory)
|
||||
|
||||
Status vfs_Attach(VfsDirectory* directory, const PRealDirectory& realDirectory)
|
||||
{
|
||||
PRealDirectory existingRealDir = directory->AssociatedDirectory();
|
||||
|
||||
// Don't allow replacing the real directory by a lower-priority one.
|
||||
if (!existingRealDir || existingRealDir->Priority() < realDirectory->Priority())
|
||||
{
|
||||
// This ordering is peculiar but useful, as it "defers" the population call.
|
||||
// If there is already a real directory, we will replace it (and lose track of it),
|
||||
// so we'll populate it right away, but the 'new' real directory can wait until we access it.
|
||||
RETURN_STATUS_IF_ERR(vfs_Populate(directory));
|
||||
directory->SetAssociatedDirectory(realDirectory);
|
||||
return INFO::OK;
|
||||
}
|
||||
// We are attaching a lower-priority real directory.
|
||||
// Because of deferred population, we need to immediately populate this new directory.
|
||||
bool shouldPop = directory->ShouldPopulate();
|
||||
// This sets "should populate" to true, so the vfs_Populate call below immediately populates.
|
||||
directory->SetAssociatedDirectory(realDirectory);
|
||||
RETURN_STATUS_IF_ERR(vfs_Populate(directory));
|
||||
// Reset to the higher priority realDirectory, which resets ShouldPopulate to true.
|
||||
directory->SetAssociatedDirectory(existingRealDir);
|
||||
// Avoid un-necessary repopulation by clearing the flag.
|
||||
if (!shouldPop)
|
||||
directory->ShouldPopulate();
|
||||
|
||||
directory->SetAssociatedDirectory(realDirectory);
|
||||
return INFO::OK;
|
||||
}
|
||||
|
@ -593,8 +593,7 @@ static void RunGameOrAtlas(int argc, const char* argv[])
|
||||
|
||||
Paths paths(args);
|
||||
g_VFS = CreateVfs();
|
||||
// Mount with highest priority, we don't want mods overwriting this.
|
||||
g_VFS->Mount(L"cache/", paths.Cache(), VFS_MOUNT_ARCHIVABLE, VFS_MAX_PRIORITY);
|
||||
g_VFS->Mount(L"cache/", paths.Cache(), VFS_MOUNT_ARCHIVABLE);
|
||||
MountMods(paths, GetMods(args, INIT_MODS));
|
||||
|
||||
{
|
||||
|
@ -41,7 +41,7 @@ public:
|
||||
{
|
||||
g_VFS = CreateVfs();
|
||||
TS_ASSERT_OK(g_VFS->Mount(L"", DataDir()/"mods"/"public", VFS_MOUNT_MUST_EXIST));
|
||||
TS_ASSERT_OK(g_VFS->Mount(L"cache", DataDir()/"_testcache", 0, VFS_MAX_PRIORITY));
|
||||
TS_ASSERT_OK(g_VFS->Mount(L"cache", DataDir()/"_testcache"));
|
||||
CXeromyces::Startup();
|
||||
|
||||
// Need some stuff for terrain movement costs:
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2021 Wildfire Games.
|
||||
/* Copyright (C) 2020 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -35,10 +35,10 @@ CArchiveBuilder::CArchiveBuilder(const OsPath& mod, const OsPath& tempdir) :
|
||||
|
||||
DeleteDirectory(m_TempDir/"_archivecache"); // clean up in case the last run failed
|
||||
|
||||
m_VFS->Mount(L"cache/", m_TempDir/"_archivecache"/"", 0, VFS_MAX_PRIORITY);
|
||||
m_VFS->Mount(L"cache/", m_TempDir/"_archivecache"/"");
|
||||
|
||||
// Mount with highest priority so base mods do not overwrite files in this mod
|
||||
m_VFS->Mount(L"", mod/"", VFS_MOUNT_MUST_EXIST | VFS_MOUNT_KEEP_DELETED, VFS_MAX_PRIORITY);
|
||||
m_VFS->Mount(L"", mod/"", VFS_MOUNT_MUST_EXIST | VFS_MOUNT_KEEP_DELETED, (size_t)-1);
|
||||
|
||||
// Collect the list of files before loading any base mods
|
||||
vfs::ForEachFile(m_VFS, L"", &CollectFileCB, (uintptr_t)static_cast<void*>(this), 0, vfs::DIR_RECURSIVE);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2021 Wildfire Games.
|
||||
/* Copyright (C) 2018 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -140,7 +140,7 @@ VfsPath CCacheLoader::LooseCachePath(const VfsPath& sourcePath, const MD5& initi
|
||||
|
||||
// Get the mod path
|
||||
OsPath path;
|
||||
m_VFS->GetOriginalPath(sourcePath, path);
|
||||
m_VFS->GetRealPath(sourcePath, path);
|
||||
|
||||
return VfsPath("cache") /
|
||||
path_name_only(path.BeforeCommon(sourcePath).Parent().string().c_str()) /
|
||||
|
@ -375,10 +375,17 @@ ErrorReactionInternal psDisplayError(const wchar_t* UNUSED(text), size_t UNUSED(
|
||||
const std::vector<CStr>& GetMods(const CmdLineArgs& args, int flags)
|
||||
{
|
||||
const bool init_mods = (flags & INIT_MODS) == INIT_MODS;
|
||||
const bool add_user = !InDevelopmentCopy() && !args.Has("noUserMod");
|
||||
const bool add_public = (flags & INIT_MODS_PUBLIC) == INIT_MODS_PUBLIC;
|
||||
|
||||
if (!init_mods)
|
||||
{
|
||||
// Add the user mod if it should be present
|
||||
if (add_user && (g_modsLoaded.empty() || g_modsLoaded.back() != "user"))
|
||||
g_modsLoaded.push_back("user");
|
||||
|
||||
return g_modsLoaded;
|
||||
}
|
||||
|
||||
g_modsLoaded = args.GetMultiple("mod");
|
||||
|
||||
@ -387,6 +394,11 @@ const std::vector<CStr>& GetMods(const CmdLineArgs& args, int flags)
|
||||
|
||||
g_modsLoaded.insert(g_modsLoaded.begin(), "mod");
|
||||
|
||||
// Add the user mod if not explicitly disabled or we have a dev copy so
|
||||
// that saved files end up in version control and not in the user mod.
|
||||
if (add_user)
|
||||
g_modsLoaded.push_back("user");
|
||||
|
||||
return g_modsLoaded;
|
||||
}
|
||||
|
||||
@ -394,24 +406,29 @@ void MountMods(const Paths& paths, const std::vector<CStr>& mods)
|
||||
{
|
||||
OsPath modPath = paths.RData()/"mods";
|
||||
OsPath modUserPath = paths.UserData()/"mods";
|
||||
|
||||
size_t userFlags = VFS_MOUNT_WATCH|VFS_MOUNT_ARCHIVABLE;
|
||||
size_t baseFlags = userFlags|VFS_MOUNT_MUST_EXIST;
|
||||
size_t priority;
|
||||
for (size_t i = 0; i < mods.size(); ++i)
|
||||
{
|
||||
priority = i + 1; // Mods are higher priority than regular mountings, which default to priority 0
|
||||
size_t priority = (i+1)*2; // mods are higher priority than regular mountings, which default to priority 0
|
||||
size_t userFlags = VFS_MOUNT_WATCH|VFS_MOUNT_ARCHIVABLE|VFS_MOUNT_REPLACEABLE;
|
||||
size_t baseFlags = userFlags|VFS_MOUNT_MUST_EXIST;
|
||||
|
||||
OsPath modName(mods[i]);
|
||||
// Only mount mods from the user path if they don't exist in the 'rdata' path.
|
||||
if (DirectoryExists(modPath / modName/""))
|
||||
g_VFS->Mount(L"", modPath / modName/"", baseFlags, priority);
|
||||
if (InDevelopmentCopy())
|
||||
{
|
||||
// We are running a dev copy, so only mount mods in the user mod path
|
||||
// if the mod does not exist in the data path.
|
||||
if (DirectoryExists(modPath / modName/""))
|
||||
g_VFS->Mount(L"", modPath / modName/"", baseFlags, priority);
|
||||
else
|
||||
g_VFS->Mount(L"", modUserPath / modName/"", userFlags, priority);
|
||||
}
|
||||
else
|
||||
g_VFS->Mount(L"", modUserPath / modName/"", userFlags, priority);
|
||||
{
|
||||
g_VFS->Mount(L"", modPath / modName/"", baseFlags, priority);
|
||||
// Ensure that user modified files are loaded, if they are present
|
||||
g_VFS->Mount(L"", modUserPath / modName/"", userFlags, priority+1);
|
||||
}
|
||||
}
|
||||
|
||||
// Mount the user mod last. In dev copy, mount it with a low priority. Otherwise, make it writable.
|
||||
g_VFS->Mount(L"", modUserPath / "user", userFlags, InDevelopmentCopy() ? 0 : priority + 1);
|
||||
}
|
||||
|
||||
static void InitVfs(const CmdLineArgs& args, int flags)
|
||||
@ -438,20 +455,23 @@ static void InitVfs(const CmdLineArgs& args, int flags)
|
||||
g_VFS = CreateVfs();
|
||||
|
||||
const OsPath readonlyConfig = paths.RData()/"config"/"";
|
||||
g_VFS->Mount(L"config/", readonlyConfig);
|
||||
|
||||
// Mount these dirs with highest priority so that mods can't overwrite them.
|
||||
g_VFS->Mount(L"cache/", paths.Cache(), VFS_MOUNT_ARCHIVABLE, VFS_MAX_PRIORITY); // (adding XMBs to archive speeds up subsequent reads)
|
||||
if (readonlyConfig != paths.Config())
|
||||
g_VFS->Mount(L"config/", readonlyConfig, 0, VFS_MAX_PRIORITY-1);
|
||||
g_VFS->Mount(L"config/", paths.Config(), 0, VFS_MAX_PRIORITY);
|
||||
g_VFS->Mount(L"screenshots/", paths.UserData()/"screenshots"/"", 0, VFS_MAX_PRIORITY);
|
||||
g_VFS->Mount(L"saves/", paths.UserData()/"saves"/"", VFS_MOUNT_WATCH, VFS_MAX_PRIORITY);
|
||||
|
||||
// Engine localization files (regular priority, these can be overwritten).
|
||||
// Engine localization files.
|
||||
g_VFS->Mount(L"l10n/", paths.RData()/"l10n"/"");
|
||||
|
||||
MountMods(paths, GetMods(args, flags));
|
||||
|
||||
// We mount these dirs last as otherwise writing could result in files being placed in a mod's dir.
|
||||
g_VFS->Mount(L"screenshots/", paths.UserData()/"screenshots"/"");
|
||||
g_VFS->Mount(L"saves/", paths.UserData()/"saves"/"", VFS_MOUNT_WATCH);
|
||||
// Mounting with highest priority, so that a mod supplied user.cfg is harmless
|
||||
g_VFS->Mount(L"config/", readonlyConfig, 0, (size_t)-1);
|
||||
if(readonlyConfig != paths.Config())
|
||||
g_VFS->Mount(L"config/", paths.Config(), 0, (size_t)-1);
|
||||
|
||||
g_VFS->Mount(L"cache/", paths.Cache(), VFS_MOUNT_ARCHIVABLE); // (adding XMBs to archive speeds up subsequent reads)
|
||||
|
||||
// note: don't bother with g_VFS->TextRepresentation - directories
|
||||
// haven't yet been populated and are empty.
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2021 Wildfire Games.
|
||||
/* Copyright (C) 2020 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -59,8 +59,7 @@ JS::Value Mod::GetAvailableMods(const ScriptInterface& scriptInterface)
|
||||
for (DirectoryNames::iterator iter = modDirs.begin(); iter != modDirs.end(); ++iter)
|
||||
{
|
||||
vfs->Clear();
|
||||
// Mount with lowest priority, we don't want to overwrite anything
|
||||
if (vfs->Mount(L"", modPath / *iter, VFS_MOUNT_MUST_EXIST, VFS_MIN_PRIORITY) < 0)
|
||||
if (vfs->Mount(L"", modPath / *iter, VFS_MOUNT_MUST_EXIST) < 0)
|
||||
continue;
|
||||
|
||||
CVFSFile modinfo;
|
||||
@ -86,8 +85,7 @@ JS::Value Mod::GetAvailableMods(const ScriptInterface& scriptInterface)
|
||||
continue;
|
||||
|
||||
vfs->Clear();
|
||||
// Mount with lowest priority, we don't want to overwrite anything
|
||||
if (vfs->Mount(L"", modUserPath / *iter, VFS_MOUNT_MUST_EXIST, VFS_MIN_PRIORITY) < 0)
|
||||
if (vfs->Mount(L"", modUserPath / *iter, VFS_MOUNT_MUST_EXIST) < 0)
|
||||
continue;
|
||||
|
||||
CVFSFile modinfo;
|
||||
@ -116,8 +114,8 @@ void Mod::CacheEnabledModVersions(const shared_ptr<ScriptContext>& scriptContext
|
||||
|
||||
for (const CStr& mod : g_modsLoaded)
|
||||
{
|
||||
// Ignore mod mod as it is irrelevant for compatibility checks
|
||||
if (mod == "mod")
|
||||
// Ignore user and mod mod as they are irrelevant for compatibility checks
|
||||
if (mod == "mod" || mod == "user")
|
||||
continue;
|
||||
|
||||
CStr version;
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2021 Wildfire Games.
|
||||
/* Copyright (C) 2020 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -284,8 +284,8 @@ bool SavedGames::DeleteSavedGame(const std::wstring& name)
|
||||
const VfsPath filename = basename.ChangeExtension(L".0adsave");
|
||||
OsPath realpath;
|
||||
|
||||
// Make sure it exists in VFS and find its path
|
||||
if (!VfsFileExists(filename) || g_VFS->GetOriginalPath(filename, realpath) != INFO::OK)
|
||||
// Make sure it exists in VFS and find its real path
|
||||
if (!VfsFileExists(filename) || g_VFS->GetRealPath(filename, realpath) != INFO::OK)
|
||||
return false; // Error
|
||||
|
||||
// Remove from VFS
|
||||
|
@ -41,7 +41,7 @@ public:
|
||||
g_VFS = CreateVfs();
|
||||
g_VFS->Mount(L"", DataDir()/"mods"/"mod", VFS_MOUNT_MUST_EXIST);
|
||||
g_VFS->Mount(L"", DataDir()/"mods"/"public", VFS_MOUNT_MUST_EXIST, 1); // ignore directory-not-found errors
|
||||
TS_ASSERT_OK(g_VFS->Mount(L"cache", DataDir()/"_testcache", 0, VFS_MAX_PRIORITY));
|
||||
TS_ASSERT_OK(g_VFS->Mount(L"cache", DataDir()/"_testcache"));
|
||||
|
||||
CXeromyces::Startup();
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2021 Wildfire Games.
|
||||
/* Copyright (C) 2020 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -38,7 +38,7 @@ public:
|
||||
{
|
||||
g_VFS = CreateVfs();
|
||||
TS_ASSERT_OK(g_VFS->Mount(L"", DataDir()/"mods"/"_test.sim", VFS_MOUNT_MUST_EXIST));
|
||||
TS_ASSERT_OK(g_VFS->Mount(L"cache", DataDir()/"_testcache", 0, VFS_MAX_PRIORITY));
|
||||
TS_ASSERT_OK(g_VFS->Mount(L"cache", DataDir()/"_testcache"));
|
||||
CXeromyces::Startup();
|
||||
}
|
||||
|
||||
@ -223,7 +223,7 @@ public:
|
||||
g_VFS = CreateVfs();
|
||||
TS_ASSERT_OK(g_VFS->Mount(L"", DataDir()/"mods"/"mod", VFS_MOUNT_MUST_EXIST));
|
||||
TS_ASSERT_OK(g_VFS->Mount(L"", DataDir()/"mods"/"public", VFS_MOUNT_MUST_EXIST));
|
||||
TS_ASSERT_OK(g_VFS->Mount(L"cache", DataDir()/"_testcache", 0, VFS_MAX_PRIORITY));
|
||||
TS_ASSERT_OK(g_VFS->Mount(L"cache", DataDir()/"_testcache"));
|
||||
CXeromyces::Startup();
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2021 Wildfire Games.
|
||||
/* Copyright (C) 2020 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -45,7 +45,7 @@ public:
|
||||
{
|
||||
g_VFS = CreateVfs();
|
||||
TS_ASSERT_OK(g_VFS->Mount(L"", DataDir()/"mods"/"_test.sim", VFS_MOUNT_MUST_EXIST));
|
||||
TS_ASSERT_OK(g_VFS->Mount(L"cache", DataDir()/"_testcache", 0, VFS_MAX_PRIORITY));
|
||||
TS_ASSERT_OK(g_VFS->Mount(L"cache", DataDir()/"_testcache"));
|
||||
CXeromyces::Startup();
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2021 Wildfire Games.
|
||||
/* Copyright (C) 2020 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -876,7 +876,7 @@ public:
|
||||
|
||||
g_VFS = CreateVfs();
|
||||
TS_ASSERT_OK(g_VFS->Mount(L"", DataDir()/"mods"/"public", VFS_MOUNT_MUST_EXIST));
|
||||
TS_ASSERT_OK(g_VFS->Mount(L"cache", DataDir()/"_testcache", 0, VFS_MAX_PRIORITY));
|
||||
TS_ASSERT_OK(g_VFS->Mount(L"cache", DataDir()/"_testcache"));
|
||||
|
||||
// Need some stuff for terrain movement costs:
|
||||
// (TODO: this ought to be independent of any graphics code)
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2021 Wildfire Games.
|
||||
/* Copyright (C) 2019 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -44,7 +44,7 @@ public:
|
||||
{
|
||||
g_VFS = CreateVfs();
|
||||
TS_ASSERT_OK(g_VFS->Mount(L"", DataDir()/"mods"/"_test.sim", VFS_MOUNT_MUST_EXIST));
|
||||
TS_ASSERT_OK(g_VFS->Mount(L"cache", DataDir()/"_testcache", 0, VFS_MAX_PRIORITY));
|
||||
TS_ASSERT_OK(g_VFS->Mount(L"cache", DataDir()/"_testcache"));
|
||||
CXeromyces::Startup();
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user