Merge pull request #83 from diamante0018/containers-are-lovely
feat: containers!
This commit is contained in:
commit
9adedb4062
@ -245,8 +245,6 @@ namespace Components
|
||||
|
||||
const char* FastFiles::GetZoneLocation(const char* file)
|
||||
{
|
||||
const auto* dir = (*Game::fs_basepath)->current.string;
|
||||
|
||||
std::vector<std::string> paths;
|
||||
const std::string fsGame = (*Game::fs_gameDirVar)->current.string;
|
||||
|
||||
@ -270,6 +268,7 @@ namespace Components
|
||||
Utils::String::Replace(zone, "_load", "");
|
||||
}
|
||||
|
||||
// Only check for usermaps on our working directory
|
||||
if (Utils::IO::FileExists(std::format("usermaps\\{}\\{}.ff", zone, filename)))
|
||||
{
|
||||
return Utils::String::Format("usermaps\\{}\\", zone);
|
||||
@ -280,6 +279,7 @@ namespace Components
|
||||
|
||||
for (auto& path : paths)
|
||||
{
|
||||
const auto* dir = (*Game::fs_basepath)->current.string;
|
||||
auto absoluteFile = std::format("{}\\{}{}", dir, path, file);
|
||||
|
||||
// No ".ff" appended, append it manually
|
||||
@ -506,11 +506,74 @@ namespace Components
|
||||
return Utils::Hook::Call<void(int, int)>(0x004925B0)(atStreamStart, surface->numsurfs);
|
||||
}
|
||||
|
||||
void FastFiles::DB_BuildOSPath_FromSource_Default(const char* zoneName, Game::FF_DIR source, unsigned int size, char* filename)
|
||||
{
|
||||
// TODO: this is where user map and mod.ff check should happen
|
||||
if (source == Game::FFD_DEFAULT)
|
||||
{
|
||||
(void)sprintf_s(filename, size, "%s\\%s%s.ff", FileSystem::Sys_DefaultInstallPath_Hk(), GetZoneLocation(zoneName), zoneName);
|
||||
}
|
||||
}
|
||||
|
||||
void FastFiles::DB_BuildOSPath_FromSource_Custom(const char* zoneName, Game::FF_DIR source, unsigned int size, char* filename)
|
||||
{
|
||||
// TODO: this is where user map and mod.ff check should happen
|
||||
if (source == Game::FFD_DEFAULT)
|
||||
{
|
||||
(void)sprintf_s(filename, size, "%s\\%s%s.ff", FileSystem::Sys_HomePath_Hk(), GetZoneLocation(zoneName), zoneName);
|
||||
}
|
||||
}
|
||||
|
||||
bool FastFiles::DB_FileExists_Hk(const char* zoneName, Game::FF_DIR source)
|
||||
{
|
||||
char filename[256]{};
|
||||
|
||||
DB_BuildOSPath_FromSource_Default(zoneName, source, sizeof(filename), filename);
|
||||
if (auto zoneFile = Game::Sys_OpenFileReliable(filename); zoneFile != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
CloseHandle(zoneFile);
|
||||
return true;
|
||||
}
|
||||
|
||||
DB_BuildOSPath_FromSource_Custom(zoneName, source, sizeof(filename), filename);
|
||||
if (auto zoneFile = Game::Sys_OpenFileReliable(filename); zoneFile != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
CloseHandle(zoneFile);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Game::Sys_File FastFiles::Sys_CreateFile_Stub(const char* dir, const char* filename)
|
||||
{
|
||||
static_assert(sizeof(Game::Sys_File) == 4);
|
||||
|
||||
auto file = Game::Sys_CreateFile(dir, filename);
|
||||
|
||||
static const std::filesystem::path home = FileSystem::Sys_HomePath_Hk();
|
||||
if (file.handle == INVALID_HANDLE_VALUE && !home.empty())
|
||||
{
|
||||
file.handle = Game::Sys_OpenFileReliable(Utils::String::VA("%s\\%s%s", FileSystem::Sys_HomePath_Hk(), dir, filename));
|
||||
}
|
||||
|
||||
if (file.handle == INVALID_HANDLE_VALUE && ZoneBuilder::IsEnabled())
|
||||
{
|
||||
file = Game::Sys_CreateFile("zone\\zonebuilder\\", filename);
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
FastFiles::FastFiles()
|
||||
{
|
||||
Dvar::Register<bool>("ui_zoneDebug", false, Game::DVAR_ARCHIVE, "Display current loaded zone.");
|
||||
g_loadingInitialZones = Dvar::Register<bool>("g_loadingInitialZones", true, Game::DVAR_NONE, "Is loading initial zones");
|
||||
|
||||
Utils::Hook(0x5BC832, Sys_CreateFile_Stub, HOOK_CALL).install()->quick();
|
||||
|
||||
Utils::Hook(0x4CCDF0, DB_FileExists_Hk, HOOK_JUMP).install()->quick();
|
||||
|
||||
// Fix XSurface assets
|
||||
Utils::Hook(0x0048E8A5, FastFiles::Load_XSurfaceArray, HOOK_CALL).install()->quick();
|
||||
|
||||
|
@ -70,5 +70,9 @@ namespace Components
|
||||
|
||||
static void Load_XSurfaceArray(int atStreamStart, int count);
|
||||
|
||||
static void DB_BuildOSPath_FromSource_Default(const char* zoneName, Game::FF_DIR source, unsigned int size, char* filename);
|
||||
static void DB_BuildOSPath_FromSource_Custom(const char* zoneName, Game::FF_DIR source, unsigned int size, char* filename);
|
||||
static Game::Sys_File Sys_CreateFile_Stub(const char* dir, const char* filename);
|
||||
static bool DB_FileExists_Hk(const char* zoneName, Game::FF_DIR source);
|
||||
};
|
||||
}
|
||||
|
@ -281,7 +281,7 @@ namespace Components
|
||||
int FileSystem::Cmd_Exec_f_Stub(const char* s0, [[maybe_unused]] const char* s1)
|
||||
{
|
||||
int f;
|
||||
auto len = Game::FS_FOpenFileByMode(s0, &f, Game::FS_READ);
|
||||
const auto len = Game::FS_FOpenFileByMode(s0, &f, Game::FS_READ);
|
||||
if (len < 0)
|
||||
{
|
||||
return 1; // Not found
|
||||
@ -336,6 +336,39 @@ namespace Components
|
||||
return current_path.data();
|
||||
}
|
||||
|
||||
FILE* FileSystem::FS_FileOpenReadText_Hk(const char* file)
|
||||
{
|
||||
const auto path = Utils::GetBaseFilesLocation();
|
||||
if (!path.empty() && Utils::IO::FileExists((path / file).string()))
|
||||
{
|
||||
return Game::FS_FileOpenReadText((path / file).string().data());
|
||||
}
|
||||
|
||||
return Game::FS_FileOpenReadText(file);
|
||||
}
|
||||
|
||||
const char* FileSystem::Sys_DefaultCDPath_Hk()
|
||||
{
|
||||
return Sys_DefaultInstallPath_Hk();
|
||||
}
|
||||
|
||||
const char* FileSystem::Sys_HomePath_Hk()
|
||||
{
|
||||
const auto path = Utils::GetBaseFilesLocation();
|
||||
if (!path.empty())
|
||||
{
|
||||
static auto current_path = path.string();
|
||||
return current_path.data();
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
const char* FileSystem::Sys_Cwd_Hk()
|
||||
{
|
||||
return Sys_DefaultInstallPath_Hk();
|
||||
}
|
||||
|
||||
FileSystem::FileSystem()
|
||||
{
|
||||
// Thread safe file system interaction
|
||||
@ -383,6 +416,21 @@ namespace Components
|
||||
|
||||
// Set the working dir based on info from the Xlabs launcher
|
||||
Utils::Hook(0x4326E0, Sys_DefaultInstallPath_Hk, HOOK_JUMP).install()->quick();
|
||||
|
||||
// Make the exe run from a folder other than the game folder
|
||||
Utils::Hook(0x406D26, FS_FileOpenReadText_Hk, HOOK_CALL).install()->quick();
|
||||
|
||||
// Make the exe run from a folder other than the game folder
|
||||
Utils::Hook::Nop(0x4290D8, 5); // FS_IsBasePathValid
|
||||
Utils::Hook::Set<uint8_t>(0x4290DF, 0xEB);
|
||||
// ^^ This check by the game above is super redundant, IW4x has other checks in place to make sure we
|
||||
// are running from a properly installed directory. This only breaks the containerized patch and we don't need it
|
||||
|
||||
// Patch FS dvar values
|
||||
Utils::Hook(0x643194, Sys_DefaultCDPath_Hk, HOOK_CALL).install()->quick();
|
||||
Utils::Hook(0x643232, Sys_HomePath_Hk, HOOK_CALL).install()->quick();
|
||||
Utils::Hook(0x6431B6, Sys_Cwd_Hk, HOOK_CALL).install()->quick();
|
||||
Utils::Hook(0x51C29A, Sys_Cwd_Hk, HOOK_CALL).install()->quick();
|
||||
}
|
||||
|
||||
FileSystem::~FileSystem()
|
||||
|
@ -99,6 +99,16 @@ namespace Components
|
||||
static std::vector<std::string> GetSysFileList(const std::string& path, const std::string& extension, bool folders = false);
|
||||
static bool _DeleteFile(const std::string& folder, const std::string& file);
|
||||
|
||||
/**
|
||||
* The game will check in FS_Startup if homepath != default(base) path
|
||||
* If they differ which will happen when IW4x is containerized it will register two brand new search paths:
|
||||
* one for the container and one where the game files are. Pretty cool!
|
||||
*/
|
||||
static const char* Sys_DefaultInstallPath_Hk();
|
||||
static const char* Sys_DefaultCDPath_Hk();
|
||||
static const char* Sys_HomePath_Hk();
|
||||
static const char* Sys_Cwd_Hk();
|
||||
|
||||
private:
|
||||
static std::mutex Mutex;
|
||||
static std::recursive_mutex FSMutex;
|
||||
@ -122,6 +132,6 @@ namespace Components
|
||||
|
||||
static void IwdFreeStub(Game::iwd_t* iwd);
|
||||
|
||||
static const char* Sys_DefaultInstallPath_Hk();
|
||||
static FILE* FS_FileOpenReadText_Hk(const char* file);
|
||||
};
|
||||
}
|
||||
|
@ -1115,18 +1115,6 @@ namespace Components
|
||||
sound->info.data_ptr = allocatedSpace;
|
||||
}
|
||||
|
||||
Game::Sys_File ZoneBuilder::Sys_CreateFile_Stub(const char* dir, const char* filename)
|
||||
{
|
||||
auto file = Game::Sys_CreateFile(dir, filename);
|
||||
|
||||
if (file.handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
file = Game::Sys_CreateFile("zone\\zonebuilder\\", filename);
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
iw4of::params_t ZoneBuilder::GetExporterAPIParams()
|
||||
{
|
||||
iw4of::params_t params{};
|
||||
@ -1345,8 +1333,6 @@ namespace Components
|
||||
// Prevent loading textures (preserves loaddef)
|
||||
//Utils::Hook::Set<BYTE>(Game::Load_Texture, 0xC3);
|
||||
|
||||
Utils::Hook(0x5BC832, Sys_CreateFile_Stub, HOOK_CALL).install()->quick();
|
||||
|
||||
// Store the loaddef
|
||||
Utils::Hook(Game::Load_Texture, StoreTexture, HOOK_JUMP).install()->quick();
|
||||
|
||||
|
@ -10,6 +10,7 @@ namespace Game
|
||||
FS_FOpenFileAppend_t FS_FOpenFileAppend = FS_FOpenFileAppend_t(0x410BB0);
|
||||
FS_FOpenFileWrite_t FS_FOpenFileWrite = FS_FOpenFileWrite_t(0x4BA530);
|
||||
FS_FOpenTextFileWrite_t FS_FOpenTextFileWrite = FS_FOpenTextFileWrite_t(0x43FD90);
|
||||
FS_FileOpenReadText_t FS_FileOpenReadText = FS_FileOpenReadText_t(0x446B60);
|
||||
FS_FOpenFileRead_t FS_FOpenFileRead = FS_FOpenFileRead_t(0x46CBF0);
|
||||
FS_FOpenFileReadDatabase_t FS_FOpenFileReadDatabase = FS_FOpenFileReadDatabase_t(0x42ECA0);
|
||||
FS_FOpenFileReadForThread_t FS_FOpenFileReadForThread = FS_FOpenFileReadForThread_t(0x643270);
|
||||
|
@ -26,6 +26,9 @@ namespace Game
|
||||
typedef int(*FS_FOpenFileRead_t)(const char* filename, int* file);
|
||||
extern FS_FOpenFileRead_t FS_FOpenFileRead;
|
||||
|
||||
typedef FILE*(*FS_FileOpenReadText_t)(const char* filename);
|
||||
extern FS_FileOpenReadText_t FS_FileOpenReadText;
|
||||
|
||||
typedef int(*FS_FOpenFileReadDatabase_t)(const char* filename, int* file);
|
||||
extern FS_FOpenFileReadDatabase_t FS_FOpenFileReadDatabase;
|
||||
|
||||
|
@ -11079,6 +11079,13 @@ namespace Game
|
||||
huff_t compressDecompress;
|
||||
};
|
||||
|
||||
enum FF_DIR
|
||||
{
|
||||
FFD_DEFAULT = 0x0,
|
||||
FFD_MOD_DIR = 0x1,
|
||||
FFD_USER_MAP = 0x2,
|
||||
};
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#ifndef IDA
|
||||
|
@ -56,4 +56,10 @@ namespace Game
|
||||
|
||||
return TryEnterCriticalSection(&s_criticalSection[critSect]) != FALSE;
|
||||
}
|
||||
|
||||
HANDLE Sys_OpenFileReliable(const char* filename)
|
||||
{
|
||||
return CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING,
|
||||
FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING, nullptr);
|
||||
}
|
||||
}
|
||||
|
@ -84,6 +84,8 @@ namespace Game
|
||||
|
||||
extern bool Sys_TryEnterCriticalSection(CriticalSection critSect);
|
||||
|
||||
extern HANDLE Sys_OpenFileReliable(const char* filename);
|
||||
|
||||
class Sys
|
||||
{
|
||||
public:
|
||||
|
@ -25,8 +25,10 @@ namespace Utils
|
||||
|
||||
void OutputDebugLastError()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
DWORD errorMessageID = ::GetLastError();
|
||||
OutputDebugStringA(Utils::String::VA("Last error code: 0x%08X (%s)\n", errorMessageID, GetLastWindowsError().data()));
|
||||
OutputDebugStringA(String::VA("Last error code: 0x%08X (%s)\n", errorMessageID, GetLastWindowsError().data()));
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string GetLastWindowsError()
|
||||
@ -85,8 +87,7 @@ namespace Utils
|
||||
if (!ntdll) return nullptr;
|
||||
|
||||
|
||||
static uint8_t ntQueryInformationThread[] = { 0xB1, 0x8B, 0xAE, 0x8A, 0x9A, 0x8D, 0x86, 0xB6, 0x91, 0x99, 0x90, 0x8D, 0x92, 0x9E, 0x8B, 0x96, 0x90, 0x91, 0xAB, 0x97, 0x8D, 0x9A, 0x9E, 0x9B }; // NtQueryInformationThread
|
||||
NtQueryInformationThread_t NtQueryInformationThread = NtQueryInformationThread_t(GetProcAddress(ntdll, String::XOR(std::string(reinterpret_cast<char*>(ntQueryInformationThread), sizeof ntQueryInformationThread), -1).data()));
|
||||
NtQueryInformationThread_t NtQueryInformationThread = NtQueryInformationThread_t(GetProcAddress(ntdll, "NtQueryInformationThread"));
|
||||
if (!NtQueryInformationThread) return nullptr;
|
||||
|
||||
HANDLE dupHandle, currentProcess = GetCurrentProcess();
|
||||
@ -116,11 +117,15 @@ namespace Utils
|
||||
SetCurrentDirectoryW(binaryPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* IW4x_INSTALL should point to where the IW4x rawfiles/client files are
|
||||
* or the current working dir
|
||||
*/
|
||||
void SetEnvironment()
|
||||
{
|
||||
char* buffer{};
|
||||
std::size_t size{};
|
||||
if (_dupenv_s(&buffer, &size, "MW2_INSTALL") != 0 || buffer == nullptr)
|
||||
if (_dupenv_s(&buffer, &size, "IW4x_INSTALL") != 0 || buffer == nullptr)
|
||||
{
|
||||
SetLegacyEnvironment();
|
||||
return;
|
||||
@ -132,10 +137,35 @@ namespace Utils
|
||||
SetDllDirectoryA(buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Points to where the Modern Warfare 2 folder is
|
||||
*/
|
||||
std::filesystem::path GetBaseFilesLocation()
|
||||
{
|
||||
char* buffer{};
|
||||
std::size_t size{};
|
||||
if (_dupenv_s(&buffer, &size, "BASE_INSTALL") != 0 || buffer == nullptr)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto _0 = gsl::finally([&] { std::free(buffer); });
|
||||
|
||||
try
|
||||
{
|
||||
std::filesystem::path result = buffer;
|
||||
return result;
|
||||
}
|
||||
catch (const std::exception& ex)
|
||||
{
|
||||
printf("Failed to convert '%s' to native file system path. Got error '%s'\n", buffer, ex.what());
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
HMODULE GetNTDLL()
|
||||
{
|
||||
static uint8_t ntdll[] = { 0x91, 0x8B, 0x9B, 0x93, 0x93, 0xD1, 0x9B, 0x93, 0x93 }; // ntdll.dll
|
||||
return GetModuleHandleA(Utils::String::XOR(std::string(reinterpret_cast<char*>(ntdll), sizeof ntdll), -1).data());
|
||||
return GetModuleHandleA("ntdll.dll");
|
||||
}
|
||||
|
||||
void SafeShellExecute(HWND hwnd, LPCSTR lpOperation, LPCSTR lpFile, LPCSTR lpParameters, LPCSTR lpDirectory, INT nShowCmd)
|
||||
|
@ -20,6 +20,7 @@ namespace Utils
|
||||
HMODULE GetNTDLL();
|
||||
|
||||
void SetEnvironment();
|
||||
std::filesystem::path GetBaseFilesLocation();
|
||||
|
||||
void OpenUrl(const std::string& url);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user