iw4x-client/src/Components/Modules/FastFiles.cpp

227 lines
5.9 KiB
C++
Raw Normal View History

#include "STDInclude.hpp"
2015-12-23 21:26:46 -05:00
namespace Components
{
std::vector<std::string> FastFiles::ZonePaths;
2016-01-27 18:32:46 -05:00
// This has to be called only once, when the game starts
void FastFiles::LoadInitialZones(Game::XZoneInfo *zoneInfo, unsigned int zoneCount, int sync)
{
std::vector<Game::XZoneInfo> data;
Utils::Merge(&data, zoneInfo, zoneCount);
2016-03-04 11:21:07 -05:00
if (FastFiles::Exists("iw4x_patch_mp"))
{
2016-03-04 11:21:07 -05:00
data.push_back({ "iw4x_patch_mp", 1, 0 });
}
2016-01-27 18:32:46 -05:00
// Load custom weapons, if present (force that later on)
2016-03-04 11:21:07 -05:00
if (FastFiles::Exists("iw4x_weapons_mp"))
2016-01-27 18:32:46 -05:00
{
2016-03-04 11:21:07 -05:00
data.push_back({ "iw4x_weapons_mp", 1, 0 });
2016-01-27 18:32:46 -05:00
}
return FastFiles::LoadDLCUIZones(data.data(), data.size(), sync);
}
// This has to be called every time the cgame is reinitialized
2015-12-23 21:26:46 -05:00
void FastFiles::LoadDLCUIZones(Game::XZoneInfo *zoneInfo, unsigned int zoneCount, int sync)
{
2016-01-01 22:51:08 -05:00
std::vector<Game::XZoneInfo> data;
Utils::Merge(&data, zoneInfo, zoneCount);
2015-12-23 21:26:46 -05:00
2016-01-01 22:51:08 -05:00
Game::XZoneInfo info = { nullptr, 2, 0 };
2015-12-23 21:26:46 -05:00
2016-01-27 18:32:46 -05:00
// Custom ui stuff
2016-03-04 11:21:07 -05:00
if (FastFiles::Exists("iw4x_ui_mp"))
2016-01-27 18:32:46 -05:00
{
2016-03-04 11:21:07 -05:00
info.name = "iw4x_ui_mp";
2016-01-27 18:32:46 -05:00
data.push_back(info);
}
else // Fallback
{
info.name = "dlc1_ui_mp";
data.push_back(info);
2015-12-23 21:26:46 -05:00
2016-01-27 18:32:46 -05:00
info.name = "dlc2_ui_mp";
data.push_back(info);
}
2015-12-23 21:26:46 -05:00
2016-01-27 18:32:46 -05:00
return FastFiles::LoadLocalizeZones(data.data(), data.size(), sync);
}
2016-03-04 11:02:00 -05:00
void FastFiles::LoadGfxZones(Game::XZoneInfo *zoneInfo, unsigned int zoneCount, int sync)
{
std::vector<Game::XZoneInfo> data;
Utils::Merge(&data, zoneInfo, zoneCount);
2016-03-04 11:21:07 -05:00
if (FastFiles::Exists("iw4x_code_post_gfx_mp"))
2016-03-04 11:02:00 -05:00
{
2016-03-04 11:21:07 -05:00
data.push_back({ "iw4x_code_post_gfx_mp", zoneInfo->allocFlags, zoneInfo->freeFlags });
2016-03-04 11:02:00 -05:00
}
Game::DB_LoadXAssets(data.data(), data.size(), sync);
}
2016-01-27 18:32:46 -05:00
// This has to be called every time fastfiles are loaded :D
void FastFiles::LoadLocalizeZones(Game::XZoneInfo *zoneInfo, unsigned int zoneCount, int sync)
{
std::vector<Game::XZoneInfo> data;
Utils::Merge(&data, zoneInfo, zoneCount);
Game::XZoneInfo info = { nullptr, 4, 0 };
// Not sure how they should be loaded :S
2016-03-04 11:21:07 -05:00
std::string langZone = Utils::VA("iw4x_localized_%s", Game::Win_GetLanguage());
2016-01-27 18:32:46 -05:00
if (FastFiles::Exists(langZone))
2016-01-27 04:54:29 -05:00
{
2016-01-27 18:32:46 -05:00
info.name = langZone.data();
2016-01-27 04:54:29 -05:00
}
2016-03-04 11:21:07 -05:00
else if (FastFiles::Exists("iw4x_localized_english")) // Fallback
2016-01-27 18:32:46 -05:00
{
2016-03-04 11:21:07 -05:00
info.name = "iw4x_localized_english";
2016-01-27 18:32:46 -05:00
}
data.push_back(info);
2016-01-26 16:56:28 -05:00
2016-01-01 22:51:08 -05:00
Game::DB_LoadXAssets(data.data(), data.size(), sync);
2015-12-23 21:26:46 -05:00
}
2016-01-27 04:54:29 -05:00
// Name is a bit weird, due to FasFileS and ExistS :P
bool FastFiles::Exists(std::string file)
{
std::string path = FastFiles::GetZoneLocation(file.data());
path.append(file);
if (!Utils::EndsWith(path.data(), ".ff"))
{
path.append(".ff");
}
2016-02-06 20:31:30 -05:00
return std::ifstream(path.data()).good();
2016-01-27 04:54:29 -05:00
}
2015-12-23 21:26:46 -05:00
const char* FastFiles::GetZoneLocation(const char* file)
{
const char* dir = Dvar::Var("fs_basepath").Get<const char*>();
for (auto &path : FastFiles::ZonePaths)
{
std::string absoluteFile = Utils::VA("%s\\%s%s", dir, path.data(), file);
// No ".ff" appended, append it manually
2016-01-27 04:54:29 -05:00
if (!Utils::EndsWith(absoluteFile.data(), ".ff"))
2015-12-23 21:26:46 -05:00
{
absoluteFile.append(".ff");
}
// Check if FastFile exists
2016-02-06 20:31:30 -05:00
if (std::ifstream(absoluteFile.data()).good())
2015-12-23 21:26:46 -05:00
{
return Utils::VA("%s", path.data());
}
}
return Utils::VA("zone\\%s\\", Game::Win_GetLanguage());
}
void FastFiles::AddZonePath(std::string path)
{
FastFiles::ZonePaths.push_back(path);
}
2015-12-25 20:51:58 -05:00
std::string FastFiles::Current()
{
const char* file = (Utils::Hook::Get<char*>(0x112A680) + 4);
if (file == reinterpret_cast<char*>(4))
2015-12-25 20:51:58 -05:00
{
return "";
}
return file;
}
2016-06-27 19:03:37 -04:00
void FastFiles::ReadVersionStub(unsigned int* version, int size)
{
Game::DB_ReadXFileUncompressed(version, size);
// Allow loading out custom version
if (*version == XFILE_VERSION_IW4X)
{
*version = XFILE_VERSION;
}
}
2015-12-23 21:26:46 -05:00
FastFiles::FastFiles()
{
2016-01-12 17:42:05 -05:00
Dvar::Register<bool>("ui_zoneDebug", false, Game::dvar_flag::DVAR_FLAG_SAVED, "Display current loaded zone.");
2015-12-23 21:26:46 -05:00
// Redirect zone paths
Utils::Hook(0x44DA90, FastFiles::GetZoneLocation, HOOK_JUMP).Install()->Quick();
2016-06-27 19:03:37 -04:00
// Allow loading 'newer' zones
Utils::Hook(0x4158E7, FastFiles::ReadVersionStub, HOOK_CALL).Install()->Quick();
// Allow custom zone loading
if (!ZoneBuilder::IsEnabled())
{
Utils::Hook(0x506BC7, FastFiles::LoadInitialZones, HOOK_CALL).Install()->Quick();
Utils::Hook(0x60B4AC, FastFiles::LoadDLCUIZones, HOOK_CALL).Install()->Quick();
2016-05-26 07:13:02 -04:00
Utils::Hook(0x506B25, FastFiles::LoadGfxZones, HOOK_CALL).Install()->Quick();
}
2015-12-23 21:26:46 -05:00
2015-12-25 20:51:58 -05:00
// basic checks (hash jumps, both normal and playlist)
Utils::Hook::Nop(0x5B97A3, 2);
Utils::Hook::Nop(0x5BA493, 2);
Utils::Hook::Nop(0x5B991C, 2);
Utils::Hook::Nop(0x5BA60C, 2);
Utils::Hook::Nop(0x5B97B4, 2);
Utils::Hook::Nop(0x5BA4A4, 2);
// allow loading of IWffu (unsigned) files
Utils::Hook::Set<BYTE>(0x4158D9, 0xEB); // main function
Utils::Hook::Nop(0x4A1D97, 2); // DB_AuthLoad_InflateInit
// some other, unknown, check
Utils::Hook::Set<BYTE>(0x5B9912, 0xB8);
Utils::Hook::Set<DWORD>(0x5B9913, 1);
Utils::Hook::Set<BYTE>(0x5BA602, 0xB8);
Utils::Hook::Set<DWORD>(0x5BA603, 1);
2015-12-23 21:26:46 -05:00
// Add custom zone paths
FastFiles::AddZonePath("zone\\patch\\");
FastFiles::AddZonePath("zone\\dlc\\");
2016-01-12 17:42:05 -05:00
Renderer::OnFrame([] ()
{
2016-03-05 12:04:35 -05:00
if (FastFiles::Current().empty() || !Dvar::Var("ui_zoneDebug").Get<bool>()) return;
2016-01-12 17:42:05 -05:00
2016-01-20 19:01:22 -05:00
Game::Font* font = Game::R_RegisterFont("fonts/consoleFont"); // Inlining that seems to skip xpos, no idea why xD
2016-01-12 17:42:05 -05:00
float color[4] = { 1.0f, 1.0f, 1.0f, (Game::CL_IsCgameInitialized() ? 0.3f : 1.0f) };
2016-02-05 12:13:34 -05:00
Game::R_AddCmdDrawText(Utils::VA("Loading FastFile: %s", FastFiles::Current().data()), 0x7FFFFFFF, font, 5.0f, static_cast<float>(Renderer::Height() - 5), 1.0f, 1.0f, 0.0f, color, Game::ITEM_TEXTSTYLE_NORMAL);
2016-01-12 17:42:05 -05:00
});
2016-01-22 07:18:26 -05:00
Command::Add("loadzone", [] (Command::Params params)
{
if (params.Length() < 2) return;
Game::XZoneInfo info;
info.name = params[1];
2016-01-26 10:12:41 -05:00
info.allocFlags = 1;//0x01000000;
2016-01-22 07:18:26 -05:00
info.freeFlags = 0;
Game::DB_LoadXAssets(&info, 1, true);
});
2015-12-23 21:26:46 -05:00
}
FastFiles::~FastFiles()
{
FastFiles::ZonePaths.clear();
}
}