#include #include "loader/component_loader.hpp" #include "game/game.hpp" #include "game/dvars.hpp" #include #include #include "filesystem.hpp" #include "game_module.hpp" namespace filesystem { namespace { const char* sys_default_install_path_stub() { static auto current_path = std::filesystem::current_path().string(); return current_path.c_str(); } } // namespace bool file_wrapper_rotate(const char* ospath) { constexpr auto MAX_BACKUPS = 20; char renamed_path[game::MAX_OSPATH]{}; struct _stat64i32 stat_buf; auto oldest_index = -1; auto current_index = 0; time_t oldest_time = 0; // Check if the original file exists if (_stat64i32(ospath, &stat_buf)) { return true; // Return true if the file does not exist (no file to rotate) } for (; current_index < MAX_BACKUPS; ++current_index) { (void)sprintf_s(renamed_path, "%s.%03i", ospath, current_index); if (_stat64i32(renamed_path, &stat_buf)) { break; // Stop if an available slot is found } if (oldest_index == -1 || stat_buf.st_mtime < oldest_time) { oldest_time = stat_buf.st_mtime; oldest_index = current_index; } } if (current_index == MAX_BACKUPS) { (void)sprintf_s(renamed_path, "%s.%03i", ospath, oldest_index); (void)std::remove(renamed_path); // Remove the oldest backup file } else { (void)sprintf_s(renamed_path, "%s.%03i", ospath, current_index); } // Rename the original file to the selected backup slot return std::rename(ospath, renamed_path) == 0; } bool file_rotate(const char* filename) { char ospath[game::MAX_OSPATH]{}; const auto* basepath = (*dvars::fs_homepath)->current.string; game::FS_BuildOSPath(basepath, reinterpret_cast(0x1956038), filename, ospath); return file_wrapper_rotate(ospath); } std::vector vectored_file_list(const std::string& path, const std::string& extension) { std::vector file_list; auto num_files = 0; const auto** files = game::FS_ListFiles(path.c_str(), extension.c_str(), game::FS_LIST_ALL, &num_files, 10); if (files) { for (auto i = 0; i < num_files; ++i) { if (files[i]) { file_list.emplace_back(files[i]); } } game::FS_FreeFileList(files, 10); } return file_list; } std::string get_binary_directory() { const auto dir = game_module::get_host_module().get_folder(); return utils::string::replace(dir, "/", "\\"); } file::file(std::string name, game::FsThread thread) : name_(std::move(name)) { assert(!this->name_.empty()); auto handle = 0; const auto len = game::FS_FOpenFileReadForThread(name_.c_str(), &handle, thread); if (!handle) { this->valid_ = false; return; } auto* buf = static_cast(game::Hunk_AllocateTempMemory(len + 1)); game::FS_Read(buf, len, handle); buf[len] = '\0'; game::FS_FCloseFile(handle); this->valid_ = true; this->buffer_.append(buf, len); } bool file::exists() const { return this->valid_; } const std::string& file::get_buffer() const { return this->buffer_; } const std::string& file::get_name() const { return this->name_; } class component final : public component_interface { public: void post_load() override { utils::hook(0x465B90, sys_default_install_path_stub, HOOK_CALL) .install() // hook* ->quick(); // Sys_CreateFile } }; } // namespace filesystem REGISTER_COMPONENT(filesystem::component)