Use premake.

This commit is contained in:
momo5502
2015-12-29 02:52:31 +01:00
parent 93d1380139
commit 87c1c36943
85 changed files with 85 additions and 519 deletions

55
src/Components/Loader.cpp Normal file
View File

@ -0,0 +1,55 @@
#include "..\STDInclude.hpp"
namespace Components
{
std::vector<Component*> Loader::Components;
void Loader::Initialize()
{
Loader::Register(new Dedicated());
Loader::Register(new Dvar());
Loader::Register(new Maps());
Loader::Register(new Menus());
Loader::Register(new Party());
Loader::Register(new Colors());
Loader::Register(new Logger());
Loader::Register(new Window());
Loader::Register(new Command());
Loader::Register(new Console());
Loader::Register(new Network());
Loader::Register(new RawFiles());
Loader::Register(new Renderer());
Loader::Register(new UIFeeder());
Loader::Register(new UIScript());
Loader::Register(new FastFiles());
Loader::Register(new Materials());
Loader::Register(new Singleton());
Loader::Register(new FileSystem());
Loader::Register(new QuickPatch());
Loader::Register(new ServerList());
Loader::Register(new AssetHandler());
Loader::Register(new Localization());
Loader::Register(new MusicalTalent());
}
void Loader::Uninitialize()
{
for (auto component : Loader::Components)
{
Logger::Print("Unregistering component: %s", component->GetName());
delete component;
}
Loader::Components.clear();
}
void Loader::Register(Component* component)
{
if (component)
{
Logger::Print("Component registered: %s", component->GetName());
Loader::Components.push_back(component);
}
}
}

46
src/Components/Loader.hpp Normal file
View File

@ -0,0 +1,46 @@
namespace Components
{
class Component
{
public:
Component() {};
virtual ~Component() {};
virtual const char* GetName() { return "Unknown"; };
};
class Loader
{
public:
static void Initialize();
static void Uninitialize();
static void Register(Component* component);
private:
static std::vector<Component*> Components;
};
}
#include "Modules\Dvar.hpp"
#include "Modules\Maps.hpp"
#include "Modules\Menus.hpp"
#include "Modules\Colors.hpp"
#include "Modules\Logger.hpp"
#include "Modules\Window.hpp"
#include "Modules\Command.hpp"
#include "Modules\Console.hpp"
#include "Modules\Network.hpp"
#include "Modules\Party.hpp" // Destroys the order, but requires network classes :D
#include "Modules\RawFiles.hpp"
#include "Modules\Renderer.hpp"
#include "Modules\UIFeeder.hpp"
#include "Modules\UIScript.hpp"
#include "Modules\Dedicated.hpp"
#include "Modules\FastFiles.hpp"
#include "Modules\Materials.hpp"
#include "Modules\Singleton.hpp"
#include "Modules\FileSystem.hpp"
#include "Modules\QuickPatch.hpp"
#include "Modules\ServerList.hpp"
#include "Modules\AssetHandler.hpp"
#include "Modules\Localization.hpp"
#include "Modules\MusicalTalent.hpp"

View File

@ -0,0 +1,158 @@
#include "..\..\STDInclude.hpp"
namespace Components
{
bool AssetHandler::BypassState = false;
std::map<Game::XAssetType, AssetHandler::Callback> AssetHandler::TypeCallbacks;
std::vector<AssetHandler::RestrictCallback> AssetHandler::RestrictCallbacks;
std::map<void*, void*> AssetHandler::Relocations;
Game::XAssetHeader AssetHandler::FindAsset(Game::XAssetType type, const char* filename)
{
Game::XAssetHeader header = { 0 };
// Allow call DB_FindXAssetHeader within the hook
AssetHandler::BypassState = true;
if (AssetHandler::TypeCallbacks.find(type) != AssetHandler::TypeCallbacks.end())
{
header = AssetHandler::TypeCallbacks[type](type, filename);
}
// Disallow calling DB_FindXAssetHeader ;)
AssetHandler::BypassState = false;
return header;
}
void __declspec(naked) AssetHandler::FindAssetStub()
{
__asm
{
push ecx
push ebx
push ebp
push esi
push edi
// Check if custom handler should be bypassed
xor eax, eax
mov al, AssetHandler::BypassState
test al, al
jnz finishOriginal
mov ecx, [esp + 18h] // Asset type
mov ebx, [esp + 1Ch] // Filename
push ebx
push ecx
call AssetHandler::FindAsset
add esp, 8h
test eax, eax
jnz finishFound
finishOriginal:
// Asset not found using custom handlers, redirect to DB_FindXAssetHeader
mov ebx, ds:6D7190h // InterlockedDecrement
mov eax, 40793Bh
jmp eax
finishFound:
pop edi
pop esi
pop ebp
pop ebx
pop ecx
retn
}
}
bool AssetHandler::IsAssetEligible(Game::XAssetType type, Game::XAssetHeader *asset)
{
const char* name = Game::DB_GetXAssetNameHandlers[type](asset);
if (!name) return false;
for (auto callback : AssetHandler::RestrictCallbacks)
{
if (!callback(type, *asset, name))
{
return false;
}
}
return true;
}
void __declspec(naked) AssetHandler::AddAssetStub()
{
__asm
{
push [esp + 8]
push [esp + 8]
call AssetHandler::IsAssetEligible
add esp, 08h
test al, al
jz doNotLoad
mov eax, [esp + 8]
sub esp, 14h
mov ecx, 5BB657h
jmp ecx
doNotLoad:
mov eax, [esp + 8]
retn
}
}
void AssetHandler::OnFind(Game::XAssetType type, AssetHandler::Callback callback)
{
AssetHandler::TypeCallbacks[type] = callback;
}
void AssetHandler::OnLoad(RestrictCallback callback)
{
AssetHandler::RestrictCallbacks.push_back(callback);
}
void AssetHandler::Relocate(void* start, void* to, DWORD size)
{
for (DWORD i = 0; i < size; i += 4)
{
AssetHandler::Relocations[reinterpret_cast<char*>(start) + i] = reinterpret_cast<char*>(to) + i;
}
}
void AssetHandler::OffsetToAlias(FastFiles::Offset* offset)
{
offset->fullPointer = *reinterpret_cast<void**>((*Game::g_streamBlocks)[offset->GetDecrementedStream()].data + offset->GetDecrementedPointer());
if (AssetHandler::Relocations.find(offset->fullPointer) != AssetHandler::Relocations.end())
{
offset->fullPointer = AssetHandler::Relocations[offset->fullPointer];
}
}
AssetHandler::AssetHandler()
{
// DB_FindXAssetHeader
Utils::Hook(Game::DB_FindXAssetHeader, AssetHandler::FindAssetStub).Install()->Quick();
// DB_ConvertOffsetToAlias
Utils::Hook(0x4FDFA0, AssetHandler::OffsetToAlias, HOOK_JUMP).Install()->Quick();
// DB_AddXAsset
Utils::Hook(0x5BB650, AssetHandler::AddAssetStub, HOOK_JUMP).Install()->Quick();
}
AssetHandler::~AssetHandler()
{
AssetHandler::TypeCallbacks.clear();
}
}

View File

@ -0,0 +1,33 @@
namespace Components
{
class AssetHandler : public Component
{
public:
typedef Game::XAssetHeader(*Callback)(Game::XAssetType, const char*);
typedef bool(*RestrictCallback)(Game::XAssetType type, Game::XAssetHeader asset, const char* name);
AssetHandler();
~AssetHandler();
const char* GetName() { return "AssetHandler"; };
static void OnFind(Game::XAssetType type, Callback callback);
static void OnLoad(RestrictCallback callback);
static void Relocate(void* start, void* to, DWORD size = 4);
private:
static bool BypassState;
static Game::XAssetHeader FindAsset(Game::XAssetType type, const char* filename);
static bool IsAssetEligible(Game::XAssetType type, Game::XAssetHeader* asset);
static void FindAssetStub();
static void AddAssetStub();
static void OffsetToAlias(FastFiles::Offset* offset);
static std::map<Game::XAssetType, Callback> TypeCallbacks;
static std::vector<RestrictCallback> RestrictCallbacks;
static std::map<void*, void*> Relocations;
};
}

View File

@ -0,0 +1,112 @@
#include "..\..\STDInclude.hpp"
namespace Components
{
Dvar::Var Colors::NewColors;
void Colors::Strip(const char* in, char* out, int max)
{
max--;
int current = 0;
while (*in != 0 && current < max)
{
if (!Q_IsColorString(in))
{
*out = *in;
out++;
current++;
}
else
{
*in++;
}
*in++;
}
*out = '\0';
}
void __declspec(naked) Colors::ClientUserinfoChanged(int length)
{
__asm
{
mov eax, [esp + 4h] // length
sub eax, 1
push eax
push ecx // name
push edx // buffer
call strncpy
add esp, 0Ch
retn
}
}
char* Colors::CL_GetClientName(int a1, int a2, char* buffer, size_t _length)
{
__asm
{
push _length
push buffer
push a2
push a1
mov eax, 4563D0h
call eax
add esp, 10h
}
// Remove the colors
char tempBuffer[100] = { 0 };
Colors::Strip(buffer, tempBuffer, _length);
strncpy(buffer, tempBuffer, _length);
return buffer;
}
void Colors::UpdateColorTable()
{
static int LastState = 2;
static DWORD DefaultTable[8] = { 0 };
DWORD* gColorTable = (DWORD*)0x78DC70;
if (LastState == 2)
{
memcpy(DefaultTable, gColorTable, sizeof(DefaultTable));
}
if (Colors::NewColors.Get<bool>() && (0xF & (int)Colors::NewColors.Get<bool>()) != LastState)
{
// Apply NTA's W<> colors :3 (slightly modified though^^)
gColorTable[1] = RGB(255, 49, 49);
gColorTable[2] = RGB(134, 192, 0);
gColorTable[3] = RGB(255, 173, 34);
gColorTable[4] = RGB(0, 135, 193);
gColorTable[5] = RGB(32, 197, 255);
gColorTable[6] = RGB(151, 80, 221);
LastState = Colors::NewColors.Get<bool>();
}
else if (!Colors::NewColors.Get<bool>() && (0xF & (int)Colors::NewColors.Get<bool>()) != LastState)
{
memcpy(gColorTable, DefaultTable, sizeof(DefaultTable));
LastState = Colors::NewColors.Get<bool>();
}
}
Colors::Colors()
{
// Allow colored names ingame
Utils::Hook(0x5D8B40, Colors::ClientUserinfoChanged, HOOK_JUMP).Install()->Quick();
// Though, don't apply that to overhead names.
Utils::Hook(0x581932, Colors::CL_GetClientName, HOOK_CALL).Install()->Quick();
// Set frame handler
Renderer::OnFrame(Colors::UpdateColorTable);
// Register dvar
Colors::NewColors = Dvar::Register<bool>("cg_newColors", true, Game::dvar_flag::DVAR_FLAG_SAVED, "Use Warfare<72> color code style.");
}
}

View File

@ -0,0 +1,20 @@
#define Q_IsColorString( p ) ( ( p ) && *( p ) == '^' && *( ( p ) + 1 ) && isdigit( *( ( p ) + 1 ) ) ) // ^[0-9]
namespace Components
{
class Colors : public Component
{
public:
Colors();
const char* GetName() { return "Colors"; };
static Dvar::Var NewColors;
static void ClientUserinfoChanged(int length);
static char* CL_GetClientName(int a1, int a2, char* buffer, size_t _length);
static void UpdateColorTable();
static void Strip(const char* in, char* out, int max);
};
}

View File

@ -0,0 +1,77 @@
#include "..\..\STDInclude.hpp"
namespace Components
{
std::vector<Game::cmd_function_t*> Command::Functions;
std::map<std::string, Command::Callback> Command::FunctionMap;
char* Command::Params::operator[](size_t index)
{
if (index >= this->Length())
{
return "";
}
return Game::cmd_argv[this->CommandId][index];
}
size_t Command::Params::Length()
{
return Game::cmd_argc[this->CommandId];
}
Command::~Command()
{
for (auto command : Command::Functions)
{
delete command;
}
Command::Functions.clear();
}
void Command::Add(const char* name, Command::Callback callback)
{
Command::FunctionMap[Utils::StrToLower(name)] = callback;
Game::Cmd_AddCommand(name, Command::MainCallback, Command::Allocate(), 0);
}
void Command::Execute(std::string command, bool sync)
{
command.append("\n"); // Make sure it's terminated
if (sync)
{
Game::Cmd_ExecuteSingleCommand(0, 0, command.data());
}
else
{
Game::Cbuf_AddText(0, command.data());
}
}
Game::cmd_function_t* Command::Allocate()
{
Game::cmd_function_t* cmd = new Game::cmd_function_t;
Command::Functions.push_back(cmd);
return cmd;
}
void Command::MainCallback()
{
Command::Params params(*Game::cmd_id);
std::string command = Utils::StrToLower(params[0]);
if (Command::FunctionMap.find(command) != Command::FunctionMap.end())
{
Command::FunctionMap[command](params);
}
}
Command::Command()
{
// TODO: Add commands here?
}
}

View File

@ -0,0 +1,36 @@
namespace Components
{
class Command : public Component
{
public:
class Params
{
public:
Params(DWORD id) : CommandId(id) {};
Params(const Params &obj) { this->CommandId = obj.CommandId; };
Params() : Params(*Game::cmd_id) {};
char* operator[](size_t index);
size_t Length();
private:
DWORD CommandId;
};
typedef void(*Callback)(Command::Params params);
Command();
~Command();
const char* GetName() { return "Command"; };
static void Add(const char* name, Callback callback);
static void Execute(std::string command, bool sync = true);
private:
static Game::cmd_function_t* Allocate();
static std::vector<Game::cmd_function_t*> Functions;
static std::map<std::string, Callback> FunctionMap;
static void MainCallback();
};
}

View File

@ -0,0 +1,38 @@
#include "..\..\STDInclude.hpp"
namespace Components
{
char** Console::GetAutoCompleteFileList(const char *path, const char *extension, Game::FsListBehavior_e behavior, int *numfiles, int allocTrackType)
{
if (path == (char*)0xBAADF00D || IsBadReadPtr(path, 1)) return nullptr;
return Game::FS_ListFiles(path, extension, behavior, numfiles, allocTrackType);
}
void Console::ToggleConsole()
{
// possibly cls.keyCatchers?
Utils::Hook::Xor<DWORD>(0xB2C538, 1);
// g_consoleField
Game::Field_Clear((void*)0xA1B6B0);
// show console output?
Utils::Hook::Set<BYTE>(0xA15F38, 0);
}
Console::Console()
{
// External console
Utils::Hook::Nop(0x60BB58, 11);
// Console '%s: %s> ' string
Utils::Hook::Set<char*>(0x5A44B4, "IW4x > ");
// Internal console
Utils::Hook(0x4F690C, Console::ToggleConsole, HOOK_CALL).Install()->Quick();
Utils::Hook(0x4F65A5, Console::ToggleConsole, HOOK_JUMP).Install()->Quick();
// Check for bad food ;)
Utils::Hook(0x4CB9F4, Console::GetAutoCompleteFileList, HOOK_CALL).Install()->Quick();
}
}

View File

@ -0,0 +1,13 @@
namespace Components
{
class Console : public Component
{
public:
Console();
const char* GetName() { return "Console"; };
private:
static void ToggleConsole();
static char** GetAutoCompleteFileList(const char *path, const char *extension, Game::FsListBehavior_e behavior, int *numfiles, int allocTrackType);
};
}

View File

@ -0,0 +1,113 @@
#include "..\..\STDInclude.hpp"
namespace Components
{
Dvar::Var Dedicated::Dedi;
bool Dedicated::IsDedicated()
{
return (Dedicated::Dedi.Get<int>() != 0);
}
void Dedicated::InitDedicatedServer()
{
const char* fastfiles[7] =
{
"code_post_gfx_mp",
"localized_code_post_gfx_mp",
"ui_mp",
"localized_ui_mp",
"common_mp",
"localized_common_mp",
"patch_mp"
};
memcpy((void*)0x66E1CB0, &fastfiles, sizeof(fastfiles));
Game::LoadInitialFF();
Utils::Hook::Call<void>(0x4F84C0);
}
Dedicated::Dedicated()
{
Dedicated::Dedi = Dvar::Register<int>("dedicated", 0, 0, 2, Game::dvar_flag::DVAR_FLAG_SERVERINFO | Game::dvar_flag::DVAR_FLAG_WRITEPROTECTED, "Start as dedicated");
// TODO: Beautify!
char* cmd = GetCommandLineA();
char* value = strstr(cmd, " dedicated");
if (value)
{
value += 10;
while (*value == ' ' || *value == '"')
value++;
char num[2] = { 0, 0 };
num[0] = *value;
int dediVal = atoi(num);
if (dediVal && dediVal < 3)
{
Dedicated::Dedi.SetRaw(dediVal);
}
}
if (Dedicated::IsDedicated())
{
Utils::Hook(0x60BE98, Dedicated::InitDedicatedServer, HOOK_CALL).Install()->Quick();
Utils::Hook::Set<BYTE>(0x683370, 0xC3); // steam sometimes doesn't like the server
Utils::Hook::Set<BYTE>(0x5B4FF0, 0xC3); // self-registration on party
Utils::Hook::Set<BYTE>(0x426130, 0xC3); // other party stuff?
Utils::Hook::Set<BYTE>(0x4D7030, 0xC3); // upnp stuff
Utils::Hook::Set<BYTE>(0x4B0FC3, 0x04); // make CL_Frame do client packets, even for game state 9
Utils::Hook::Set<BYTE>(0x4F5090, 0xC3); // init sound system (1)
Utils::Hook::Set<BYTE>(0x507B80, 0xC3); // start render thread
Utils::Hook::Set<BYTE>(0x4F84C0, 0xC3); // R_Init caller
Utils::Hook::Set<BYTE>(0x46A630, 0xC3); // init sound system (2)
Utils::Hook::Set<BYTE>(0x41FDE0, 0xC3); // Com_Frame audio processor?
Utils::Hook::Set<BYTE>(0x41B9F0, 0xC3); // called from Com_Frame, seems to do renderer stuff
Utils::Hook::Set<BYTE>(0x41D010, 0xC3); // CL_CheckForResend, which tries to connect to the local server constantly
Utils::Hook::Set<BYTE>(0x62B6C0, 0xC3); // UI expression 'DebugPrint', mainly to prevent some console spam
Utils::Hook::Set<BYTE>(0x468960, 0xC3); // some mixer-related function called on shutdown
Utils::Hook::Set<BYTE>(0x60AD90, 0); // masterServerName flags
Utils::Hook::Nop(0x4DCEC9, 2); // some check preventing proper game functioning
Utils::Hook::Nop(0x507C79, 6); // another similar bsp check
Utils::Hook::Nop(0x414E4D, 6); // unknown check in SV_ExecuteClientMessage (0x20F0890 == 0, related to client->f_40)
Utils::Hook::Nop(0x4DCEE9, 5); // some deinit renderer function
Utils::Hook::Nop(0x59A896, 5); // warning message on a removed subsystem
Utils::Hook::Nop(0x4B4EEF, 5); // same as above
Utils::Hook::Nop(0x64CF77, 5); // function detecting video card, causes Direct3DCreate9 to be called
Utils::Hook::Nop(0x60BC52, 0x15); // recommended settings check
// isHost script call return 0
Utils::Hook::Set<DWORD>(0x5DEC04, 0);
// map_rotate func
//*(DWORD*)0x4152E8 = (DWORD)SV_MapRotate_f;
// sv_network_fps max 1000, and uncheat
Utils::Hook::Set<BYTE>(0x4D3C67, 0); // ?
Utils::Hook::Set<DWORD>(0x4D3C69, 1000);
// r_loadForRenderer default to 0
Utils::Hook::Set<BYTE>(0x519DDF, 0);
// disable cheat protection on onlinegame
Utils::Hook::Set<BYTE>(0x404CF7, 0x80);
// some d3d9 call on error
Utils::Hook::Set<BYTE>(0x508470, 0xC3);
// stop saving a config_mp.cfg
Utils::Hook::Set<BYTE>(0x60B240, 0xC3);
}
}
}

View File

@ -0,0 +1,16 @@
namespace Components
{
class Dedicated : public Component
{
public:
Dedicated();
const char* GetName() { return "Dedicated"; };
static bool IsDedicated();
private:
static Dvar::Var Dedi;
static void InitDedicatedServer();
};
}

View File

@ -0,0 +1,149 @@
#include "..\..\STDInclude.hpp"
namespace Components
{
Dvar::Var::Var(std::string dvarName) : Var()
{
this->dvar = Game::Dvar_FindVar(dvarName.data());
if (!this->dvar)
{
// Quick-register the dvar
Game::SetConsole(dvarName.data(), "");
this->dvar = Game::Dvar_FindVar(dvarName.data());
}
}
template <> Game::dvar_t* Dvar::Var::Get()
{
return this->dvar;
}
template <> char* Dvar::Var::Get()
{
if (this->dvar && this->dvar->type == Game::dvar_type::DVAR_TYPE_STRING && this->dvar->current.string)
{
return this->dvar->current.string;
}
return "";
}
template <> const char* Dvar::Var::Get()
{
return this->Get<char*>();
}
template <> int Dvar::Var::Get()
{
if (this->dvar && this->dvar->type == Game::dvar_type::DVAR_TYPE_INT)
{
return this->dvar->current.integer;
}
return 0;
}
template <> float Dvar::Var::Get()
{
if (this->dvar && this->dvar->type == Game::dvar_type::DVAR_TYPE_FLOAT)
{
return this->dvar->current.value;
}
return 0;
}
template <> float* Dvar::Var::Get()
{
static float val[4] = { 0 };
if (this->dvar && (this->dvar->type == Game::dvar_type::DVAR_TYPE_FLOAT_2 || this->dvar->type == Game::dvar_type::DVAR_TYPE_FLOAT_3 || this->dvar->type == Game::dvar_type::DVAR_TYPE_FLOAT_4))
{
return this->dvar->current.vec4;
}
return val;
}
template <> bool Dvar::Var::Get()
{
if (this->dvar && this->dvar->type == Game::dvar_type::DVAR_TYPE_BOOL)
{
return this->dvar->current.boolean;
}
return false;
}
void Dvar::Var::Set(char* string)
{
this->Set(reinterpret_cast<const char*>(string));
}
void Dvar::Var::Set(const char* string)
{
if (this->dvar && this->dvar->name)
{
Game::Dvar_SetCommand(this->dvar->name, string);
}
}
void Dvar::Var::Set(std::string string)
{
this->Set(string.data());
}
void Dvar::Var::Set(int integer)
{
if (this->dvar && this->dvar->name)
{
Game::Dvar_SetCommand(this->dvar->name, Utils::VA("%i", integer));
}
}
void Dvar::Var::Set(float value)
{
if (this->dvar && this->dvar->name)
{
Game::Dvar_SetCommand(this->dvar->name, Utils::VA("%f", value));
}
}
void Dvar::Var::SetRaw(int integer)
{
if (this->dvar)
{
this->dvar->current.integer = integer;
}
}
template<> static Dvar::Var Dvar::Register(const char* name, bool value, Dvar::Flag flag, const char* description)
{
return Game::Dvar_RegisterBool(name, value, flag.val, description);
}
template<> static Dvar::Var Dvar::Register(const char* name, const char* value, Dvar::Flag flag, const char* description)
{
return Game::Dvar_RegisterString(name, value, flag.val, description);
}
template<> static Dvar::Var Dvar::Register(const char* name, int value, int min, int max, Dvar::Flag flag, const char* description)
{
return Game::Dvar_RegisterInt(name, value, min, max, flag.val, description);
}
Game::dvar_t* Dvar::RegisterName(const char* name, const char* default, Game::dvar_flag flag, const char* description)
{
// TODO: Register string dvars here
return Dvar::Register<const char*>(name, "Unknown Soldier", Dvar::Flag(flag | Game::dvar_flag::DVAR_FLAG_SAVED).val, description).Get<Game::dvar_t*>();
}
Dvar::Dvar()
{
// set flags of cg_drawFPS to archive
Utils::Hook::Or<BYTE>(0x4F8F69, Game::dvar_flag::DVAR_FLAG_SAVED);
// un-cheat cg_fov and add archive flags
Utils::Hook::Xor<BYTE>(0x4F8E35, Game::dvar_flag::DVAR_FLAG_CHEAT | Game::dvar_flag::DVAR_FLAG_SAVED);
// set flags of cg_drawFPS to archive
Utils::Hook::Or<BYTE>(0x4F8F69, Game::dvar_flag::DVAR_FLAG_SAVED);
// set cg_fov max to 90.0
static float cgFov90 = 90.0f;
Utils::Hook::Set<float*>(0x4F8E28, &cgFov90);
// Hook dvar 'name' registration
Utils::Hook(0x40531C, Dvar::RegisterName, HOOK_CALL).Install()->Quick();
}
}

View File

@ -0,0 +1,49 @@
namespace Components
{
class Dvar : public Component
{
public:
struct Flag
{
Flag(Game::dvar_flag flag) : val(flag){};
Flag(int flag) : Flag((Game::dvar_flag)flag) {};
Game::dvar_flag val;
};
class Var
{
public:
Var() : dvar(0) {};
Var(const Var &obj) { this->dvar = obj.dvar; };
Var(Game::dvar_t* _dvar) : dvar(_dvar) {};
Var(std::string dvarName);
Var(std::string dvarName, std::string value);
template<typename T> T Get();
void Set(char* string);
void Set(const char* string);
void Set(std::string string);
void Set(int integer);
void Set(float value);
// TODO: Add others
void SetRaw(int integer);
private:
Game::dvar_t* dvar;
};
Dvar();
const char* GetName() { return "Dvar"; };
// Only strings and bools use this type of declaration
template<typename T> static Var Register(const char* name, T value, Flag flag, const char* description);
template<typename T> static Var Register(const char* name, T value, T min, T max, Flag flag, const char* description);
private:
static Game::dvar_t* RegisterName(const char* name, const char* default, Game::dvar_flag flag, const char* description);
};
}

View File

@ -0,0 +1,107 @@
#include "..\..\STDInclude.hpp"
namespace Components
{
std::vector<std::string> FastFiles::ZonePaths;
void FastFiles::LoadDLCUIZones(Game::XZoneInfo *zoneInfo, unsigned int zoneCount, int sync)
{
Game::XZoneInfo* data = new Game::XZoneInfo[zoneCount + 2];
memcpy(data, zoneInfo, sizeof(Game::XZoneInfo) * zoneCount);
data[zoneCount].name = "dlc1_ui_mp";
data[zoneCount].allocFlags = 2;
data[zoneCount].freeFlags = 0;
zoneCount++;
data[zoneCount].name = "dlc2_ui_mp";
data[zoneCount].allocFlags = 2;
data[zoneCount].freeFlags = 0;
zoneCount++;
Game::DB_LoadXAssets(data, zoneCount, sync);
delete[] data;
}
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
if (!Utils::EndsWith(file, ".ff"))
{
absoluteFile.append(".ff");
}
// Check if FastFile exists
if (GetFileAttributes(absoluteFile.data()) != INVALID_FILE_ATTRIBUTES)
{
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);
}
std::string FastFiles::Current()
{
const char* file = (Utils::Hook::Get<char*>(0x112A680) + 4);
if ((int)file == 4)
{
return "";
}
return file;
}
FastFiles::FastFiles()
{
// Redirect zone paths
Utils::Hook(0x44DA90, FastFiles::GetZoneLocation, HOOK_JUMP).Install()->Quick();
// Allow dlc ui zone loading
Utils::Hook(0x506BC7, FastFiles::LoadDLCUIZones, HOOK_CALL).Install()->Quick();
Utils::Hook(0x60B4AC, FastFiles::LoadDLCUIZones, HOOK_CALL).Install()->Quick();
// 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);
// Add custom zone paths
FastFiles::AddZonePath("zone\\patch\\");
FastFiles::AddZonePath("zone\\dlc\\");
}
FastFiles::~FastFiles()
{
FastFiles::ZonePaths.clear();
}
}

View File

@ -0,0 +1,48 @@
namespace Components
{
class FastFiles : public Component
{
public:
class Offset
{
public:
union
{
struct
{
uint32_t pointer : 28;
int stream : 4;
};
uint32_t fullValue;
void* fullPointer;
};
uint32_t GetDecrementedPointer()
{
Offset offset = *this;
offset.fullValue--;
return offset.pointer;
};
int GetDecrementedStream()
{
Offset offset = *this;
offset.fullValue--;
return offset.stream;
};
};
FastFiles();
~FastFiles();
const char* GetName() { return "FastFiles"; };
static void AddZonePath(std::string path);
static std::string Current();
private:
static std::vector<std::string> ZonePaths;
static const char* GetZoneLocation(const char* file);
static void LoadDLCUIZones(Game::XZoneInfo *zoneInfo, unsigned int zoneCount, int sync);
};
}

View File

@ -0,0 +1,30 @@
#include "..\..\STDInclude.hpp"
namespace Components
{
void FileSystem::File::Read()
{
char* buffer = nullptr;
int size = Game::FS_ReadFile(this->FilePath.data(), &buffer);
this->Buffer.clear();
if (size < 0)
{
if (buffer)
{
Game::FS_FreeFile(buffer);
}
}
else
{
this->Buffer.append(buffer, size);
Game::FS_FreeFile(buffer);
}
}
FileSystem::FileSystem()
{
}
}

View File

@ -0,0 +1,27 @@
namespace Components
{
class FileSystem : public Component
{
public:
class File
{
public:
//File() {};
File(std::string file) : FilePath(file) { this->Read(); };
bool Exists() { return this->Buffer.size() > 0; };
std::string GetName() { return this->FilePath; };
std::string& GetBuffer() { return this->Buffer; };
private:
std::string FilePath;
std::string Buffer;
void Read();
};
FileSystem();
const char* GetName() { return "FileSystem"; };
};
}

View File

@ -0,0 +1,44 @@
#include "..\..\STDInclude.hpp"
namespace Components
{
Dvar::Var Localization::UseLocalization;
std::map<std::string, std::string> Localization::LocalizeMap;
void Localization::Set(const char* key, const char* value)
{
Localization::LocalizeMap[key] = value;
}
const char* Localization::Get(const char* key)
{
if (!Localization::UseLocalization.Get<bool>()) return key;
if (Localization::LocalizeMap.find(key) != Localization::LocalizeMap.end())
{
return Localization::LocalizeMap[key].data();
}
Game::localizedEntry_s* entry = Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_LOCALIZE, key).localize;
if (entry)
{
return entry->value;
}
return key;
}
Localization::Localization()
{
Utils::Hook(0x629B90, Localization::Get, HOOK_JUMP).Install()->Quick();
//Localization::Set("MENU_MULTIPLAYER_CAPS", "^5Fotze");
Localization::UseLocalization = Dvar::Register<bool>("ui_localize", true, Game::dvar_flag::DVAR_FLAG_NONE, "Use localization strings");
}
Localization::~Localization()
{
Localization::LocalizeMap.clear();
}
}

View File

@ -0,0 +1,17 @@
namespace Components
{
class Localization : public Component
{
public:
Localization();
~Localization();
const char* GetName() { return "Localization"; };
static void Set(const char* key, const char* value);
static const char* Get(const char* key);
private:
static std::map<std::string, std::string> LocalizeMap;
static Dvar::Var UseLocalization;
};
}

View File

@ -0,0 +1,57 @@
#include "..\..\STDInclude.hpp"
namespace Components
{
bool Logger::IsConsoleReady()
{
return (IsWindow(*(HWND*)0x64A3288) != FALSE);
}
void Logger::Print(const char* message, ...)
{
char buffer[0x1000] = { 0 };
va_list ap;
va_start(ap, message);
vsprintf_s(buffer, message, ap);
va_end(ap);
if (Logger::IsConsoleReady())
{
Game::Com_Printf(0, "%s", buffer);
}
else
{
OutputDebugStringA(buffer);
}
}
void Logger::Error(const char* message, ...)
{
char buffer[0x1000] = { 0 };
va_list ap;
va_start(ap, message);
vsprintf_s(buffer, message, ap);
va_end(ap);
Game::Com_Error(0, "%s", buffer);
}
void Logger::SoftError(const char* message, ...)
{
char buffer[0x1000] = { 0 };
va_list ap;
va_start(ap, message);
vsprintf_s(buffer, message, ap);
va_end(ap);
Game::Com_Error(2, "%s", buffer);
}
Logger::Logger()
{
}
}

View File

@ -0,0 +1,14 @@
namespace Components
{
class Logger : public Component
{
public:
Logger();
const char* GetName() { return "Logger"; };
static void Print(const char* message, ...);
static void Error(const char* message, ...);
static void SoftError(const char* message, ...);
static bool IsConsoleReady();
};
}

View File

@ -0,0 +1,183 @@
#include "..\..\STDInclude.hpp"
namespace Components
{
void* Maps::WorldMP = 0;
void* Maps::WorldSP = 0;
std::map<std::string, std::string> Maps::DependencyList;
std::vector<std::string> Maps::CurrentDependencies;
std::vector<Game::XAssetEntry> Maps::EntryPool;
void Maps::LoadMapZones(Game::XZoneInfo *zoneInfo, unsigned int zoneCount, int sync)
{
Maps::CurrentDependencies.clear();
for (auto i = Maps::DependencyList.begin(); i != Maps::DependencyList.end(); i++)
{
if (std::regex_match(zoneInfo->name, std::regex(i->first)))
{
if (std::find(Maps::CurrentDependencies.begin(), Maps::CurrentDependencies.end(), i->second) == Maps::CurrentDependencies.end())
{
Maps::CurrentDependencies.push_back(i->second);
}
}
}
Game::XZoneInfo* data = new Game::XZoneInfo[zoneCount + Maps::CurrentDependencies.size()];
memcpy(data, zoneInfo, sizeof(Game::XZoneInfo) * zoneCount);
for (unsigned int i = 0; i < Maps::CurrentDependencies.size(); i++)
{
data[zoneCount + i].name = (&Maps::CurrentDependencies[i])->data();
data[zoneCount + i].allocFlags = data->allocFlags;
data[zoneCount + i].freeFlags = data->freeFlags;
}
Game::DB_LoadXAssets(data, zoneCount + Maps::CurrentDependencies.size(), sync);
delete[] data;
}
bool Maps::LoadAssetRestrict(Game::XAssetType type, Game::XAssetHeader asset, const char* name)
{
if (std::find(Maps::CurrentDependencies.begin(), Maps::CurrentDependencies.end(), FastFiles::Current()) != Maps::CurrentDependencies.end())
{
if (type == Game::XAssetType::ASSET_TYPE_GAME_MAP_MP || type == Game::XAssetType::ASSET_TYPE_COL_MAP_MP || type == Game::XAssetType::ASSET_TYPE_GFX_MAP || type == Game::XAssetType::ASSET_TYPE_MAP_ENTS || type == Game::XAssetType::ASSET_TYPE_COM_MAP || type == Game::XAssetType::ASSET_TYPE_FX_MAP)
{
return false;
}
}
if (type == Game::XAssetType::ASSET_TYPE_MAP_ENTS)
{
static std::string mapEntities;
FileSystem::File ents(Utils::VA("%s.ents", name));
if (ents.Exists())
{
mapEntities = ents.GetBuffer();
asset.mapEnts->entitystring = mapEntities.data();
}
}
return true;
}
void Maps::GetBSPName(char* buffer, size_t size, const char* format, const char* mapname)
{
if (_strnicmp("mp_", mapname, 3))
{
format = "maps/%s.d3dbsp";
// Adjust pointer to GameMap_Data
Utils::Hook::Set<void*>(0x4D90B7, Maps::WorldSP);
}
else
{
// Adjust pointer to GameMap_Data
Utils::Hook::Set<void*>(0x4D90B7, Maps::WorldMP);
}
_snprintf(buffer, size, format, mapname);
}
void Maps::AddDependency(std::string expression, std::string zone)
{
// Test expression before adding it
try
{
std::regex _(expression);
}
catch (std::exception e)
{
MessageBoxA(0, Utils::VA("Invalid regular expression: %s", expression.data()), "Warning", MB_ICONEXCLAMATION);
return;
}
Maps::DependencyList[expression] = zone;
}
void Maps::ReallocateEntryPool()
{
static_assert(sizeof(Game::XAssetEntry) == 16, "XAssetEntry size mismatch");
Maps::EntryPool.clear();
Maps::EntryPool.resize(789312);
// Apply new size
Utils::Hook::Set<DWORD>(0x5BAEB0, Maps::EntryPool.size());
// Apply new pool
Utils::Hook::Set<Game::XAssetEntry*>(0x48E6F4, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x4C67E4, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x4C8584, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BAEA8, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BB0C4, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BB0F5, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BB1D4, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BB235, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BB278, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BB34C, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BB484, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BB570, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BB6B7, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BB844, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BB98D, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BBA66, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BBB8D, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BBCB1, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BBD9B, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BBE4C, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BBF14, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BBF54, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BBFB8, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BAE91, Maps::EntryPool.data() + 1);
Utils::Hook::Set<Game::XAssetEntry*>(0x5BAEA2, Maps::EntryPool.data() + 1);
}
Maps::Maps()
{
// Restrict asset loading
AssetHandler::OnLoad(Maps::LoadAssetRestrict);
// hunk size (was 300 MiB)
Utils::Hook::Set<DWORD>(0x64A029, 0x1C200000); // 450 MiB
Utils::Hook::Set<DWORD>(0x64A057, 0x1C200000);
// Intercept BSP name resolving
Utils::Hook(0x4C5979, Maps::GetBSPName, HOOK_CALL).Install()->Quick();
// Intercept map zone loading
Utils::Hook(0x42C2AF, Maps::LoadMapZones, HOOK_CALL).Install()->Quick();
Maps::WorldSP = reinterpret_cast<char*>(Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_GAME_MAP_SP, 1)) + 52; // Skip name and other padding to reach world data
Maps::WorldMP = Utils::Hook::Get<char*>(0x4D90B7);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_IMAGE, 7168);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_LOADED_SOUND, 2700);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_FX, 1200);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_LOCALIZE, 14000);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_XANIM, 8192);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_XMODEL, 5125);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_PHYSPRESET, 128);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_PIXELSHADER, 10000);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_VERTEXSHADER, 3072);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_MATERIAL, 8192);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_VERTEXDECL, 196);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_WEAPON, 2400);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_STRINGTABLE, 800);
Maps::ReallocateEntryPool();
// Dependencies
Maps::AddDependency("oilrig", "mp_subbase");
Maps::AddDependency("gulag", "mp_subbase");
Maps::AddDependency("^(?!mp_).*", "mp_subbase"); // All maps not starting with "mp_"
}
Maps::~Maps()
{
Maps::EntryPool.clear();
}
}

View File

@ -0,0 +1,27 @@
namespace Components
{
class Maps : public Component
{
public:
Maps();
~Maps();
const char* GetName() { return "Maps"; };
static void AddDependency(std::string expression, std::string zone);
private:
static void* WorldMP;
static void* WorldSP;
static std::vector<Game::XAssetEntry> EntryPool;
static std::map<std::string, std::string> DependencyList;
static std::vector<std::string> CurrentDependencies;
static void GetBSPName(char* buffer, size_t size, const char* format, const char* mapname);
static bool LoadAssetRestrict(Game::XAssetType type, Game::XAssetHeader asset, const char* name);
static void LoadMapZones(Game::XZoneInfo *zoneInfo, unsigned int zoneCount, int sync);
void ReallocateEntryPool();
};
}

View File

@ -0,0 +1,33 @@
#include "..\..\STDInclude.hpp"
namespace Components
{
Utils::Hook Materials::ImageVersionCheckHook;
void __declspec(naked) Materials::ImageVersionCheck()
{
__asm
{
cmp eax, 9
je returnSafely
jmp Materials::ImageVersionCheckHook.Original
returnSafely:
mov al, 1
add esp, 18h
retn
}
}
Materials::Materials()
{
// Allow codo images
Materials::ImageVersionCheckHook.Initialize(0x53A456, Materials::ImageVersionCheck, HOOK_CALL)->Install();
}
Materials::~Materials()
{
Materials::ImageVersionCheckHook.Uninstall();
}
}

View File

@ -0,0 +1,14 @@
namespace Components
{
class Materials : public Component
{
public:
Materials();
~Materials();
const char* GetName() { return "Materials"; };
private:
static Utils::Hook ImageVersionCheckHook;
static void ImageVersionCheck();
};
}

View File

@ -0,0 +1,535 @@
#include "..\..\STDInclude.hpp"
namespace Components
{
std::vector<Game::menuDef_t*> Menus::MenuList;
std::vector<Game::MenuList*> Menus::MenuListList;
int Menus::ReserveSourceHandle()
{
// Check if a free slot is available
int i = 1;
for (; i < MAX_SOURCEFILES; i++)
{
if (!Game::sourceFiles[i])
break;
}
if (i >= MAX_SOURCEFILES)
return 0;
// Reserve it, if yes
Game::sourceFiles[i] = (Game::source_t*)1;
return i;
}
Game::script_t* Menus::LoadMenuScript(std::string name, std::string buffer)
{
Game::script_t* script = Game::Script_Alloc(sizeof(Game::script_t) + 1 + buffer.length());
strcpy_s(script->filename, sizeof(script->filename), name.data());
script->buffer = (char*)(script + 1);
*((char*)(script + 1) + buffer.length()) = '\0';
script->script_p = script->buffer;
script->lastscript_p = script->buffer;
script->length = buffer.length();
script->end_p = &script->buffer[buffer.length()];
script->line = 1;
script->lastline = 1;
script->tokenavailable = 0;
Game::Script_SetupTokens(script, (void*)0x797F80);
script->punctuations = (Game::punctuation_t*)0x797F80;
strcpy(script->buffer, buffer.data());
script->length = Game::Script_CleanString(script->buffer);
return script;
}
int Menus::LoadMenuSource(std::string name, std::string buffer)
{
int handle = Menus::ReserveSourceHandle();
if (!Menus::IsValidSourceHandle(handle)) return 0; // No free source slot!
Game::source_t *source = nullptr;
Game::script_t *script = Menus::LoadMenuScript(name, buffer);
if (!script)
{
Game::sourceFiles[handle] = nullptr; // Free reserved slot
return 0;
}
script->next = NULL;
source = (Game::source_t *)calloc(1, sizeof(Game::source_t));
strncpy(source->filename, "string", 64);
source->scriptstack = script;
source->tokens = NULL;
source->defines = NULL;
source->indentstack = NULL;
source->skip = 0;
source->definehash = (Game::define_t**)calloc(1, 4096);
Game::sourceFiles[handle] = source;
return handle;
}
bool Menus::IsValidSourceHandle(int handle)
{
return (handle > 0 && handle < MAX_SOURCEFILES && Game::sourceFiles[handle]);
}
int Menus::KeywordHash(char* key)
{
// patch this function on-the-fly, as it's some ugly C.
Utils::Hook::Set<DWORD>(0x63FE9E, 3523);
Utils::Hook::Set<DWORD>(0x63FECB, 0x7F);
int var = 0x63FE90;
__asm
{
mov eax, key
call var
mov var, eax
}
Utils::Hook::Set<DWORD>(0x63FE9E, 531);
Utils::Hook::Set<DWORD>(0x63FECB, 0x1FF);
return var;
}
Game::menuDef_t* Menus::ParseMenu(int handle)
{
Game::menuDef_t* menu = (Game::menuDef_t*)calloc(1, sizeof(Game::menuDef_t));
menu->items = (Game::itemDef_t**)calloc(512, sizeof(Game::itemDef_t*));
Menus::MenuList.push_back(menu);
Game::pc_token_t token;
Game::keywordHash_t *key;
if (!Game::PC_ReadTokenHandle(handle, &token) || token.string[0] != '{')
{
return menu;
}
while (true)
{
ZeroMemory(&token, sizeof(token));
if (!Game::PC_ReadTokenHandle(handle, &token))
{
Game::PC_SourceError(handle, "end of file inside menu\n");
break; // Fail
}
if (*token.string == '}')
{
break; // Success
}
int idx = Menus::KeywordHash(token.string);
key = Game::menuParseKeywordHash[idx];
if (!key)
{
Game::PC_SourceError(handle, "unknown menu keyword %s", token.string);
continue;
}
if (!key->func((Game::itemDef_t*)menu, handle))
{
Game::PC_SourceError(handle, "couldn't parse menu keyword %s", token.string);
break; // Fail
}
}
return menu;
}
std::vector<Game::menuDef_t*> Menus::LoadMenu(std::string menu)
{
std::vector<Game::menuDef_t*> menus;
FileSystem::File menuFile(menu);
if (menuFile.Exists())
{
Game::pc_token_t token;
int handle = Menus::LoadMenuSource(menu, menuFile.GetBuffer());
if (Menus::IsValidSourceHandle(handle))
{
while (true)
{
ZeroMemory(&token, sizeof(token));
if (!Game::PC_ReadTokenHandle(handle, &token) || token.string[0] == '}')
{
break;
}
if (!_stricmp(token.string, "loadmenu"))
{
Game::PC_ReadTokenHandle(handle, &token);
std::vector<Game::menuDef_t*> newMenus = Menus::LoadMenu(Utils::VA("ui_mp\\%s.menu", token.string));
for (auto newMenu : newMenus)
{
menus.push_back(newMenu);
}
}
if (!_stricmp(token.string, "menudef"))
{
menus.push_back(Menus::ParseMenu(handle));
}
}
Menus::FreeMenuSource(handle);
}
}
return menus;
}
std::vector<Game::menuDef_t*> Menus::LoadMenu(Game::menuDef_t* menudef)
{
std::vector<Game::menuDef_t*> menus = Menus::LoadMenu(Utils::VA("ui_mp\\%s.menu", menudef->window.name));
if (!menus.size())
{
menus.push_back(menudef);
}
return menus;
}
Game::MenuList* Menus::LoadScriptMenu(const char* menu)
{
std::vector<Game::menuDef_t*> menus = Menus::LoadMenu(menu);
if (!menus.size()) return nullptr;
// Allocate new menu list
Game::MenuList* newList = (Game::MenuList*)calloc(1, sizeof(Game::MenuList));
newList->name = _strdup(menu);
newList->menus = (Game::menuDef_t **)calloc(menus.size(), sizeof(Game::menuDef_t *));
newList->menuCount = menus.size();
// Copy new menus
memcpy(newList->menus, menus.data(), menus.size() * sizeof(Game::menuDef_t *));
Menus::MenuListList.push_back(newList);
return newList;
}
Game::MenuList* Menus::LoadMenuList(Game::MenuList* menuList)
{
std::vector<Game::menuDef_t*> menus;
for (int i = 0; i < menuList->menuCount; i++)
{
if (!menuList->menus[i])
{
continue;
}
std::vector<Game::menuDef_t*> newMenus = Menus::LoadMenu(menuList->menus[i]);
for (auto newMenu : newMenus)
{
menus.push_back(newMenu);
}
}
// Allocate new menu list
Game::MenuList* newList = (Game::MenuList*)calloc(1, sizeof(Game::MenuList));
newList->name = _strdup(menuList->name);
newList->menus = (Game::menuDef_t **)calloc(menus.size(), sizeof(Game::menuDef_t *));
newList->menuCount = menus.size();
// Copy new menus
memcpy(newList->menus, menus.data(), menus.size() * sizeof(Game::menuDef_t *));
Menus::MenuListList.push_back(newList);
return newList;
}
void Menus::FreeMenuSource(int handle)
{
if (!Menus::IsValidSourceHandle(handle)) return;
Game::script_t *script;
Game::token_t *token;
Game::define_t *define;
Game::indent_t *indent;
Game::source_t *source = Game::sourceFiles[handle];
while (source->scriptstack)
{
script = source->scriptstack;
source->scriptstack = source->scriptstack->next;
Game::FreeMemory(script);
}
while (source->tokens)
{
token = source->tokens;
source->tokens = source->tokens->next;
Game::FreeMemory(token);
}
while (source->defines)
{
define = source->defines;
source->defines = source->defines->next;
Game::FreeMemory(define);
}
while (source->indentstack)
{
indent = source->indentstack;
source->indentstack = source->indentstack->next;
free(indent);
}
if (source->definehash) free(source->definehash);
free(source);
Game::sourceFiles[handle] = nullptr;
}
void Menus::FreeMenu(Game::menuDef_t* menudef)
{
// Do i need to free expressions and strings?
// Or does the game take care of it?
// Seems like it does...
if (menudef->items)
{
// Seems like this is obsolete as well,
// as the game handles the memory
//for (int i = 0; i < menudef->itemCount; i++)
//{
// Game::Menu_FreeItemMemory(menudef->items[i]);
//}
free(menudef->items);
}
free(menudef);
}
void Menus::FreeMenuList(Game::MenuList* menuList)
{
if (menuList)
{
if (menuList->name)
{
free((void*)menuList->name);
}
if (menuList->menus)
{
free(menuList->menus);
}
free(menuList);
}
}
void Menus::RemoveMenu(Game::menuDef_t* menudef)
{
for (auto i = Menus::MenuList.begin(); i != Menus::MenuList.end(); i++)
{
if ((*i) == menudef)
{
Menus::FreeMenu(menudef);
Menus::MenuList.erase(i);
break;
}
}
}
void Menus::RemoveMenuList(Game::MenuList* menuList)
{
if (!menuList) return;
for (auto i = Menus::MenuListList.begin(); i != Menus::MenuListList.end(); i++)
{
if ((*i)->name == menuList->name)
{
for (auto j = 0; j < menuList->menuCount; j++)
{
Menus::RemoveMenu(menuList->menus[j]);
}
Menus::FreeMenuList(menuList);
Menus::MenuListList.erase(i);
break;
}
}
}
void Menus::FreeEverything()
{
for (auto menu : Menus::MenuList)
{
Menus::FreeMenu(menu);
}
Menus::MenuList.clear();
for (auto menuList : Menus::MenuListList)
{
Menus::FreeMenuList(menuList);
}
Menus::MenuListList.clear();
}
Game::XAssetHeader Menus::MenuFileLoad(Game::XAssetType type, const char* filename)
{
Game::XAssetHeader header = { 0 };
// Check if we already loaded it
for (auto menuList : Menus::MenuListList)
{
if (!_stricmp(menuList->name, filename))
{
// Free it, seems like the game deallocated it
Menus::RemoveMenuList(menuList);
break;
}
}
Game::MenuList* menuList = Game::DB_FindXAssetHeader(type, filename).menuList;
header.menuList = menuList;
if (menuList)
{
// Parse scriptmenus!
if (!strcmp(menuList->menus[0]->window.name, "default_menu") || Utils::EndsWith(filename, ".menu"))
{
if (FileSystem::File(filename).Exists())
{
header.menuList = Menus::LoadScriptMenu(filename);
// Reset, if we didn't find scriptmenus
if (!header.menuList)
{
header.menuList = menuList;
}
}
}
else
{
header.menuList = Menus::LoadMenuList(menuList);
}
}
return header;
}
void Menus::AddMenuListHook(Game::UiContext *dc, Game::MenuList *menuList, int close)
{
Game::MenuList* menus = Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_MENUFILE, "ui_mp/menus.txt").menuList;
Game::UI_AddMenuList(dc, menus, close);
Game::UI_AddMenuList(dc, menuList, close);
}
Game::menuDef_t* Menus::FindMenuByName(Game::UiContext* dc, const char* name)
{
for (int i = 0; i < dc->menuCount; i++)
{
Game::menuDef_t* menu = dc->Menus[i];
if (menu && menu->window.name && !IsBadReadPtr(menu->window.name, 1)) // Sanity checks
{
if (!_strnicmp(name, menu->window.name, 0x7FFFFFFF))
{
return menu;
}
}
else
{
// TODO: Remove menu from stack and free if custom menu
}
}
return nullptr;
}
Menus::Menus()
{
AssetHandler::OnFind(Game::XAssetType::ASSET_TYPE_MENUFILE, Menus::MenuFileLoad);
//Utils::Hook(0x63FE80, Menus::MenuFileLoad, HOOK_JUMP).Install()->Quick();
// Custom Menus_FindByName
Utils::Hook(0x487240, Menus::FindMenuByName, HOOK_JUMP).Install()->Quick();
// Load menus ingame
Utils::Hook(0x41C178, Menus::AddMenuListHook, HOOK_CALL).Install()->Quick();
// disable the 2 new tokens in ItemParse_rect
Utils::Hook::Set<BYTE>(0x640693, 0xEB);
// don't load ASSET_TYPE_MENU assets for every menu (might cause patch menus to fail)
Utils::Hook::Nop(0x453406, 5);
//make Com_Error and similar go back to main_text instead of menu_xboxlive.
strcpy((char*)0x6FC790, "main_text");
Command::Add("openmenu", [] (Command::Params params)
{
if (params.Length() != 2)
{
Logger::Print("USAGE: openmenu <menu name>\n");
return;
}
Game::Menus_OpenByName(Game::uiContext, params[1]);
});
Command::Add("reloadmenus", [] (Command::Params params)
{
// Close all menus
Game::Menus_CloseAll(Game::uiContext);
// Free custom menus
Menus::FreeEverything();
// Only disconnect if in-game, context is updated automatically!
if (Game::CL_IsCgameInitialized())
{
Game::Cbuf_AddText(0, "disconnect\n");
}
else
{
// Reinitialize ui context
((void(*)())0x401700)();
// Reopen main menu
Game::Menus_OpenByName(Game::uiContext, "main_text");
}
});
}
Menus::~Menus()
{
Menus::FreeEverything();
}
}

View File

@ -0,0 +1,47 @@
#define MAX_SOURCEFILES 64
namespace Components
{
class Menus : public Component
{
public:
Menus();
~Menus();
const char* GetName() { return "Menus"; };
static void FreeEverything();
private:
static std::vector<Game::menuDef_t*> MenuList;
static std::vector<Game::MenuList*> MenuListList;
static Game::XAssetHeader MenuFileLoad(Game::XAssetType type, const char* filename);
static Game::MenuList* LoadMenuList(Game::MenuList* menuList);
static Game::MenuList* LoadScriptMenu(const char* menu);
static std::vector<Game::menuDef_t*> LoadMenu(Game::menuDef_t* menudef);
static std::vector<Game::menuDef_t*> LoadMenu(std::string file);
static Game::script_t* LoadMenuScript(std::string name, std::string buffer);
static int LoadMenuSource(std::string name, std::string buffer);
static int ReserveSourceHandle();
static bool IsValidSourceHandle(int handle);
static Game::menuDef_t* ParseMenu(int handle);
static void FreeMenuSource(int handle);
static void FreeMenuList(Game::MenuList* menuList);
static void FreeMenu(Game::menuDef_t* menudef);
static void RemoveMenu(Game::menuDef_t* menudef);
static void RemoveMenuList(Game::MenuList* menuList);
static void AddMenuListHook(Game::UiContext *dc, Game::MenuList *menuList, int close);
static Game::menuDef_t* FindMenuByName(Game::UiContext* dc, const char* name);
// Ugly!
static int KeywordHash(char* key);
};
}

View File

@ -0,0 +1,45 @@
#include "..\..\STDInclude.hpp"
namespace Components
{
std::map<std::string, const char*> MusicalTalent::SoundAliasList;
void MusicalTalent::Replace(std::string sound, const char* file)
{
MusicalTalent::SoundAliasList[Utils::StrToLower(sound)] = file;
}
Game::XAssetHeader MusicalTalent::ManipulateAliases(Game::XAssetType type, const char* filename)
{
Game::XAssetHeader header = { 0 };
if (MusicalTalent::SoundAliasList.find(Utils::StrToLower(filename)) != MusicalTalent::SoundAliasList.end())
{
Game::snd_alias_list_t* aliases = Game::DB_FindXAssetHeader(type, filename).aliasList;
if (aliases)
{
if (aliases->aliases->stream->type == 2)
{
aliases->aliases->stream->file = MusicalTalent::SoundAliasList[Utils::StrToLower(filename)];
}
header.aliasList = aliases;
}
}
return header;
}
MusicalTalent::MusicalTalent()
{
AssetHandler::OnFind(Game::XAssetType::ASSET_TYPE_SOUND, MusicalTalent::ManipulateAliases);
MusicalTalent::Replace("music_mainmenu_mp", "hz_boneyard_intro_LR_1.mp3");
}
MusicalTalent::~MusicalTalent()
{
MusicalTalent::SoundAliasList.clear();
}
}

View File

@ -0,0 +1,16 @@
namespace Components
{
class MusicalTalent : public Component
{
public:
MusicalTalent();
~MusicalTalent();
const char* GetName() { return "MusicalTalent"; };
static void Replace(std::string sound, const char* file);
private:
static std::map<std::string, const char*> SoundAliasList;
static Game::XAssetHeader ManipulateAliases(Game::XAssetType type, const char* filename);
};
}

View File

@ -0,0 +1,133 @@
#include "..\..\STDInclude.hpp"
namespace Components
{
std::string Network::SelectedPacket;
std::map<std::string, Network::Callback> Network::PacketHandlers;
Network::Address::Address(std::string addrString)
{
Game::NET_StringToAdr(addrString.data(), &this->address);
}
bool Network::Address::operator==(const Network::Address &obj)
{
return Game::NET_CompareAdr(this->address, obj.address);
}
void Network::Address::SetPort(unsigned short port)
{
this->address.port = port;
};
unsigned short Network::Address::GetPort()
{
return this->address.port;
}
void Network::Address::SetIP(DWORD ip)
{
*(DWORD*)this->address.ip = ip;
}
DWORD Network::Address::GetIP()
{
return *(DWORD*)this->address.ip;
}
Game::netadr_t* Network::Address::Get()
{
return &this->address;
}
const char* Network::Address::GetString()
{
return Game::NET_AdrToString(this->address);
}
void Network::Handle(std::string packet, Network::Callback callback)
{
Network::PacketHandlers[Utils::StrToLower(packet)] = callback;
}
void Network::Send(Game::netsrc_t type, Address target, std::string data)
{
Game::OOBPrintT(type, *target.Get(), data.data());
}
void Network::Send(Address target, std::string data)
{
Network::Send(Game::netsrc_t::NS_CLIENT, target, data);
}
int Network::PacketInterceptionHandler(const char* packet)
{
// Check if custom handler exists
for (auto i = Network::PacketHandlers.begin(); i != Network::PacketHandlers.end(); i++)
{
if (!_strnicmp(i->first.data(), packet, i->first.size()))
{
Network::SelectedPacket = i->first;
return 0;
}
}
// No interception
return 1;
}
void Network::DeployPacket(Game::netadr_t from, Game::msg_t* msg)
{
if (Network::PacketHandlers.find(Network::SelectedPacket) != Network::PacketHandlers.end())
{
size_t offset = Network::SelectedPacket.size() + 4 + 1;
Network::PacketHandlers[Network::SelectedPacket](from, std::string(msg->data + offset, msg->cursize - offset));
}
else
{
Logger::Print("Error: Network packet intercepted, but handler is missing!\n");
}
}
void __declspec(naked) Network::DeployPacketStub()
{
__asm
{
push ebp //C54
// esp = C54h?
mov eax, [esp + 0C54h + 14h]
push eax
mov eax, [esp + 0C58h + 10h]
push eax
mov eax, [esp + 0C5Ch + 0Ch]
push eax
mov eax, [esp + 0C60h + 08h]
push eax
mov eax, [esp + 0C64h + 04h]
push eax
call Network::DeployPacket
add esp, 14h
add esp, 4h
mov al, 1
//C50
pop edi //C4C
pop esi //C48
pop ebp //C44
pop ebx //C40
add esp, 0C40h
retn
}
}
Network::Network()
{
// maximum size in NET_OutOfBandPrint
Utils::Hook::Set<DWORD>(0x4AEF08, 0x1FFFC);
Utils::Hook::Set<DWORD>(0x4AEFA3, 0x1FFFC);
// Install interception handler
Utils::Hook(0x5AA709, Network::PacketInterceptionHandler, HOOK_CALL).Install()->Quick();
// Install packet deploy hook
Utils::Hook::Set<int>(0x5AA715, (DWORD)Network::DeployPacketStub - 0x5AA713 - 6);
}
Network::~Network()
{
Network::SelectedPacket.clear();
Network::PacketHandlers.clear();
}
}

View File

@ -0,0 +1,48 @@
namespace Components
{
class Network : public Component
{
public:
class Address
{
public:
Address() {};
Address(std::string addrString);
Address(Game::netadr_t addr) : address(addr) {}
Address(Game::netadr_t* addr) : Address(*addr) {}
Address(const Address& obj) { this->address = obj.address; };
bool operator!=(const Address &obj) { return !(*this == obj); };
bool operator==(const Address &obj);
void SetPort(unsigned short port);
unsigned short GetPort();
void SetIP(DWORD ip);
DWORD GetIP();
Game::netadr_t* Get();
const char* GetString();
private:
Game::netadr_t address;
};
typedef void(*Callback)(Address address, std::string data);
Network();
~Network();
const char* GetName() { return "Network"; };
static void Handle(std::string packet, Callback callback);
static void Send(Address target, std::string data);
static void Send(Game::netsrc_t type, Address target, std::string data);
private:
static std::string SelectedPacket;
static std::map<std::string, Callback> PacketHandlers;
static int PacketInterceptionHandler(const char* packet);
static void DeployPacket(Game::netadr_t from, Game::msg_t* msg);
static void DeployPacketStub();
};
}

View File

@ -0,0 +1,253 @@
#include "..\..\STDInclude.hpp"
namespace Components
{
Party::JoinContainer Party::Container;
std::map<uint64_t, Network::Address> Party::LobbyMap;
SteamID Party::GenerateLobbyId()
{
SteamID id;
id.AccountID = Game::Com_Milliseconds();
id.Universe = 1;
id.AccountType = 8;
id.AccountInstance = 0x40000;
return id;
}
void Party::Connect(Network::Address target)
{
Party::Container.Valid = true;
Party::Container.JoinTime = Game::Com_Milliseconds();
Party::Container.Target = target;
Party::Container.Challenge = Utils::VA("%X", Party::Container.JoinTime);
Network::Send(Party::Container.Target, Utils::VA("getinfo %s\n", Party::Container.Challenge.data()));
Command::Execute("openmenu popup_reconnectingtoparty");
}
const char* Party::GetLobbyInfo(SteamID lobby, std::string key)
{
if (Party::LobbyMap.find(lobby.Bits) != Party::LobbyMap.end())
{
Network::Address address = Party::LobbyMap[lobby.Bits];
if (key == "addr")
{
return Utils::VA("%d", address.Get()->ip[0] | (address.Get()->ip[1] << 8) | (address.Get()->ip[2] << 16) | (address.Get()->ip[3] << 24));
}
else if (key =="port")
{
return Utils::VA("%d", htons(address.GetPort()));
}
}
return "212";
}
void Party::RemoveLobby(SteamID lobby)
{
if (Party::LobbyMap.find(lobby.Bits) != Party::LobbyMap.end())
{
Party::LobbyMap.erase(Party::LobbyMap.find(lobby.Bits));
}
}
void Party::ConnectError(std::string message)
{
Command::Execute("closemenu popup_reconnectingtoparty");
Dvar::Var("partyend_reason").Set(message);
Command::Execute("openmenu menu_xboxlive_partyended");
}
Game::dvar_t* Party::RegisterMinPlayers(const char* name, int value, int min, int max, Game::dvar_flag flag, const char* description)
{
return Dvar::Register<int>(name, 1, 1, max, Game::dvar_flag::DVAR_FLAG_WRITEPROTECTED | flag, description).Get<Game::dvar_t*>();
}
Party::Party()
{
// various changes to SV_DirectConnect-y stuff to allow non-party joinees
Utils::Hook::Set<WORD>(0x460D96, 0x90E9);
Utils::Hook::Set<BYTE>(0x460F0A, 0xEB);
Utils::Hook::Set<BYTE>(0x401CA4, 0xEB);
Utils::Hook::Set<BYTE>(0x401C15, 0xEB);
// disable configstring checksum matching (it's unreliable at most)
Utils::Hook::Set<BYTE>(0x4A75A7, 0xEB); // SV_SpawnServer
Utils::Hook::Set<BYTE>(0x5AC2CF, 0xEB); // CL_ParseGamestate
Utils::Hook::Set<BYTE>(0x5AC2C3, 0xEB); // CL_ParseGamestate
// AnonymousAddRequest
Utils::Hook::Set<BYTE>(0x5B5E18, 0xEB);
Utils::Hook::Set<BYTE>(0x5B5E64, 0xEB);
Utils::Hook::Nop(0x5B5E5C, 2);
// HandleClientHandshake
Utils::Hook::Set<BYTE>(0x5B6EA5, 0xEB);
Utils::Hook::Set<BYTE>(0x5B6EF3, 0xEB);
Utils::Hook::Nop(0x5B6EEB, 2);
// Allow local connections
Utils::Hook::Set<BYTE>(0x4D43DA, 0xEB);
// LobbyID mismatch
Utils::Hook::Nop(0x4E50D6, 2);
Utils::Hook::Set<BYTE>(0x4E50DA, 0xEB);
// causes 'does current Steam lobby match' calls in Steam_JoinLobby to be ignored
Utils::Hook::Set<BYTE>(0x49D007, 0xEB);
// functions checking party heartbeat timeouts, cause random issues
Utils::Hook::Nop(0x4E532D, 5);
// Steam_JoinLobby call causes migration
Utils::Hook::Nop(0x5AF851, 5);
Utils::Hook::Set<BYTE>(0x5AF85B, 0xEB);
// Allow xpartygo in public lobbies
Utils::Hook::Set<BYTE>(0x5A969E, 0xEB);
// Patch party_minplayers to 1 and protect it
Utils::Hook(0x4D5D51, Party::RegisterMinPlayers, HOOK_CALL).Install()->Quick();
Command::Add("connect", [] (Command::Params params)
{
if (params.Length() < 2)
{
return;
}
Party::Connect(Network::Address(params[1]));
});
Renderer::OnFrame([] ()
{
if (!Party::Container.Valid) return;
if ((Game::Com_Milliseconds() - Party::Container.JoinTime) > 5000)
{
Party::Container.Valid = false;
Party::ConnectError("Server connection timed out.");
}
});
// Basic info handler
Network::Handle("getInfo", [] (Network::Address address, std::string data)
{
int clientCount = 0;
for (int i = 0; i < *Game::svs_numclients; i++)
{
if (Game::svs_clients[i].state >= 3)
{
clientCount++;
}
}
Utils::InfoString info;
info.Set("challenge", data.substr(0, data.find_first_of("\n")).data());
info.Set("gamename", "IW4");
info.Set("hostname", Dvar::Var("sv_hostname").Get<const char*>());
info.Set("mapname", Dvar::Var("mapname").Get<const char*>());
info.Set("gametype", Dvar::Var("g_gametype").Get<const char*>());
info.Set("fs_game", Dvar::Var("fs_game").Get<const char*>());
info.Set("xuid", Utils::VA("%llX", Steam::SteamUser()->GetSteamID().Bits));
info.Set("clients", Utils::VA("%i", clientCount));
info.Set("sv_maxclients", Utils::VA("%i", *Game::svs_numclients));
// Set matchtype
// 0 - No match, connecting not possible
// 1 - Party, use Steam_JoinLobby to connect
// 2 - Match, use CL_ConnectFromParty to connect
if (Dvar::Var("party_host").Get<bool>()) // Party hosting
{
info.Set("matchtype", "1");
}
else if (Dvar::Var("sv_running").Get<bool>()) // Match hosting
{
info.Set("matchtype", "2");
}
else
{
info.Set("matchtype", "0");
}
Network::Send(address, Utils::VA("infoResponse\n%s\n", info.Build().data()));
});
Network::Handle("infoResponse", [] (Network::Address address, std::string data)
{
Utils::InfoString info(data);
// Handle connection
if (Party::Container.Valid)
{
if (Party::Container.Target == address)
{
// Invalidate handler for future packets
Party::Container.Valid = false;
int matchType = atoi(info.Get("matchtype").data());
if (info.Get("challenge") != Party::Container.Challenge)
{
Party::ConnectError("Invalid join response: Challenge mismatch.");
}
else if (!matchType)
{
Party::ConnectError("Server is not hosting a match.");
}
// Connect
else if (matchType == 1) // Party
{
SteamID id = Party::GenerateLobbyId();
Party::LobbyMap[id.Bits] = address;
Game::Steam_JoinLobby(id, 0);
// Callback not registered on first try
// TODO: Fix :D
if (Party::LobbyMap.size() <= 1) Game::Steam_JoinLobby(id, 0);
}
else if (matchType == 2) // Match
{
if (atoi(info.Get("clients").data()) >= atoi(info.Get("sv_maxclients").data()))
{
Party::ConnectError("@EXE_SERVERISFULL");
}
if (info.Get("mapname") == "" || info.Get("gametype") == "")
{
Party::ConnectError("Invalid map or gametype.");
}
else
{
Dvar::Var("xblive_privatematch").Set(1);
Game::Menus_CloseAll(Game::uiContext);
char xnaddr[32];
Game::CL_ConnectFromParty(0, xnaddr, *address.Get(), 0, 0, info.Get("mapname").data(), info.Get("gametype").data());
}
}
else
{
Party::ConnectError("Invalid join response: Unknown matchtype");
}
}
}
ServerList::Insert(address, info);
});
}
Party::~Party()
{
Party::LobbyMap.clear();
}
}

View File

@ -0,0 +1,32 @@
namespace Components
{
class Party : public Component
{
public:
Party();
~Party();
const char* GetName() { return "Party"; };
static void Connect(Network::Address target);
static const char* GetLobbyInfo(SteamID lobby, std::string key);
static void RemoveLobby(SteamID lobby);
private:
struct JoinContainer
{
Network::Address Target;
std::string Challenge;
DWORD JoinTime;
bool Valid;
};
static JoinContainer Container;
static std::map<uint64_t, Network::Address> LobbyMap;
static SteamID GenerateLobbyId();
static Game::dvar_t* RegisterMinPlayers(const char* name, int value, int min, int max, Game::dvar_flag flag, const char* description);
static void ConnectError(std::string message);
};
}

View File

@ -0,0 +1,90 @@
#include "..\..\STDInclude.hpp"
namespace Components
{
__int64* QuickPatch::GetStatsID()
{
static __int64 id = 0x110000100001337;
return &id;
}
QuickPatch::QuickPatch()
{
// remove system pre-init stuff (improper quit, disk full)
Utils::Hook::Set<BYTE>(0x411350, 0xC3);
// remove STEAMSTART checking for DRM IPC
Utils::Hook::Nop(0x451145, 5);
Utils::Hook::Set<BYTE>(0x45114C, 0xEB);
// Apply new playlist
char* playlist = "mp_playlists_dlc2";
Utils::Hook::Set<char*>(0x494803, playlist);
Utils::Hook::Set<char*>(0x4C6EC1, playlist);
Utils::Hook::Set<char*>(0x4CF7F9, playlist);
Utils::Hook::Set<char*>(0x4D6E63, playlist);
Utils::Hook::Set<char*>(0x4D7358, playlist);
Utils::Hook::Set<char*>(0x4D73C8, playlist);
Utils::Hook::Set<char*>(0x4F4EA1, playlist);
Utils::Hook::Set<char*>(0x4D47FB, "mp_playlists_dlc2.ff");
Utils::Hook::Set<char*>(0x60B06E, "playlists.patch2");
// disable playlist download function
Utils::Hook::Set<BYTE>(0x4D4790, 0xC3);
// disable playlist.ff loading function
//Utils::Hook::Set<BYTE>(0x4D6E60, 0xC3);
// Load playlist, but don't delete it
Utils::Hook::Nop(0x4D6EBB, 5);
Utils::Hook::Nop(0x4D6E67, 5);
Utils::Hook::Nop(0x4D6E71, 2);
// playlist dvar 'validity check'
Utils::Hook::Set<BYTE>(0x4B1170, 0xC3);
//Got playlists is true
//Utils::Hook::Set<bool>(0x1AD3680, true);
// LSP disabled
Utils::Hook::Set<BYTE>(0x435950, 0xC3); // LSP HELLO
Utils::Hook::Set<BYTE>(0x49C220, 0xC3); // We wanted to send a logging packet, but we haven't connected to LSP!
Utils::Hook::Set<BYTE>(0x4BD900, 0xC3); // main LSP response func
Utils::Hook::Set<BYTE>(0x682170, 0xC3); // Telling LSP that we're playing a private match
// Don't delete config files if corrupted
Utils::Hook::Set<BYTE>(0x47DCB3, 0xEB);
// hopefully allow alt-tab during game, used at least in alt-enter handling
Utils::Hook::Set<DWORD>(0x45ACE0, 0xC301B0);
// fs_basegame
Utils::Hook::Set<char*>(0x6431D1, "data");
// remove limit on IWD file loading
Utils::Hook::Set<BYTE>(0x642BF3, 0xEB);
// Disable UPNP
Utils::Hook::Nop(0x60BE24, 5);
// disable the IWNet IP detection (default 'got ipdetect' flag to 1)
Utils::Hook::Set<BYTE>(0x649D6F0, 1);
// Fix stats sleeping
Utils::Hook::Set<BYTE>(0x6832BA, 0xEB);
Utils::Hook::Set<BYTE>(0x4BD190, 0xC3);
// default sv_pure to 0
Utils::Hook::Set<BYTE>(0x4D3A74, 0);
// Force debug logging
Utils::Hook::Nop(0x4AA89F, 2);
Utils::Hook::Nop(0x4AA8A1, 6);
// Patch stats steamid
Utils::Hook::Nop(0x682EBF, 20);
Utils::Hook::Nop(0x6830B1, 20);
Utils::Hook(0x682EBF, QuickPatch::GetStatsID, HOOK_CALL).Install()->Quick();
Utils::Hook(0x6830B1, QuickPatch::GetStatsID, HOOK_CALL).Install()->Quick();
}
}

View File

@ -0,0 +1,12 @@
namespace Components
{
class QuickPatch : public Component
{
public:
QuickPatch();
const char* GetName() { return "QuickPatch"; };
private:
static _int64* GetStatsID();
};
}

View File

@ -0,0 +1,24 @@
#include "..\..\STDInclude.hpp"
namespace Components
{
void* RawFiles::LoadModdableRawfileFunc(const char* filename)
{
return Game::LoadModdableRawfile(0, filename);
}
RawFiles::RawFiles()
{
Utils::Hook(0x632155, RawFiles::LoadModdableRawfileFunc, HOOK_CALL).Install()->Quick();
Utils::Hook(0x5FA46C, RawFiles::LoadModdableRawfileFunc, HOOK_CALL).Install()->Quick();
Utils::Hook(0x5FA4D6, RawFiles::LoadModdableRawfileFunc, HOOK_CALL).Install()->Quick();
Utils::Hook(0x6321EF, RawFiles::LoadModdableRawfileFunc, HOOK_CALL).Install()->Quick();
Utils::Hook(0x630A88, RawFiles::LoadModdableRawfileFunc, HOOK_CALL).Install()->Quick();
Utils::Hook(0x59A6F8, RawFiles::LoadModdableRawfileFunc, HOOK_CALL).Install()->Quick();
Utils::Hook(0x57F1E6, RawFiles::LoadModdableRawfileFunc, HOOK_CALL).Install()->Quick();
Utils::Hook(0x57ED36, RawFiles::LoadModdableRawfileFunc, HOOK_CALL).Install()->Quick();
// remove fs_game check for moddable rawfiles - allows non-fs_game to modify rawfiles
Utils::Hook::Nop(0x61AB76, 2);
}
}

View File

@ -0,0 +1,11 @@
namespace Components
{
class RawFiles : public Component
{
public:
RawFiles();
const char* GetName() { return "RawFiles"; };
static void* RawFiles::LoadModdableRawfileFunc(const char* filename);
};
}

View File

@ -0,0 +1,41 @@
#include "..\..\STDInclude.hpp"
namespace Components
{
Utils::Hook Renderer::DrawFrameHook;
std::vector<Renderer::Callback> Renderer::FrameCallbacks;
void __declspec(naked) Renderer::FrameHook()
{
__asm
{
call Renderer::FrameHandler
jmp Renderer::DrawFrameHook.Original
}
}
void Renderer::FrameHandler()
{
for (auto callback : Renderer::FrameCallbacks)
{
callback();
}
}
void Renderer::OnFrame(Renderer::Callback callback)
{
Renderer::FrameCallbacks.push_back(callback);
}
Renderer::Renderer()
{
// Frame hook
Renderer::DrawFrameHook.Initialize(0x5ACB99, Renderer::FrameHook, HOOK_CALL)->Install();
}
Renderer::~Renderer()
{
Renderer::DrawFrameHook.Uninstall();
Renderer::FrameCallbacks.clear();
}
}

View File

@ -0,0 +1,21 @@
namespace Components
{
class Renderer : public Component
{
public:
typedef void(*Callback)();
Renderer();
~Renderer();
const char* GetName() { return "Renderer"; };
static void OnFrame(Callback callback);
private:
static void FrameHook();
static void FrameHandler();
static std::vector<Callback> FrameCallbacks;
static Utils::Hook DrawFrameHook;
};
}

View File

@ -0,0 +1,272 @@
#include "..\..\STDInclude.hpp"
namespace Components
{
unsigned int ServerList::CurrentServer = 0;
ServerList::Container ServerList::RefreshContainer;
std::vector<ServerList::ServerInfo> ServerList::OnlineList;
int ServerList::GetServerCount()
{
return ServerList::OnlineList.size();
}
const char* ServerList::GetServerText(int index, int column)
{
if ((unsigned int)index >= ServerList::OnlineList.size()) return "";
ServerList::ServerInfo* Server = &ServerList::OnlineList[index];
switch (column)
{
case Column::Password:
{
return (Server->Password ? "X" : "");
}
case Column::Hostname:
{
return Server->Hostname.data();
}
case Column::Mapname:
{
return Game::UI_LocalizeMapName(Server->Mapname.data());
}
case Column::Players:
{
return Utils::VA("%i (%i)", Server->Clients, Server->MaxClients);
}
case Column::Gametype:
{
if (Server->Mod != "")
{
return (Server->Mod.data() + 5);
}
return Game::UI_LocalizeGameType(Server->Gametype.data());
}
case Column::Ping:
{
return Utils::VA("%i", Server->Ping);
}
}
return "";
}
void ServerList::SelectServer(int index)
{
ServerList::CurrentServer = (unsigned int)index;
}
void ServerList::Refresh()
{
ServerList::OnlineList.clear();
ServerList::RefreshContainer.Mutex.lock();
ServerList::RefreshContainer.Servers.clear();
ServerList::RefreshContainer.Mutex.unlock();
ServerList::RefreshContainer.SendCount = 0;
ServerList::RefreshContainer.SentCount = 0;
ServerList::RefreshContainer.AwatingList = true;
ServerList::RefreshContainer.AwaitTime = Game::Com_Milliseconds();
int masterPort = Dvar::Var("masterPort").Get<int>();
const char* masterServerName = Dvar::Var("masterServerName").Get<const char*>();
ServerList::RefreshContainer.Host = Network::Address(Utils::VA("%s:%u", masterServerName, masterPort));
Logger::Print("Sending serverlist request to master: %s:%u\n", masterServerName, masterPort);
Network::Send(ServerList::RefreshContainer.Host, "getservers IW4 145 full empty");
//Network::Send(ServerList::RefreshContainer.Host, "getservers 0 full empty\n");
}
void ServerList::Insert(Network::Address address, Utils::InfoString info)
{
ServerList::RefreshContainer.Mutex.lock();
for (auto i = ServerList::RefreshContainer.Servers.begin(); i != ServerList::RefreshContainer.Servers.end(); i++)
{
// Our desired server
if (i->Target == address && i->Sent)
{
// Challenge did not match
if (i->Challenge != info.Get("challenge"))
{
// Shall we remove the server from the queue?
// Better not, it might send a second response with the correct challenge.
// This might happen when users refresh twice (or more often) in a short period of time
break;
}
// TODO: Implement deeper check like version and game
ServerInfo server;
server.Hostname = info.Get("hostname");
server.Mapname = info.Get("mapname");
server.Gametype = info.Get("gametype");
server.Mod = info.Get("fs_game");
server.MatchType = atoi(info.Get("matchtype").data());
server.Clients = atoi(info.Get("clients").data());
server.MaxClients = atoi(info.Get("sv_maxclients").data());
server.Password = 0; // No info yet
server.Ping = (Game::Com_Milliseconds() - i->SendTime);
server.Addr = address;
// Check if already inserted and remove
for (auto j = ServerList::OnlineList.begin(); j != ServerList::OnlineList.end(); j++)
{
if (j->Addr == address)
{
ServerList::OnlineList.erase(j);
break;
}
}
ServerList::OnlineList.push_back(server);
ServerList::RefreshContainer.Servers.erase(i);
break;
}
}
ServerList::RefreshContainer.Mutex.unlock();
}
void ServerList::Frame()
{
ServerList::RefreshContainer.Mutex.lock();
if (ServerList::RefreshContainer.AwatingList)
{
// Check if we haven't got a response within 10 seconds
if (Game::Com_Milliseconds() - ServerList::RefreshContainer.AwaitTime > 5000)
{
ServerList::RefreshContainer.AwatingList = false;
Logger::Print("We haven't received a response from the master within %d seconds!\n", (Game::Com_Milliseconds() - ServerList::RefreshContainer.AwaitTime) / 1000);
}
}
// Send requests to 10 servers each frame
int SendServers = 10;
for (unsigned int i = 0; i < ServerList::RefreshContainer.Servers.size(); i++)
{
ServerList::Container::ServerContainer* server = &ServerList::RefreshContainer.Servers[i];
if (server->Sent) continue;
// Found server we can send a request to
server->Sent = true;
SendServers--;
server->SendTime = Game::Com_Milliseconds();
server->Challenge = Utils::VA("%d", server->SendTime);
ServerList::RefreshContainer.SentCount++;
Network::Send(server->Target, Utils::VA("getinfo %s\n", server->Challenge.data()));
// Display in the menu, like in COD4
//Logger::Print("Sent %d/%d\n", ServerList::RefreshContainer.SentCount, ServerList::RefreshContainer.SendCount);
if (SendServers <= 0) break;
}
ServerList::RefreshContainer.Mutex.unlock();
}
ServerList::ServerList()
{
ServerList::OnlineList.clear();
Network::Handle("getServersResponse", [] (Network::Address address, std::string data)
{
if (ServerList::RefreshContainer.Host != address) return; // Only parse from host we sent to
ServerList::RefreshContainer.AwatingList = false;
ServerList::RefreshContainer.Mutex.lock();
int offset = 0;
int count = ServerList::RefreshContainer.Servers.size();
ServerList::MasterEntry* entry = nullptr;
// Find first entry
do
{
entry = (ServerList::MasterEntry*)(data.data() + offset++);
}
while (!entry->HasSeparator() && !entry->IsEndToken());
for (int i = 0; !entry[i].IsEndToken() && entry[i].HasSeparator(); i++)
{
Network::Address serverAddr = address;
serverAddr.SetIP(entry[i].IP);
serverAddr.SetPort(entry[i].Port);
serverAddr.Get()->type = Game::NA_IP;
ServerList::Container::ServerContainer container;
container.Sent = false;
container.Target = serverAddr;
bool alreadyInserted = false;
for (auto &server : ServerList::RefreshContainer.Servers)
{
if (server.Target == container.Target)
{
alreadyInserted = true;
break;
}
}
if (!alreadyInserted)
{
ServerList::RefreshContainer.Servers.push_back(container);
ServerList::RefreshContainer.SendCount++;
}
}
Logger::Print("Parsed %d servers from master\n", ServerList::RefreshContainer.Servers.size() - count);
ServerList::RefreshContainer.Mutex.unlock();
});
// Set default masterServerName + port and save it
Utils::Hook::Set<const char*>(0x60AD92, "localhost");
Utils::Hook::Set<BYTE>(0x60AD90, Game::dvar_flag::DVAR_FLAG_SAVED); // masterServerName
Utils::Hook::Set<BYTE>(0x60ADC6, Game::dvar_flag::DVAR_FLAG_SAVED); // masterPort
// Add server list feeder
UIFeeder::Add(2.0f, ServerList::GetServerCount, ServerList::GetServerText, ServerList::SelectServer);
// Add required UIScripts
UIScript::Add("RefreshServers", ServerList::Refresh);
UIScript::Add("JoinServer", [] ()
{
if (ServerList::OnlineList.size() > ServerList::CurrentServer)
{
Party::Connect(ServerList::OnlineList[ServerList::CurrentServer].Addr);
}
});
UIScript::Add("ServerSort", [] (UIScript::Token token)
{
Logger::Print("Server list sorting by token: %d\n", token.Get<int>());
});
// Add frame callback
Renderer::OnFrame(ServerList::Frame);
}
ServerList::~ServerList()
{
ServerList::OnlineList.clear();
}
}

View File

@ -0,0 +1,94 @@
namespace Components
{
class ServerList : public Component
{
public:
struct ServerInfo
{
Network::Address Addr;
bool Visible;
std::string Hostname;
std::string Mapname;
std::string Gametype;
std::string Mod;
int Clients;
int MaxClients;
bool Password;
int Ping;
int MatchType;
bool Hardcore;
};
ServerList();
~ServerList();
const char* GetName() { return "ServerList"; };
static void Refresh();
static void Insert(Network::Address address, Utils::InfoString info);
private:
enum Column
{
Password,
Hostname,
Mapname,
Players,
Gametype,
Ping,
};
#pragma pack(push, 1)
union MasterEntry
{
char Token[7];
struct
{
uint32_t IP;
uint16_t Port;
};
bool IsEndToken()
{
// End of transmission or file token
return (Token[0] == 'E' && Token[1] == 'O' && (Token[2] == 'T' || Token[2] == 'F'));
}
bool HasSeparator()
{
return (Token[6] == '\\');
}
};
#pragma pack(pop)
struct Container
{
struct ServerContainer
{
bool Sent;
int SendTime;
std::string Challenge;
Network::Address Target;
};
bool AwatingList;
int AwaitTime;
int SentCount;
int SendCount;
Network::Address Host;
std::vector<ServerContainer> Servers;
std::mutex Mutex;
};
static int GetServerCount();
static const char* GetServerText(int index, int column);
static void SelectServer(int index);
static void Frame();
static unsigned int CurrentServer;
static Container RefreshContainer;
static std::vector<ServerInfo> OnlineList;
};
}

View File

@ -0,0 +1,23 @@
#include "..\..\STDInclude.hpp"
namespace Components
{
bool Singleton::FirstInstance = true;
bool Singleton::IsFirstInstance()
{
return Singleton::FirstInstance;
}
Singleton::Singleton()
{
if (Dedicated::IsDedicated()) return;
Singleton::FirstInstance = (CreateMutex(NULL, FALSE, "iw4x_mutex") && GetLastError() != ERROR_ALREADY_EXISTS);
if (!Singleton::FirstInstance && MessageBoxA(0, "Do you want to start a second instance?", "Game already running", MB_ICONEXCLAMATION | MB_YESNO) == IDNO)
{
ExitProcess(0);
}
}
}

View File

@ -0,0 +1,14 @@
namespace Components
{
class Singleton : public Component
{
public:
Singleton();
const char* GetName() { return "Singleton"; };
static bool IsFirstInstance();
private:
static bool FirstInstance;
};
}

View File

@ -0,0 +1,285 @@
#include "..\..\STDInclude.hpp"
namespace Components
{
UIFeeder::Container UIFeeder::Current;
std::map<float, UIFeeder::Callbacks> UIFeeder::Feeders;
void UIFeeder::Add(float feeder, UIFeeder::GetItemCount_t itemCountCb, UIFeeder::GetItemText_t itemTextCb, UIFeeder::Select_t selectCb)
{
UIFeeder::Feeders[feeder] = { itemCountCb, itemTextCb, selectCb };
}
const char* UIFeeder::GetItemText()
{
if (UIFeeder::Feeders.find(UIFeeder::Current.Feeder) != UIFeeder::Feeders.end())
{
return UIFeeder::Feeders[UIFeeder::Current.Feeder].GetItemText(UIFeeder::Current.Index, UIFeeder::Current.Column);
}
return nullptr;
}
int UIFeeder::GetItemCount()
{
if (UIFeeder::Feeders.find(UIFeeder::Current.Feeder) != UIFeeder::Feeders.end())
{
return UIFeeder::Feeders[UIFeeder::Current.Feeder].GetItemCount();
}
return 0;
}
bool UIFeeder::SetItemSelection()
{
if (UIFeeder::Feeders.find(UIFeeder::Current.Feeder) != UIFeeder::Feeders.end())
{
UIFeeder::Feeders[UIFeeder::Current.Feeder].Select(UIFeeder::Current.Index);
return true;
}
return false;
}
bool UIFeeder::CheckFeeder()
{
if (UIFeeder::Current.Feeder == 15.0f) return false;
return (UIFeeder::Feeders.find(UIFeeder::Current.Feeder) != UIFeeder::Feeders.end());
}
void __declspec(naked) UIFeeder::SetItemSelectionStub()
{
__asm
{
mov eax, [esp + 08h]
mov UIFeeder::Current.Feeder, eax
mov eax, [esp + 0Ch]
mov UIFeeder::Current.Index, eax
call UIFeeder::SetItemSelection
test al, al
jz continue
retn
continue:
fld ds : 739FD0h
mov eax, 4C25D6h
jmp eax
}
}
void __declspec(naked) UIFeeder::GetItemTextStub()
{
__asm
{
mov eax, [esp + 0Ch]
mov UIFeeder::Current.Feeder, eax
mov eax, [esp + 10h]
mov UIFeeder::Current.Index, eax
mov eax, [esp + 14h]
mov UIFeeder::Current.Column, eax
call UIFeeder::GetItemText
test eax, eax
jz continue
push ebx
mov ebx, [esp + 4 + 28h]
mov dword ptr[ebx], 0
pop ebx
retn
continue:
push ecx
fld ds:739FD0h
mov eax, 4CE9E7h
jmp eax
}
}
void __declspec(naked) UIFeeder::GetItemCountStub()
{
__asm
{
mov eax, [esp + 8h]
mov UIFeeder::Current.Feeder, eax
call UIFeeder::GetItemCount
test eax, eax
jz continue
retn
continue:
push ecx
fld ds:739FD0h
mov eax, 41A0D7h
jmp eax;
}
}
void __declspec(naked) UIFeeder::HandleKeyStub()
{
static int NextClickTime = 0;
__asm
{
mov ebx, ebp
mov eax, [ebp + 12Ch]
mov UIFeeder::Current.Feeder, eax
push ebx
call UIFeeder::CheckFeeder
pop ebx
test al, al
jz continueOriginal
// Get current milliseconds
call Game::Com_Milliseconds
// Check if allowed to click
cmp eax, NextClickTime
jl continueOriginal
// Set next allowed click time to current time + 300ms
add eax, 300
mov NextClickTime, eax
// Get item cursor position ptr
mov ecx, ebx
add ecx, Game::itemDef_t::cursorPos
// Get item listbox ptr
mov edx, ebx
add edx, Game::itemDef_t::typeData
// Get listbox cursor pos
mov edx, [edx]
add edx, Game::listBoxDef_s::startPos
mov edx, [edx]
// Resolve item cursor pos pointer
mov ebx, [ecx]
// Check if item cursor pos equals listbox cursor pos
cmp ebx, edx
je returnSafe
// Update indices if not
mov [ecx], edx
mov UIFeeder::Current.Index, edx
call UIFeeder::SetItemSelection
returnSafe:
retn
continueOriginal:
mov eax, 635570h
jmp eax
}
}
void __declspec(naked) UIFeeder::MouseEnterStub()
{
__asm
{
mov eax, [edi + 12Ch]
mov UIFeeder::Current.Feeder, eax
call UIFeeder::CheckFeeder
test al, al
jnz continue
mov[edi + 130h], esi
continue:
mov eax, 639D75h
jmp eax
}
}
void __declspec(naked) UIFeeder::MouseSelectStub()
{
__asm
{
mov eax, [esp + 08h]
mov UIFeeder::Current.Feeder, eax
call UIFeeder::CheckFeeder
test al, al
jnz continue
mov eax, 4C25D0h
jmp eax
continue:
retn
}
}
void __declspec(naked) UIFeeder::PlaySoundStub()
{
__asm
{
mov eax, [edi + 12Ch]
mov UIFeeder::Current.Feeder, eax
call UIFeeder::CheckFeeder
test al, al
jnz continue
mov eax, 685E10h
jmp eax
continue:
retn
}
}
UIFeeder::UIFeeder()
{
// Get feeder item count
Utils::Hook(0x41A0D0, UIFeeder::GetItemCountStub, HOOK_JUMP).Install()->Quick();
// Get feeder item text
Utils::Hook(0x4CE9E0, UIFeeder::GetItemTextStub, HOOK_JUMP).Install()->Quick();
// Select feeder item
Utils::Hook(0x4C25D0, UIFeeder::SetItemSelectionStub, HOOK_JUMP).Install()->Quick();
// Mouse enter check
Utils::Hook(0x639D6E, UIFeeder::MouseEnterStub, HOOK_JUMP).Install()->Quick();
// Handle key event
Utils::Hook(0x63C5BC, UIFeeder::HandleKeyStub, HOOK_CALL).Install()->Quick();
// Mouse select check
Utils::Hook(0x639D31, UIFeeder::MouseSelectStub, HOOK_CALL).Install()->Quick();
// Play mouse over sound check
Utils::Hook(0x639D66, UIFeeder::PlaySoundStub, HOOK_CALL).Install()->Quick();
// some thing overwriting feeder 2's data
Utils::Hook::Set<BYTE>(0x4A06A9, 0xEB);
}
UIFeeder::~UIFeeder()
{
UIFeeder::Feeders.clear();
}
}

View File

@ -0,0 +1,51 @@
namespace Components
{
class UIFeeder : public Component
{
public:
typedef int(__cdecl * GetItemCount_t)();
typedef const char* (__cdecl * GetItemText_t)(int index, int column);
typedef void(__cdecl * Select_t)(int index);
struct Callbacks
{
GetItemCount_t GetItemCount;
GetItemText_t GetItemText;
Select_t Select;
};
UIFeeder();
~UIFeeder();
const char* GetName() { return "UIFeeder"; };
static void Add(float feeder, GetItemCount_t itemCountCb, GetItemText_t itemTextCb, Select_t selectCb);
private:
struct Container
{
float Feeder;
int Index;
int Column;
};
static Container Current;
static void GetItemCountStub();
static int GetItemCount();
static void GetItemTextStub();
static const char* GetItemText();
static void SetItemSelectionStub();
static bool SetItemSelection();
static bool CheckFeeder();
static void MouseEnterStub();
static void MouseSelectStub();
static void HandleKeyStub();
static void PlaySoundStub();
static std::map<float, Callbacks> Feeders;
};
}

View File

@ -0,0 +1,110 @@
#include "..\..\STDInclude.hpp"
namespace Components
{
std::map<std::string, UIScript::Callback> UIScript::UIScripts;
template<> int UIScript::Token::Get()
{
if (this->IsValid())
{
return atoi(this->token);
}
return 0;
}
template<> char* UIScript::Token::Get()
{
if (this->IsValid())
{
return this->token;
}
return "";
}
template<> const char* UIScript::Token::Get()
{
return this->Get<char*>();
}
template<> std::string UIScript::Token::Get()
{
return this->Get<const char*>();
}
bool UIScript::Token::IsValid()
{
return (token && token[0]);
}
void UIScript::Token::Parse(const char** args)
{
if (args)
{
this->token = Game::Com_ParseExt(args);
}
}
void UIScript::Add(std::string name, UIScript::Callback callback)
{
UIScript::UIScripts[name] = callback;
}
void UIScript::Add(std::string name, UIScript::CallbackRaw callback)
{
UIScript::Add(name, reinterpret_cast<UIScript::Callback>(callback));
}
bool UIScript::RunMenuScript(const char* name, const char** args)
{
if (UIScript::UIScripts.find(name) != UIScript::UIScripts.end())
{
UIScript::UIScripts[name](UIScript::Token(args));
return true;
}
return false;
}
void __declspec(naked) UIScript::RunMenuScriptStub()
{
__asm
{
mov eax, esp
add eax, 8h
mov edx, eax // UIScript name
mov eax, [esp + 0C10h] // UIScript args
push eax
push edx
call UIScript::RunMenuScript
add esp, 8h
test al, al
jz continue
// if returned
pop edi
pop esi
add esp, 0C00h
retn
continue:
mov eax, 45ED00h
jmp eax
}
}
UIScript::UIScript()
{
// Install handler
Utils::Hook::Set<int>(0x45EC5B, (DWORD)UIScript::RunMenuScriptStub - 0x45EC59 - 6);
}
UIScript::~UIScript()
{
UIScript::UIScripts.clear();
}
}

View File

@ -0,0 +1,39 @@
namespace Components
{
class UIScript : public Component
{
public:
UIScript();
~UIScript();
const char* GetName() { return "UIScript"; };
class Token
{
public:
Token(const char** args) : token(0) { this->Parse(args); };
Token(const Token &obj) { this->token = obj.token; };
template<typename T> T Get();
bool IsValid();
private:
char* token;
void Parse(const char** args);
};
typedef void(*Callback)(Token token);
typedef void(*CallbackRaw)();
static void Add(std::string name, Callback callback);
static void Add(std::string name, CallbackRaw callback);
private:
static bool RunMenuScript(const char* name, const char** args);
static void RunMenuScriptStub();
static std::map<std::string, Callback> UIScripts;
};
}

View File

@ -0,0 +1,27 @@
#include "..\..\STDInclude.hpp"
namespace Components
{
Dvar::Var Window::NoBorder;
void __declspec(naked) Window::StyleHookStub()
{
if (Window::NoBorder.Get<bool>())
{
__asm mov ebp, WS_VISIBLE | WS_POPUP
}
else
{
__asm mov ebp, WS_VISIBLE | WS_SYSMENU | WS_CAPTION
}
__asm retn
}
Window::Window()
{
// Borderless window
Window::NoBorder = Dvar::Register<bool>("r_noborder", true, Game::dvar_flag::DVAR_FLAG_SAVED, "Do not use a border in windowed mode");
Utils::Hook(0x507643, Window::StyleHookStub, HOOK_CALL).Install()->Quick();
}
}

View File

@ -0,0 +1,12 @@
namespace Components
{
class Window : public Component
{
public:
Window();
const char* GetName() { return "Window"; };
static Dvar::Var NoBorder;
static void Window::StyleHookStub();
};
}

180
src/Game/Functions.cpp Normal file
View File

@ -0,0 +1,180 @@
#include "..\STDInclude.hpp"
namespace Game
{
Cbuf_AddText_t Cbuf_AddText = (Cbuf_AddText_t)0x404B20;
CL_IsCgameInitialized_t CL_IsCgameInitialized = (CL_IsCgameInitialized_t)0x43EB20;
CL_ConnectFromParty_t CL_ConnectFromParty = (CL_ConnectFromParty_t)0x433D30;
Cmd_AddCommand_t Cmd_AddCommand = (Cmd_AddCommand_t)0x470090;
Cmd_ExecuteSingleCommand_t Cmd_ExecuteSingleCommand = (Cmd_ExecuteSingleCommand_t)0x609540;
Com_Error_t Com_Error = (Com_Error_t)0x4B22D0;
Com_Printf_t Com_Printf = (Com_Printf_t)0x402500;
Com_Milliseconds_t Com_Milliseconds = (Com_Milliseconds_t)0x42A660;
Com_ParseExt_t Com_ParseExt = (Com_ParseExt_t)0x474D60;
DB_FindXAssetHeader_t DB_FindXAssetHeader = (DB_FindXAssetHeader_t)0x407930;
DB_GetXAssetNameHandler_t* DB_GetXAssetNameHandlers = (DB_GetXAssetNameHandler_t*)0x799328;
DB_GetXAssetSizeHandler_t* DB_GetXAssetSizeHandlers = (DB_GetXAssetSizeHandler_t*)0x799488;
DB_LoadXAssets_t DB_LoadXAssets = (DB_LoadXAssets_t)0x4E5930;
Dvar_RegisterBool_t Dvar_RegisterBool = (Dvar_RegisterBool_t)0x4CE1A0;
Dvar_RegisterFloat_t Dvar_RegisterFloat = (Dvar_RegisterFloat_t)0x648440;
Dvar_RegisterFloat2_t Dvar_RegisterFloat2 = (Dvar_RegisterFloat2_t)0x4F6070;
Dvar_RegisterFloat3_t Dvar_RegisterFloat3 = (Dvar_RegisterFloat3_t)0x4EF8E0;
Dvar_RegisterFloat4_t Dvar_RegisterFloat4 = (Dvar_RegisterFloat4_t)0x4F28E0;
Dvar_RegisterInt_t Dvar_RegisterInt = (Dvar_RegisterInt_t)0x479830;
Dvar_RegisterEnum_t Dvar_RegisterEnum = (Dvar_RegisterEnum_t)0x412E40;
Dvar_RegisterString_t Dvar_RegisterString = (Dvar_RegisterString_t)0x4FC7E0;
Dvar_RegisterColor_t Dvar_RegisterColor = (Dvar_RegisterColor_t)0x471500;
Dvar_FindVar_t Dvar_FindVar = (Dvar_FindVar_t)0x4D5390;
Dvar_SetCommand_t Dvar_SetCommand = (Dvar_SetCommand_t)0x4EE430;
Field_Clear_t Field_Clear = (Field_Clear_t)0x437EB0;
FreeMemory_t FreeMemory = (FreeMemory_t)0x4D6640;
FS_FileExists_t FS_FileExists = (FS_FileExists_t)0x4DEFA0;
FS_FreeFile_t FS_FreeFile = (FS_FreeFile_t)0x4416B0;
FS_ReadFile_t FS_ReadFile = (FS_ReadFile_t)0x4F4B90;
FS_ListFiles_t FS_ListFiles = (FS_ListFiles_t)0x441BB0;
FS_FreeFileList_t FS_FreeFileList = (FS_FreeFileList_t)0x4A5DE0;
FS_FOpenFileAppend_t FS_FOpenFileAppend = (FS_FOpenFileAppend_t)0x410BB0;
FS_FOpenFileAppend_t FS_FOpenFileWrite = (FS_FOpenFileAppend_t)0x4BA530;
FS_FOpenFileRead_t FS_FOpenFileRead = (FS_FOpenFileRead_t)0x46CBF0;
FS_FCloseFile_t FS_FCloseFile = (FS_FCloseFile_t)0x462000;
FS_WriteFile_t FS_WriteFile = (FS_WriteFile_t)0x426450;
FS_Write_t FS_Write = (FS_Write_t)0x4C06E0;
FS_Read_t FS_Read = (FS_Read_t)0x4A04C0;
FS_Seek_t FS_Seek = (FS_Seek_t)0x4A63D0;
FS_FTell_t FS_FTell = (FS_FTell_t)0x4E6760;
FS_Remove_t FS_Remove = (FS_Remove_t)0x4660F0;
FS_Restart_t FS_Restart = (FS_Restart_t)0x461A50;
FS_BuildPathToFile_t FS_BuildPathToFile = (FS_BuildPathToFile_t)0x4702C0;
Menus_CloseAll_t Menus_CloseAll = (Menus_CloseAll_t)0x4BA5B0;
Menus_OpenByName_t Menus_OpenByName = (Menus_OpenByName_t)0x4CCE60;
NET_AdrToString_t NET_AdrToString = (NET_AdrToString_t)0x469880;
NET_CompareAdr_t NET_CompareAdr = (NET_CompareAdr_t)0x4D0AA0;
NET_StringToAdr_t NET_StringToAdr = (NET_StringToAdr_t)0x409010;
Live_MPAcceptInvite_t Live_MPAcceptInvite = (Live_MPAcceptInvite_t)0x420A6D;
LoadInitialFF_t LoadInitialFF = (LoadInitialFF_t)0x506AC0;
LoadModdableRawfile_t LoadModdableRawfile = (LoadModdableRawfile_t)0x61ABC0;
LocalizeString_t LocalizeString = (LocalizeString_t)0x4FB010;
LocalizeMapString_t LocalizeMapString = (LocalizeMapString_t)0x44BB30;
sendOOB_t OOBPrint = (sendOOB_t)0x4AEF00;
PC_ReadToken_t PC_ReadToken = (PC_ReadToken_t)0x4ACCD0;
PC_ReadTokenHandle_t PC_ReadTokenHandle = (PC_ReadTokenHandle_t)0x4D2060;
PC_SourceError_t PC_SourceError = (PC_SourceError_t)0x467A00;
PartyHost_GetMemberAddressBySlot_t PartyHost_GetMemberAddressBySlot = (PartyHost_GetMemberAddressBySlot_t)0x44E100;
Script_Alloc_t Script_Alloc = (Script_Alloc_t)0x422E70;
Script_SetupTokens_t Script_SetupTokens = (Script_SetupTokens_t)0x4E6950;
Script_CleanString_t Script_CleanString = (Script_CleanString_t)0x498220;
SetConsole_t SetConsole = (SetConsole_t)0x44F060;
Steam_JoinLobby_t Steam_JoinLobby = (Steam_JoinLobby_t)0x49CF70;
UI_AddMenuList_t UI_AddMenuList = (UI_AddMenuList_t)0x4533C0;
Win_GetLanguage_t Win_GetLanguage = (Win_GetLanguage_t)0x45CBA0;
void** DB_XAssetPool = (void**)0x7998A8;
unsigned int* g_poolSize = (unsigned int*)0x7995E8;
DWORD* cmd_id = (DWORD*)0x1AAC5D0;
DWORD* cmd_argc = (DWORD*)0x1AAC614;
char*** cmd_argv = (char***)0x1AAC634;
source_t **sourceFiles = (source_t **)0x7C4A98;
keywordHash_t **menuParseKeywordHash = (keywordHash_t **)0x63AE928;
int* svs_numclients = (int*)0x31D938C;
client_t* svs_clients = (client_t*)0x31D9390;
UiContext *uiContext = (UiContext *)0x62E2858;
int* arenaCount = (int*)0x62E6930;
mapArena_t* arenas = (mapArena_t*)0x62E6934;
int* gameTypeCount = (int*)0x62E50A0;
gameTypeName_t* gameTypes = (gameTypeName_t*)0x62E50A4;
XBlock** g_streamBlocks = (XBlock**)0x16E554C;
void* ReallocateAssetPool(XAssetType type, unsigned int newSize)
{
int elSize = DB_GetXAssetSizeHandlers[type]();
void* poolEntry = new char[newSize * elSize];
DB_XAssetPool[type] = poolEntry;
g_poolSize[type] = newSize;
return poolEntry;
}
void Menu_FreeItemMemory(Game::itemDef_t* item)
{
__asm
{
mov edi, item
mov eax, 63D880h
call eax
}
}
void OOBPrintT(int type, netadr_t netadr, const char* message)
{
int* adr = (int*)&netadr;
OOBPrint(type, *adr, *(adr + 1), *(adr + 2), 0xFFFFFFFF, *(adr + 4), message);
}
const char* UI_LocalizeMapName(const char* mapName)
{
for (int i = 0; i < *arenaCount; i++)
{
if (!_stricmp(arenas[i].mapName, mapName))
{
char* uiName = &arenas[i].uiName[0];
if ((uiName[0] == 'M' && uiName[1] == 'P') || (uiName[0] == 'P' && uiName[1] == 'A')) // MPUI/PATCH
{
char* name = LocalizeMapString(uiName);
return name;
}
return uiName;
}
}
return mapName;
}
const char* UI_LocalizeGameType(const char* gameType)
{
if (gameType == 0 || *gameType == '\0')
{
return "";
}
for (int i = 0; i < *gameTypeCount; i++)
{
if (!_stricmp(gameTypes[i].gameType, gameType))
{
char* name = LocalizeMapString(gameTypes[i].uiName);
return name;
}
}
return gameType;
}
}

224
src/Game/Functions.hpp Normal file
View File

@ -0,0 +1,224 @@
namespace Game
{
typedef void(__cdecl * Cbuf_AddText_t)(int a1, const char* cmd);
extern Cbuf_AddText_t Cbuf_AddText;
typedef int(__cdecl * CL_IsCgameInitialized_t)();
extern CL_IsCgameInitialized_t CL_IsCgameInitialized;
typedef void(__cdecl * CL_ConnectFromParty_t)(int controller, void*, netadr_t adr, int, int, const char*, const char*);
extern CL_ConnectFromParty_t CL_ConnectFromParty;
typedef void(__cdecl * Cmd_AddCommand_t)(const char* name, void(*callback), cmd_function_t* data, char);
extern Cmd_AddCommand_t Cmd_AddCommand;
typedef void(__cdecl * Cmd_ExecuteSingleCommand_t)(int controller, int a2, const char* cmd);
extern Cmd_ExecuteSingleCommand_t Cmd_ExecuteSingleCommand;
typedef void(__cdecl * Com_Error_t)(int type, char* message, ...);
extern Com_Error_t Com_Error;
typedef void(__cdecl * Com_Printf_t)(int, const char*, ...);
extern Com_Printf_t Com_Printf;
typedef int(__cdecl * Com_Milliseconds_t)(void);
extern Com_Milliseconds_t Com_Milliseconds;
typedef char* (__cdecl * Com_ParseExt_t)(const char**);
extern Com_ParseExt_t Com_ParseExt;
typedef XAssetHeader (__cdecl * DB_FindXAssetHeader_t)(XAssetType type, const char* filename);
extern DB_FindXAssetHeader_t DB_FindXAssetHeader;
typedef const char* (__cdecl * DB_GetXAssetNameHandler_t)(Game::XAssetHeader* asset);
extern DB_GetXAssetNameHandler_t* DB_GetXAssetNameHandlers;
typedef int(__cdecl * DB_GetXAssetSizeHandler_t)();
extern DB_GetXAssetSizeHandler_t* DB_GetXAssetSizeHandlers;
typedef void(*DB_LoadXAssets_t)(XZoneInfo *zoneInfo, unsigned int zoneCount, int sync);
extern DB_LoadXAssets_t DB_LoadXAssets;
typedef dvar_t* (__cdecl * Dvar_RegisterBool_t)(const char* name, bool default, int flags, const char* description);
extern Dvar_RegisterBool_t Dvar_RegisterBool;
typedef dvar_t* (__cdecl * Dvar_RegisterFloat_t)(const char* name, float default, float min, float max, int flags, const char* description);
extern Dvar_RegisterFloat_t Dvar_RegisterFloat;
typedef dvar_t* (__cdecl * Dvar_RegisterFloat2_t)(const char* name, float defx, float defy, float min, float max, int flags, const char* description);
extern Dvar_RegisterFloat2_t Dvar_RegisterFloat2;
typedef dvar_t* (__cdecl * Dvar_RegisterFloat3_t)(const char* name, float defx, float defy, float defz, float min, float max, int flags, const char* description);
extern Dvar_RegisterFloat3_t Dvar_RegisterFloat3;
typedef dvar_t* (__cdecl * Dvar_RegisterFloat4_t)(const char* name, float defx, float defy, float defz, float defw, float min, float max, int flags, const char* description);
extern Dvar_RegisterFloat4_t Dvar_RegisterFloat4;
typedef dvar_t* (__cdecl * Dvar_RegisterInt_t)(const char* name, int default, int min, int max, int flags, const char* description);
extern Dvar_RegisterInt_t Dvar_RegisterInt;
typedef dvar_t* (__cdecl * Dvar_RegisterEnum_t)(const char* name, char** enumValues, int default, int flags, const char* description);
extern Dvar_RegisterEnum_t Dvar_RegisterEnum;
typedef dvar_t* (__cdecl * Dvar_RegisterString_t)(const char* name, const char* default, int, const char*);
extern Dvar_RegisterString_t Dvar_RegisterString;
typedef dvar_t* (__cdecl * Dvar_RegisterColor_t)(const char* name, float r, float g, float b, float a, int flags, const char* description);
extern Dvar_RegisterColor_t Dvar_RegisterColor;
typedef dvar_t* (__cdecl * Dvar_FindVar_t)(const char *dvarName);
extern Dvar_FindVar_t Dvar_FindVar;
typedef dvar_t* (__cdecl * Dvar_SetCommand_t)(const char* name, const char* value);
extern Dvar_SetCommand_t Dvar_SetCommand;
typedef void(__cdecl * Field_Clear_t)(void* field);
extern Field_Clear_t Field_Clear;
typedef void(__cdecl * FreeMemory_t)(void* buffer);
extern FreeMemory_t FreeMemory;
typedef void(__cdecl * FS_FreeFile_t)(void* buffer);
extern FS_FreeFile_t FS_FreeFile;
typedef int(__cdecl * FS_ReadFile_t)(const char* path, char** buffer);
extern FS_ReadFile_t FS_ReadFile;
typedef char** (__cdecl * FS_ListFiles_t)(const char *path, const char *extension, FsListBehavior_e behavior, int *numfiles, int allocTrackType);
extern FS_ListFiles_t FS_ListFiles;
typedef void(__cdecl * FS_FreeFileList_t)(char** list);
extern FS_FreeFileList_t FS_FreeFileList;
typedef int(__cdecl * FS_FOpenFileAppend_t)(char* file);
extern FS_FOpenFileAppend_t FS_FOpenFileAppend;
extern FS_FOpenFileAppend_t FS_FOpenFileWrite;
typedef int(__cdecl * FS_FOpenFileRead_t)(const char* file, int* fh, int uniqueFile);
extern FS_FOpenFileRead_t FS_FOpenFileRead;
typedef int(__cdecl * FS_FCloseFile_t)(int fh);
extern FS_FCloseFile_t FS_FCloseFile;
typedef bool(__cdecl * FS_FileExists_t)(const char* file);
extern FS_FileExists_t FS_FileExists;
typedef bool(__cdecl * FS_WriteFile_t)(char* filename, char* folder, void* buffer, int size);
extern FS_WriteFile_t FS_WriteFile;
typedef int(__cdecl * FS_Write_t)(void* buffer, size_t size, int file);
extern FS_Write_t FS_Write;
typedef int(__cdecl * FS_Read_t)(void* buffer, size_t size, int file);
extern FS_Read_t FS_Read;
typedef int(__cdecl * FS_Seek_t)(int fileHandle, int seekPosition, int seekOrigin);
extern FS_Seek_t FS_Seek;
typedef int(__cdecl * FS_FTell_t)(int fileHandle);
extern FS_FTell_t FS_FTell;
typedef int(__cdecl * FS_Remove_t)(char *);
extern FS_Remove_t FS_Remove;
typedef int(__cdecl * FS_Restart_t)(int a1, int a2);
extern FS_Restart_t FS_Restart;
typedef int(__cdecl * FS_BuildPathToFile_t)(const char*, const char*, const char*, char**);
extern FS_BuildPathToFile_t FS_BuildPathToFile;
typedef void(__cdecl * Menus_CloseAll_t)(UiContext *dc);
extern Menus_CloseAll_t Menus_CloseAll;
typedef int(__cdecl * Menus_OpenByName_t)(UiContext *dc, const char *p);
extern Menus_OpenByName_t Menus_OpenByName;
typedef const char* (__cdecl * NET_AdrToString_t)(netadr_t adr);
extern NET_AdrToString_t NET_AdrToString;
typedef bool(__cdecl * NET_CompareAdr_t)(netadr_t, netadr_t);
extern NET_CompareAdr_t NET_CompareAdr;
typedef bool(__cdecl * NET_StringToAdr_t)(const char*, netadr_t*);
extern NET_StringToAdr_t NET_StringToAdr;
typedef void(__cdecl * Live_MPAcceptInvite_t)(_XSESSION_INFO *hostInfo, const int controllerIndex, bool fromGameInvite);
extern Live_MPAcceptInvite_t Live_MPAcceptInvite;
typedef void(*LoadInitialFF_t)(void);
extern LoadInitialFF_t LoadInitialFF;
typedef void* (__cdecl * LoadModdableRawfile_t)(int a1, const char* filename);
extern LoadModdableRawfile_t LoadModdableRawfile;
typedef char* (__cdecl * LocalizeString_t)(char*, char*);
extern LocalizeString_t LocalizeString;
typedef char* (__cdecl * LocalizeMapString_t)(char*);
extern LocalizeMapString_t LocalizeMapString;
typedef void(__cdecl* sendOOB_t)(int, int, int, int, int, int, const char*);
extern sendOOB_t OOBPrint;
typedef int(__cdecl * PC_ReadToken_t)(source_t*, token_t*);
extern PC_ReadToken_t PC_ReadToken;
typedef int(__cdecl * PC_ReadTokenHandle_t)(int handle, pc_token_s *pc_token);
extern PC_ReadTokenHandle_t PC_ReadTokenHandle;
typedef void(__cdecl * PC_SourceError_t)(int, const char*, ...);
extern PC_SourceError_t PC_SourceError;
typedef netadr_t *(__cdecl * PartyHost_GetMemberAddressBySlot_t)(int unk, void *party, const int slot);
extern PartyHost_GetMemberAddressBySlot_t PartyHost_GetMemberAddressBySlot;
typedef script_t* (__cdecl * Script_Alloc_t)(int length);
extern Script_Alloc_t Script_Alloc;
typedef void(__cdecl * Script_SetupTokens_t)(script_t* script, void* tokens);
extern Script_SetupTokens_t Script_SetupTokens;
typedef int(__cdecl * Script_CleanString_t)(char* buffer);
extern Script_CleanString_t Script_CleanString;
typedef void(__cdecl * SetConsole_t)(const char* cvar, const char* value);
extern SetConsole_t SetConsole;
typedef void(__cdecl * Steam_JoinLobby_t)(SteamID, char);
extern Steam_JoinLobby_t Steam_JoinLobby;
typedef void(__cdecl * UI_AddMenuList_t)(UiContext *dc, MenuList *menuList, int close);
extern UI_AddMenuList_t UI_AddMenuList;
typedef const char * (__cdecl * Win_GetLanguage_t)();
extern Win_GetLanguage_t Win_GetLanguage;
extern void** DB_XAssetPool;
extern unsigned int* g_poolSize;
extern DWORD* cmd_id;
extern DWORD* cmd_argc;
extern char*** cmd_argv;
extern int* svs_numclients;
extern client_t* svs_clients;
extern source_t **sourceFiles;
extern keywordHash_t **menuParseKeywordHash;
extern UiContext *uiContext;
extern int* arenaCount;
extern mapArena_t* arenas;
extern int* gameTypeCount;
extern gameTypeName_t* gameTypes;
extern XBlock** g_streamBlocks;
void* ReallocateAssetPool(XAssetType type, unsigned int newSize);
void Menu_FreeItemMemory(Game::itemDef_t* item);
void OOBPrintT(int type, netadr_t netadr, const char* message);
const char* UI_LocalizeMapName(const char* mapName);
const char* UI_LocalizeGameType(const char* gameType);
}

944
src/Game/Structs.hpp Normal file
View File

@ -0,0 +1,944 @@
namespace Game
{
typedef enum
{
ASSET_TYPE_PHYSPRESET = 0,
ASSET_TYPE_PHYS_COLLMAP = 1,
ASSET_TYPE_XANIM = 2,
ASSET_TYPE_XMODELSURFS = 3,
ASSET_TYPE_XMODEL = 4,
ASSET_TYPE_MATERIAL = 5,
ASSET_TYPE_PIXELSHADER = 6,
ASSET_TYPE_VERTEXSHADER = 7,
ASSET_TYPE_VERTEXDECL = 8,
ASSET_TYPE_TECHSET = 9,
ASSET_TYPE_IMAGE = 10,
ASSET_TYPE_SOUND = 11,
ASSET_TYPE_SNDCURVE = 12,
ASSET_TYPE_LOADED_SOUND = 13,
ASSET_TYPE_COL_MAP_SP = 14,
ASSET_TYPE_COL_MAP_MP = 15,
ASSET_TYPE_COM_MAP = 16,
ASSET_TYPE_GAME_MAP_SP = 17,
ASSET_TYPE_GAME_MAP_MP = 18,
ASSET_TYPE_MAP_ENTS = 19,
ASSET_TYPE_FX_MAP = 20,
ASSET_TYPE_GFX_MAP = 21,
ASSET_TYPE_LIGHTDEF = 22,
ASSET_TYPE_UI_MAP = 23,
ASSET_TYPE_FONT = 24,
ASSET_TYPE_MENUFILE = 25,
ASSET_TYPE_MENU = 26,
ASSET_TYPE_LOCALIZE = 27,
ASSET_TYPE_WEAPON = 28,
ASSET_TYPE_SNDDRIVERGLOBALS = 29,
ASSET_TYPE_FX = 30,
ASSET_TYPE_IMPACTFX = 31,
ASSET_TYPE_AITYPE = 32,
ASSET_TYPE_MPTYPE = 33,
ASSET_TYPE_CHARACTER = 34,
ASSET_TYPE_XMODELALIAS = 35,
ASSET_TYPE_RAWFILE = 36,
ASSET_TYPE_STRINGTABLE = 37,
ASSET_TYPE_LEADERBOARDDEF = 38,
ASSET_TYPE_STRUCTUREDDATADEF = 39,
ASSET_TYPE_TRACER = 40,
ASSET_TYPE_VEHICLE = 41,
ASSET_TYPE_ADDON_MAP_ENTS = 42,
ASSET_TYPE_MAX = 43
} XAssetType;
typedef enum
{
DVAR_FLAG_NONE = 0x0, //no flags
DVAR_FLAG_SAVED = 0x1, //saves in config_mp.cfg for clients
DVAR_FLAG_LATCHED = 0x2, //no changing apart from initial value (although it might apply on a map reload, I think)
DVAR_FLAG_CHEAT = 0x4, //cheat
DVAR_FLAG_REPLICATED = 0x8, //on change, this is sent to all clients (if you are host)
DVAR_FLAG_UNKNOWN10 = 0x10, //unknown
DVAR_FLAG_UNKNOWN20 = 0x20, //unknown
DVAR_FLAG_UNKNOWN40 = 0x40, //unknown
DVAR_FLAG_UNKNOWN80 = 0x80, //unknown
DVAR_FLAG_USERCREATED = 0x100, //a 'set' type command created it
DVAR_FLAG_USERINFO = 0x200, //userinfo?
DVAR_FLAG_SERVERINFO = 0x400, //in the getstatus oob
DVAR_FLAG_WRITEPROTECTED = 0x800, //write protected
DVAR_FLAG_UNKNOWN1000 = 0x1000, //unknown
DVAR_FLAG_READONLY = 0x2000, //read only (same as 0x800?)
DVAR_FLAG_UNKNOWN4000 = 0x4000, //unknown
DVAR_FLAG_UNKNOWN8000 = 0x8000, //unknown
DVAR_FLAG_UNKNOWN10000 = 0x10000, //unknown
DVAR_FLAG_DEDISAVED = 0x1000000, //unknown
DVAR_FLAG_NONEXISTENT = 0xFFFFFFFF //no such dvar
} dvar_flag;
typedef enum
{
DVAR_TYPE_BOOL = 0,
DVAR_TYPE_FLOAT = 1,
DVAR_TYPE_FLOAT_2 = 2,
DVAR_TYPE_FLOAT_3 = 3,
DVAR_TYPE_FLOAT_4 = 4,
DVAR_TYPE_INT = 5,
DVAR_TYPE_ENUM = 6,
DVAR_TYPE_STRING = 7,
DVAR_TYPE_COLOR = 8,
//DVAR_TYPE_INT64 = 9 only in Tx
} dvar_type;
// 67/72 bytes figured out
union dvar_value_t {
char* string;
int integer;
float value;
bool boolean;
float vec2[2];
float vec3[3];
float vec4[4];
BYTE color[4]; //to get float: multiply by 0.003921568859368563 - BaberZz
//__int64 integer64; only in Tx
};
union dvar_maxmin_t {
int i;
float f;
};
typedef struct dvar_t
{
//startbyte:endbyte
const char* name; //0:3
const char* description; //4:7
unsigned int flags; //8:11
char type; //12:12
char pad2[3]; //13:15
dvar_value_t current; //16:31
dvar_value_t latched; //32:47
dvar_value_t default; //48:64
dvar_maxmin_t min; //65:67
dvar_maxmin_t max; //68:72 woooo
} dvar_t;
typedef struct cmd_function_s
{
char pad[24];
} cmd_function_t;
typedef struct
{
char type;
char pad[3];
const char* folder;
const char* file;
} StreamFile;
typedef struct
{
char pad[20];
StreamFile* stream;
char pad2[76];
} snd_alias_t;
typedef struct
{
const char* name;
snd_alias_t* aliases;
int numAliases;
} snd_alias_list_t;
typedef struct
{
const char *name;
int allocFlags;
int freeFlags;
} XZoneInfo;
typedef float vec_t;
typedef vec_t vec4_t[4];
struct expression_s;
struct statement_s;
struct menuDef_t;
enum operationEnum;
struct Material
{
const char *name;
};
struct keyname_t
{
const char *name;
int keynum;
};
struct ItemFloatExpressionEntry
{
int target;
const char *s1;
const char *s2;
};
#define ITEM_TYPE_TEXT 0 // simple text
#define ITEM_TYPE_BUTTON 1 // button, basically text with a border
#define ITEM_TYPE_RADIOBUTTON 2 // toggle button, may be grouped
#define ITEM_TYPE_CHECKBOX 3 // check box
#define ITEM_TYPE_EDITFIELD 4 // editable text, associated with a dvar
#define ITEM_TYPE_COMBO 5 // drop down list
#define ITEM_TYPE_LISTBOX 6 // scrollable list
#define ITEM_TYPE_MODEL 7 // model
#define ITEM_TYPE_OWNERDRAW 8 // owner draw, name specs what it is
#define ITEM_TYPE_NUMERICFIELD 9 // editable text, associated with a dvar
#define ITEM_TYPE_SLIDER 10 // mouse speed, volume, etc.
#define ITEM_TYPE_YESNO 11 // yes no dvar setting
#define ITEM_TYPE_MULTI 12 // multiple list setting, enumerated
#define ITEM_TYPE_DVARENUM 13 // multiple list setting, enumerated from a dvar
#define ITEM_TYPE_BIND 14 // bind
#define ITEM_TYPE_MENUMODEL 15 // special menu model
#define ITEM_TYPE_VALIDFILEFIELD 16 // text must be valid for use in a dos filename
#define ITEM_TYPE_DECIMALFIELD 17 // editable text, associated with a dvar, which allows decimal input
#define ITEM_TYPE_UPREDITFIELD 18 // editable text, associated with a dvar
#define ITEM_TYPE_GAME_MESSAGE_WINDOW 19 // game message window
#define ITEM_TYPE_NEWSTICKER 20 // horizontal scrollbox
#define ITEM_TYPE_TEXTSCROLL 21 // vertical scrollbox
#define ITEM_TYPE_EMAILFIELD 22
#define ITEM_TYPE_PASSWORDFIELD 23
struct MenuEventHandlerSet;
struct Statement_s;
struct UIFunctionList
{
int totalFunctions;
Statement_s **functions;
};
struct StaticDvar
{
/*dvar_t*/
void *dvar;
char *dvarName;
};
struct StaticDvarList
{
int numStaticDvars;
StaticDvar **staticDvars;
};
struct StringList
{
int totalStrings;
const char **strings;
};
struct ExpressionSupportingData
{
UIFunctionList uifunctions;
StaticDvarList staticDvarList;
StringList uiStrings;
};
enum expDataType : int
{
VAL_INT = 0x0,
VAL_FLOAT = 0x1,
VAL_STRING = 0x2,
VAL_FUNCTION = 0x3,
};
struct ExpressionString
{
const char *string;
};
union operandInternalDataUnion
{
int intVal;
float floatVal;
ExpressionString stringVal;
Statement_s *function;
};
struct Operand
{
expDataType dataType;
operandInternalDataUnion internals;
};
union entryInternalData
{
operationEnum op;
Operand operand;
};
/* expressionEntry->type */
#define OPERATOR 0
#define OPERAND 1
struct expressionEntry // 0xC
{
int type;
entryInternalData data;
};
struct Statement_s // 0x18
{
int numEntries;
expressionEntry *entries;
ExpressionSupportingData *supportingData;
char unknown[0xC]; // ?
};
struct SetLocalVarData
{
const char *localVarName;
Statement_s *expression;
};
struct ConditionalScript
{
MenuEventHandlerSet *eventHandlerSet;
Statement_s *eventExpression; // loads this first
};
union EventData
{
const char *unconditionalScript;
ConditionalScript *conditionalScript;
MenuEventHandlerSet *elseScript;
SetLocalVarData *setLocalVarData;
};
enum EventType
{
EVENT_UNCONDITIONAL = 0x0,
EVENT_IF = 0x1,
EVENT_ELSE = 0x2,
EVENT_SET_LOCAL_VAR_BOOL = 0x3,
EVENT_SET_LOCAL_VAR_INT = 0x4,
EVENT_SET_LOCAL_VAR_FLOAT = 0x5,
EVENT_SET_LOCAL_VAR_STRING = 0x6,
EVENT_COUNT = 0x7,
};
struct MenuEventHandler
{
EventData eventData;
EventType eventType;
};
struct MenuEventHandlerSet
{
int eventHandlerCount;
MenuEventHandler **eventHandlers;
};
struct ItemKeyHandler
{
int key;
MenuEventHandlerSet *action;
ItemKeyHandler *next;
};
#pragma pack(push, 4)
struct rectDef_s
{
float x;
float y;
float w;
float h;
char horzAlign;
char vertAlign;
};
#pragma pack(pop)
/* windowDef_t->dynamicFlags */
// 0x1
#define WINDOWDYNAMIC_HASFOCUS 0x00000002
#define WINDOWDYNAMIC_VISIBLE 0x00000004
#define WINDOWDYNAMIC_FADEOUT 0x00000010
#define WINDOWDYNAMIC_FADEIN 0x00000020
// 0x40
// 0x80
#define WINDOWDYNAMIC_CLOSED 0x00000800
// 0x2000
#define WINDOWDYNAMIC_BACKCOLOR 0x00008000
#define WINDOWDYNAMIC_FORECOLOR 0x00010000
/* windowDef_t->staticFlags */
#define WINDOWSTATIC_DECORATION 0x00100000
#define WINDOWSTATIC_HORIZONTALSCROLL 0x00200000
#define WINDOWSTATIC_SCREENSPACE 0x00400000
#define WINDOWSTATIC_AUTOWRAPPED 0x00800000
#define WINDOWSTATIC_POPUP 0x01000000
#define WINDOWSTATIC_OUTOFBOUNDSCLICK 0x02000000
#define WINDOWSTATIC_LEGACYSPLITSCREENSCALE 0x04000000
#define WINDOWSTATIC_HIDDENDURINGFLASH 0x10000000
#define WINDOWSTATIC_HIDDENDURINGSCOPE 0x20000000
#define WINDOWSTATIC_HIDDENDURINGUI 0x40000000
#define WINDOWSTATIC_TEXTONLYFOCUS 0x80000000
struct windowDef_t // 0xA4
{
const char *name; // 0x00
rectDef_s rect;
rectDef_s rectClient;
char *group; // 0x2C
int style; // 0x30
int border; // 0x34
int ownerDraw; // 0x38
int ownerDrawFlags; // 0x3C
float borderSize; // 0x40
int staticFlags; // 0x44
int dynamicFlags; // 0x48
int nextTime; // 0x4C
float foreColor[4]; // 0x50
float backColor[4]; // 0x60
float borderColor[4];// 0x70
float outlineColor[4];// 0x80
float disableColor[4];// 0x90
Material *background; // 0xA0
};
enum ItemFloatExpressionTarget
{
ITEM_FLOATEXP_TGT_RECT_X = 0x0,
ITEM_FLOATEXP_TGT_RECT_Y = 0x1,
ITEM_FLOATEXP_TGT_RECT_W = 0x2,
ITEM_FLOATEXP_TGT_RECT_H = 0x3,
ITEM_FLOATEXP_TGT_FORECOLOR_R = 0x4,
ITEM_FLOATEXP_TGT_FORECOLOR_G = 0x5,
ITEM_FLOATEXP_TGT_FORECOLOR_B = 0x6,
ITEM_FLOATEXP_TGT_FORECOLOR_RGB = 0x7,
ITEM_FLOATEXP_TGT_FORECOLOR_A = 0x8,
ITEM_FLOATEXP_TGT_GLOWCOLOR_R = 0x9,
ITEM_FLOATEXP_TGT_GLOWCOLOR_G = 0xA,
ITEM_FLOATEXP_TGT_GLOWCOLOR_B = 0xB,
ITEM_FLOATEXP_TGT_GLOWCOLOR_RGB = 0xC,
ITEM_FLOATEXP_TGT_GLOWCOLOR_A = 0xD,
ITEM_FLOATEXP_TGT_BACKCOLOR_R = 0xE,
ITEM_FLOATEXP_TGT_BACKCOLOR_G = 0xF,
ITEM_FLOATEXP_TGT_BACKCOLOR_B = 0x10,
ITEM_FLOATEXP_TGT_BACKCOLOR_RGB = 0x11,
ITEM_FLOATEXP_TGT_BACKCOLOR_A = 0x12,
ITEM_FLOATEXP_TGT__COUNT = 0x13,
};
struct ItemFloatExpression
{
ItemFloatExpressionTarget target;
Statement_s *expression;
};
struct editFieldDef_s
{
float minVal;
float maxVal;
float defVal;
float range;
int maxChars;
int maxCharsGotoNext;
int maxPaintChars;
int paintOffset;
};
struct multiDef_s // 0x188
{
const char *dvarList[32];
const char *dvarStr[32];
float dvarValue[32];
int count;
int strDef;
};
struct columnInfo_s
{
int xpos;
int width;
int maxChars;
int alignment;
};
struct listBoxDef_s // 0x144
{
// somethings not right here
int startPos[2];
int endPos[2];
float elementWidth;
float elementHeight;
int elementStyle;
int numColumns;
columnInfo_s columnInfo[16];
MenuEventHandlerSet *doubleClick; // 0xC8
int notselectable;
int noscrollbars;
int usepaging;
float selectBorder[4];
Material *selectIcon;
};
struct newsTickerDef_s
{
int feedId;
int speed;
int spacing;
};
struct textScrollDef_s
{
int startTime;
};
union itemDefData_t
{
listBoxDef_s *listBox;
editFieldDef_s *editField;
newsTickerDef_s *ticker;
multiDef_s *multiDef;
const char *enumDvarName;
textScrollDef_s *scroll;
void *data;
};
struct itemDef_t
{
windowDef_t window;
rectDef_s textRect;
int type;
int dataType;
int alignment;
int fontEnum;
int textAlignMode;
float textAlignX;
float textAlignY;
float textScale;
int textStyle;
int gameMsgWindowIndex;
int gameMsgWindowMode;
const char *text;
int textSaveGameInfo;
int parent;
MenuEventHandlerSet *mouseEnterText;
MenuEventHandlerSet *mouseExitText;
MenuEventHandlerSet *mouseEnter;
MenuEventHandlerSet *mouseExit;
MenuEventHandlerSet *action;
MenuEventHandlerSet *accept;
MenuEventHandlerSet *onFocus;
MenuEventHandlerSet *leaveFocus;
const char *dvar;
const char *dvarTest;
ItemKeyHandler *onKey;
const char *enableDvar;
const char *localVar;
int dvarFlags;
const char *focusSound;
float special;
int cursorPos;
itemDefData_t typeData;
int imageTrack;
int floatExpressionCount;
ItemFloatExpression *floatExpressions;
Statement_s *visibleExp;
Statement_s *disabledExp;
Statement_s *textExp;
Statement_s *materialExp;
float glowColor[4];
bool decayActive;
int fxBirthTime;
int fxLetterTime;
int fxDecayStartTime;
int fxDecayDuration;
int lastSoundPlayedTime;
};
struct menuTransition // 0x18
{
int transitionType;
int startTime;
float startVal;
float endVal;
float time;
int endTriggerType;
};
struct menuDef_t
{
windowDef_t window;
int font;
int fullscreen;
int itemCount;
int fontIndex;
int cursorItems;
int fadeCycle;
float fadeClamp;
float fadeAmount;
float fadeInAmount;
float blurRadius;
MenuEventHandlerSet *onOpen;
MenuEventHandlerSet *onRequestClose;
MenuEventHandlerSet *onClose;
MenuEventHandlerSet *onEsc;
ItemKeyHandler *onKey;
Statement_s *visibleExp;
const char *allowedBinding;
const char *soundLoop;
int imageTrack;
float focusColor[4];
Statement_s *rectXExp;
Statement_s *rectYExp;
Statement_s *rectHExp;
Statement_s *rectWExp;
Statement_s *openSoundExp;
Statement_s *closeSoundExp;
itemDef_t **items;
char unknown[112];
ExpressionSupportingData *expressionData;
};
struct MenuList
{
const char *name;
int menuCount;
menuDef_t **menus;
};
enum FsListBehavior_e
{
FS_LIST_PURE_ONLY = 0x0,
FS_LIST_ALL = 0x1,
};
typedef enum
{
NA_BOT,
NA_BAD, // an address lookup failed
NA_LOOPBACK,
NA_BROADCAST,
NA_IP,
NA_IP6, // custom type
} netadrtype_t;
typedef enum
{
NS_CLIENT,
NS_SERVER
} netsrc_t;
typedef struct
{
netadrtype_t type;
BYTE ip[4];
unsigned short port;
BYTE ipx[10];
} netadr_t;
typedef struct
{
int unknown1;
int unknown2;
char* data;
int unknown3;
int maxsize; // 16
int cursize;
int unknown4;
int readcount; // 28
} msg_t;
#pragma pack(push, 1)
typedef struct client_s
{
// 0
int state;
// 4
char pad[36];
// 40
netadr_t adr;
// 60
char pad1[1568];
// 1628
char connectInfoString[1024];
// 2652
char pad2[133192];
// 135844
char name[16];
// 135860
char pad3[12];
// 135872
int snapNum;
// 135876
int pad4;
// 135880
short ping;
// 135882
//char pad5[142390];
char pad5[133158];
// 269040
int isBot;
// 269044
char pad6[9228];
// 278272
__int64 steamid;
// 278280
char pad7[403592];
} client_t;
#pragma pack(pop)
// Q3TA precompiler code
//undef if binary numbers of the form 0b... or 0B... are not allowed
#define BINARYNUMBERS
//undef if not using the token.intvalue and token.floatvalue
#define NUMBERVALUE
//use dollar sign also as punctuation
#define DOLLAR
//maximum token length
#define MAX_TOKEN 1024
//punctuation
typedef struct punctuation_s
{
char *p; //punctuation character(s)
int n; //punctuation indication
struct punctuation_s *next; //next punctuation
} punctuation_t;
//token
typedef struct token_s
{
char string[MAX_TOKEN]; //available token
int type; //last read token type
int subtype; //last read token sub type
#ifdef NUMBERVALUE
unsigned long int intvalue; //integer value
long double floatvalue; //floating point value
#endif //NUMBERVALUE
char *whitespace_p; //start of white space before token
char *endwhitespace_p; //start of white space before token
int line; //line the token was on
int linescrossed; //lines crossed in white space
struct token_s *next; //next token in chain
} token_t;
//script file
typedef struct script_s
{
char filename[64]; //file name of the script
char *buffer; //buffer containing the script
char *script_p; //current pointer in the script
char *end_p; //pointer to the end of the script
char *lastscript_p; //script pointer before reading token
char *whitespace_p; //begin of the white space
char *endwhitespace_p; //end of the white space
int length; //length of the script in bytes
int line; //current line in script
int lastline; //line before reading token
int tokenavailable; //set by UnreadLastToken
int flags; //several script flags
punctuation_t *punctuations; //the punctuations used in the script
punctuation_t **punctuationtable;
token_t token; //available token
struct script_s *next; //next script in a chain
} script_t;
//macro definitions
typedef struct define_s
{
char *name; //define name
int flags; //define flags
int builtin; // > 0 if builtin define
int numparms; //number of define parameters
token_t *parms; //define parameters
token_t *tokens; //macro tokens (possibly containing parm tokens)
struct define_s *next; //next defined macro in a list
struct define_s *hashnext; //next define in the hash chain
} define_t;
//indents
//used for conditional compilation directives:
//#if, #else, #elif, #ifdef, #ifndef
typedef struct indent_s
{
int type; //indent type
int skip; //true if skipping current indent
script_t *script; //script the indent was in
struct indent_s *next; //next indent on the indent stack
} indent_t;
//source file
typedef struct source_s
{
char filename[64]; //file name of the script
char includepath[64]; //path to include files
punctuation_t *punctuations; //punctuations to use
script_t *scriptstack; //stack with scripts of the source
token_t *tokens; //tokens to read first
define_t *defines; //list with macro definitions
define_t **definehash; //hash chain with defines
indent_t *indentstack; //stack with indents
int skip; // > 0 if skipping conditional code
token_t token; //last read token
} source_t;
#define MAX_TOKENLENGTH 1024
typedef struct pc_token_s
{
int type;
int subtype;
int intvalue;
float floatvalue;
char string[MAX_TOKENLENGTH];
} pc_token_t;
//token types
#define TT_STRING 1 // string
#define TT_LITERAL 2 // literal
#define TT_NUMBER 3 // number
#define TT_NAME 4 // name
#define TT_PUNCTUATION 5 // punctuation
//typedef int menuDef_t;
//typedef int itemDef_t;
#define KEYWORDHASH_SIZE 512
typedef struct keywordHash_s
{
char *keyword;
bool(*func)(itemDef_t *item, int handle);
//struct keywordHash_s *next;
} keywordHash_t;
enum UILocalVarType
{
UILOCALVAR_INT = 0x0,
UILOCALVAR_FLOAT = 0x1,
UILOCALVAR_STRING = 0x2,
};
struct UILocalVar
{
UILocalVarType type;
const char *name;
union
{
int integer;
float value;
const char *string;
};
};
struct UILocalVarContext
{
UILocalVar table[256];
};
struct UiContext
{
// int localClientNum;
// float bias;
// int realTime;
// int frameTime;
// int cursorx;
// int cursory;
// int debug;
// int screenWidth;
// int screenHeight;
// float screenAspect;
// float FPS;
// float blurRadiusOut;
char pad[56];
menuDef_t *Menus[512];
char pad2[512];
int menuCount;
// Unsure if below is correct
menuDef_t *menuStack[16];
int openMenuCount;
UILocalVarContext localVars;
};
struct localizedEntry_s
{
const char* value;
const char* name;
};
struct MapEnts
{
const char* name;
const char* entitystring;
};
union XAssetHeader
{
void *data;
MenuList *menuList;
menuDef_t *menu;
Material *material;
snd_alias_list_t *aliasList;
localizedEntry_s *localize;
MapEnts* mapEnts;
};
struct XAsset
{
XAssetType type;
XAssetHeader header;
};
struct XBlock
{
char *data;
unsigned int size;
};
struct XAssetEntry
{
XAsset asset;
char zoneIndex;
bool inuse;
unsigned __int16 nextHash;
unsigned __int16 nextOverride;
unsigned __int16 usageFrame;
};
struct XNKID
{
char ab[8];
};
struct XNADDR
{
in_addr ina;
in_addr inaOnline;
unsigned __int16 wPortOnline;
char abEnet[6];
char abOnline[20];
};
struct XNKEY
{
char ab[16];
};
struct _XSESSION_INFO
{
XNKID sessionID;
XNADDR hostAddress;
XNKEY keyExchangeKey;
};
struct mapArena_t
{
char uiName[32];
char mapName[16];
char pad[2768];
};
struct gameTypeName_t
{
char gameType[12];
char uiName[32];
};
}

29
src/Main.cpp Normal file
View File

@ -0,0 +1,29 @@
#include "STDInclude.hpp"
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
static Utils::Hook EntryPointHook;
if (ul_reason_for_call == DLL_PROCESS_ATTACH)
{
FreeConsole();
DWORD oldProtect;
VirtualProtect(GetModuleHandle(NULL), 0x6C73000, PAGE_EXECUTE_READWRITE, &oldProtect);
EntryPointHook.Initialize(0x6BAC0F, [] ()
{
EntryPointHook.Uninstall();
Components::Loader::Initialize();
__asm jmp EntryPointHook.Place
})->Install();
}
else if (ul_reason_for_call == DLL_PROCESS_DETACH)
{
Components::Loader::Uninitialize();
}
return TRUE;
}

34
src/STDInclude.hpp Normal file
View File

@ -0,0 +1,34 @@
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <wincrypt.h>
#include <time.h>
#include <timeapi.h>
#include <WinSock2.h>
#pragma comment(lib, "Winmm.lib")
#pragma comment(lib, "Crypt32.lib")
#pragma comment(lib, "Ws2_32.lib")
#include <map>
#include <mutex>
#include <string>
#include <vector>
#include <sstream>
#include <utility>
#include <algorithm>
#include <regex>
#include "Utils\Utils.hpp"
#include "Utils\Hooking.hpp"
#include "Steam\Steam.hpp"
#include "Game\Structs.hpp"
#include "Game\Functions.hpp"
#include "Components\Loader.hpp"

View File

@ -0,0 +1,120 @@
#include "..\..\STDInclude.hpp"
using namespace Components;
namespace Steam
{
const char *Friends::GetPersonaName()
{
return Dvar::Var("name").Get<const char*>();
}
void Friends::SetPersonaName(const char *pchPersonaName)
{
Dvar::Var("name").Set(pchPersonaName);
}
int Friends::GetPersonaState()
{
return 1;
}
int Friends::GetFriendCount(int eFriendFlags)
{
return 0;
}
SteamID Friends::GetFriendByIndex(int iFriend, int iFriendFlags)
{
return SteamID();
}
int Friends::GetFriendRelationship(SteamID steamIDFriend)
{
return 0;
}
int Friends::GetFriendPersonaState(SteamID steamIDFriend)
{
return 0;
}
const char *Friends::GetFriendPersonaName(SteamID steamIDFriend)
{
return "";
}
int Friends::GetFriendAvatar(SteamID steamIDFriend, int eAvatarSize)
{
return 0;
}
bool Friends::GetFriendGamePlayed(SteamID steamIDFriend, void *pFriendGameInfo)
{
return false;
}
const char *Friends::GetFriendPersonaNameHistory(SteamID steamIDFriend, int iPersonaName)
{
return "";
}
bool Friends::HasFriend(SteamID steamIDFriend, int eFriendFlags)
{
return false;
}
int Friends::GetClanCount()
{
return 0;
}
SteamID Friends::GetClanByIndex(int iClan)
{
return SteamID();
}
const char *Friends::GetClanName(SteamID steamIDClan)
{
return "3arc";
}
int Friends::GetFriendCountFromSource(SteamID steamIDSource)
{
return 0;
}
SteamID Friends::GetFriendFromSourceByIndex(SteamID steamIDSource, int iFriend)
{
return SteamID();
}
bool Friends::IsUserInSource(SteamID steamIDUser, SteamID steamIDSource)
{
return false;
}
void Friends::SetInGameVoiceSpeaking(SteamID steamIDUser, bool bSpeaking)
{
}
void Friends::ActivateGameOverlay(const char *pchDialog)
{
}
void Friends::ActivateGameOverlayToUser(const char *pchDialog, SteamID steamID)
{
}
void Friends::ActivateGameOverlayToWebPage(const char *pchURL)
{
}
void Friends::ActivateGameOverlayToStore(unsigned int nAppID)
{
}
void Friends::SetPlayedWith(SteamID steamIDUserPlayedWith)
{
}
}

View File

@ -0,0 +1,31 @@
namespace Steam
{
class Friends
{
public:
virtual const char *GetPersonaName();
virtual void SetPersonaName(const char *pchPersonaName);
virtual int GetPersonaState();
virtual int GetFriendCount(int eFriendFlags);
virtual SteamID GetFriendByIndex(int iFriend, int iFriendFlags);
virtual int GetFriendRelationship(SteamID steamIDFriend);
virtual int GetFriendPersonaState(SteamID steamIDFriend);
virtual const char *GetFriendPersonaName(SteamID steamIDFriend);
virtual int GetFriendAvatar(SteamID steamIDFriend, int eAvatarSize);
virtual bool GetFriendGamePlayed(SteamID steamIDFriend, void *pFriendGameInfo);
virtual const char *GetFriendPersonaNameHistory(SteamID steamIDFriend, int iPersonaName);
virtual bool HasFriend(SteamID steamIDFriend, int eFriendFlags);
virtual int GetClanCount();
virtual SteamID GetClanByIndex(int iClan);
virtual const char *GetClanName(SteamID steamIDClan);
virtual int GetFriendCountFromSource(SteamID steamIDSource);
virtual SteamID GetFriendFromSourceByIndex(SteamID steamIDSource, int iFriend);
virtual bool IsUserInSource(SteamID steamIDUser, SteamID steamIDSource);
virtual void SetInGameVoiceSpeaking(SteamID steamIDUser, bool bSpeaking);
virtual void ActivateGameOverlay(const char *pchDialog);
virtual void ActivateGameOverlayToUser(const char *pchDialog, SteamID steamID);
virtual void ActivateGameOverlayToWebPage(const char *pchURL);
virtual void ActivateGameOverlayToStore(unsigned int nAppID);
virtual void SetPlayedWith(SteamID steamIDUserPlayedWith);
};
}

View File

@ -0,0 +1,91 @@
#include "..\..\STDInclude.hpp"
namespace Steam
{
void GameServer::LogOn()
{
}
void GameServer::LogOff()
{
}
bool GameServer::LoggedOn()
{
return true;
}
bool GameServer::Secure()
{
return false;
}
SteamID GameServer::GetSteamID()
{
return SteamID();
}
bool GameServer::SendUserConnectAndAuthenticate(unsigned int unIPClient, const void *pvAuthBlob, unsigned int cubAuthBlobSize, SteamID *pSteamIDUser)
{
return true;
}
SteamID GameServer::CreateUnauthenticatedUserConnection()
{
return SteamID();
}
void GameServer::SendUserDisconnect(SteamID steamIDUser)
{
}
bool GameServer::UpdateUserData(SteamID steamIDUser, const char *pchPlayerName, unsigned int uScore)
{
return true;
}
bool GameServer::SetServerType(unsigned int unServerFlags, unsigned int unGameIP, unsigned short unGamePort, unsigned short unSpectatorPort, unsigned short usQueryPort, const char *pchGameDir, const char *pchVersion, bool bLANMode)
{
return true;
}
void GameServer::UpdateServerStatus(int cPlayers, int cPlayersMax, int cBotPlayers, const char *pchServerName, const char *pSpectatorServerName, const char *pchMapName)
{
}
void GameServer::UpdateSpectatorPort(unsigned short unSpectatorPort)
{
}
void GameServer::SetGameType(const char *pchGameType)
{
}
bool GameServer::GetUserAchievementStatus(SteamID steamID, const char *pchAchievementName)
{
return false;
}
void GameServer::GetGameplayStats()
{
}
bool GameServer::RequestUserGroupStatus(SteamID steamIDUser, SteamID steamIDGroup)
{
return false;
}
unsigned int GameServer::GetPublicIP()
{
return 0;
}
void GameServer::SetGameData(const char *pchGameData)
{
}
int GameServer::UserHasLicenseForApp(SteamID steamID, unsigned int appID)
{
return 0;
}
}

View File

@ -0,0 +1,26 @@
namespace Steam
{
class GameServer
{
public:
virtual void LogOn();
virtual void LogOff();
virtual bool LoggedOn();
virtual bool Secure();
virtual SteamID GetSteamID();
virtual bool SendUserConnectAndAuthenticate(unsigned int unIPClient, const void *pvAuthBlob, unsigned int cubAuthBlobSize, SteamID *pSteamIDUser);
virtual SteamID CreateUnauthenticatedUserConnection();
virtual void SendUserDisconnect(SteamID steamIDUser);
virtual bool UpdateUserData(SteamID steamIDUser, const char *pchPlayerName, unsigned int uScore);
virtual bool SetServerType(unsigned int unServerFlags, unsigned int unGameIP, unsigned short unGamePort, unsigned short unSpectatorPort, unsigned short usQueryPort, const char *pchGameDir, const char *pchVersion, bool bLANMode);
virtual void UpdateServerStatus(int cPlayers, int cPlayersMax, int cBotPlayers, const char *pchServerName, const char *pSpectatorServerName, const char *pchMapName);
virtual void UpdateSpectatorPort(unsigned short unSpectatorPort);
virtual void SetGameType(const char *pchGameType);
virtual bool GetUserAchievementStatus(SteamID steamID, const char *pchAchievementName);
virtual void GetGameplayStats();
virtual bool RequestUserGroupStatus(SteamID steamIDUser, SteamID steamIDGroup);
virtual unsigned int GetPublicIP();
virtual void SetGameData(const char *pchGameData);
virtual int UserHasLicenseForApp(SteamID steamID, unsigned int appID);
};
}

View File

@ -0,0 +1,67 @@
#include "..\..\STDInclude.hpp"
namespace Steam
{
void MasterServerUpdater::SetActive(bool bActive)
{
}
void MasterServerUpdater::SetHeartbeatInterval(int iHeartbeatInterval)
{
}
bool MasterServerUpdater::HandleIncomingPacket(const void *pData, int cbData, unsigned int srcIP, unsigned short srcPort)
{
return true;
}
int MasterServerUpdater::GetNextOutgoingPacket(void *pOut, int cbMaxOut, unsigned int *pNetAdr, unsigned short *pPort)
{
return 0;
}
void MasterServerUpdater::SetBasicServerData(unsigned short nProtocolVersion, bool bDedicatedServer, const char *pRegionName, const char *pProductName, unsigned short nMaxReportedClients, bool bPasswordProtected, const char *pGameDescription)
{
}
void MasterServerUpdater::ClearAllKeyValues()
{
}
void MasterServerUpdater::SetKeyValue(const char *pKey, const char *pValue)
{
}
void MasterServerUpdater::NotifyShutdown()
{
}
bool MasterServerUpdater::WasRestartRequested()
{
return false;
}
void MasterServerUpdater::ForceHeartbeat()
{
}
bool MasterServerUpdater::AddMasterServer(const char *pServerAddress)
{
return true;
}
bool MasterServerUpdater::RemoveMasterServer(const char *pServerAddress)
{
return true;
}
int MasterServerUpdater::GetNumMasterServers()
{
return 0;
}
int MasterServerUpdater::GetMasterServerAddress(int iServer, char *pOut, int outBufferSize)
{
return 0;
}
}

View File

@ -0,0 +1,21 @@
namespace Steam
{
class MasterServerUpdater
{
public:
virtual void SetActive(bool bActive);
virtual void SetHeartbeatInterval(int iHeartbeatInterval);
virtual bool HandleIncomingPacket(const void *pData, int cbData, unsigned int srcIP, unsigned short srcPort);
virtual int GetNextOutgoingPacket(void *pOut, int cbMaxOut, unsigned int *pNetAdr, unsigned short *pPort);
virtual void SetBasicServerData(unsigned short nProtocolVersion, bool bDedicatedServer, const char *pRegionName, const char *pProductName, unsigned short nMaxReportedClients, bool bPasswordProtected, const char *pGameDescription);
virtual void ClearAllKeyValues();
virtual void SetKeyValue(const char *pKey, const char *pValue);
virtual void NotifyShutdown();
virtual bool WasRestartRequested();
virtual void ForceHeartbeat();
virtual bool AddMasterServer(const char *pServerAddress);
virtual bool RemoveMasterServer(const char *pServerAddress);
virtual int GetNumMasterServers();
virtual int GetMasterServerAddress(int iServer, char *pOut, int outBufferSize);
};
}

View File

@ -0,0 +1,193 @@
#include "..\..\STDInclude.hpp"
namespace Steam
{
int Matchmaking::GetFavoriteGameCount()
{
return 0;
}
bool Matchmaking::GetFavoriteGame(int iGame, unsigned int *pnAppID, unsigned int *pnIP, unsigned short *pnConnPort, unsigned short *pnQueryPort, unsigned int *punFlags, unsigned int *pRTime32LastPlayedOnServer)
{
return false;
}
int Matchmaking::AddFavoriteGame(unsigned int nAppID, unsigned int nIP, unsigned short nConnPort, unsigned short nQueryPort, unsigned int unFlags, unsigned int rTime32LastPlayedOnServer)
{
return 0;
}
bool Matchmaking::RemoveFavoriteGame(unsigned int nAppID, unsigned int nIP, unsigned short nConnPort, unsigned short nQueryPort, unsigned int unFlags)
{
return false;
}
unsigned __int64 Matchmaking::RequestLobbyList()
{
return 0;
}
void Matchmaking::AddRequestLobbyListStringFilter(const char *pchKeyToMatch, const char *pchValueToMatch, int eComparisonType)
{
}
void Matchmaking::AddRequestLobbyListNumericalFilter(const char *pchKeyToMatch, int nValueToMatch, int eComparisonType)
{
}
void Matchmaking::AddRequestLobbyListNearValueFilter(const char *pchKeyToMatch, int nValueToBeCloseTo)
{
}
void Matchmaking::AddRequestLobbyListFilterSlotsAvailable(int nSlotsAvailable)
{
}
SteamID Matchmaking::GetLobbyByIndex(int iLobby)
{
return SteamID();
}
unsigned __int64 Matchmaking::CreateLobby(int eLobbyType, int cMaxMembers)
{
uint64_t result = Callbacks::RegisterCall();
LobbyCreated* retvals = new LobbyCreated;
SteamID id;
id.AccountID = 1337132;
id.Universe = 1;
id.AccountType = 8;
id.AccountInstance = 0x40000;
retvals->m_eResult = 1;
retvals->m_ulSteamIDLobby = id;
Callbacks::ReturnCall(retvals, sizeof(LobbyCreated), LobbyCreated::CallbackID, result);
Matchmaking::JoinLobby(id);
return result;
}
unsigned __int64 Matchmaking::JoinLobby(SteamID steamIDLobby)
{
uint64_t result = Callbacks::RegisterCall();
LobbyEnter* retvals = new LobbyEnter;
retvals->m_bLocked = false;
retvals->m_EChatRoomEnterResponse = 1;
retvals->m_rgfChatPermissions = 0xFFFFFFFF;
retvals->m_ulSteamIDLobby = steamIDLobby;
Callbacks::ReturnCall(retvals, sizeof(LobbyEnter), LobbyEnter::CallbackID, result);
return result;
}
void Matchmaking::LeaveLobby(SteamID steamIDLobby)
{
Components::Party::RemoveLobby(steamIDLobby);
}
bool Matchmaking::InviteUserToLobby(SteamID steamIDLobby, SteamID steamIDInvitee)
{
return true;
}
int Matchmaking::GetNumLobbyMembers(SteamID steamIDLobby)
{
return 1;
}
SteamID Matchmaking::GetLobbyMemberByIndex(SteamID steamIDLobby, int iMember)
{
return SteamUser()->GetSteamID();
}
const char *Matchmaking::GetLobbyData(SteamID steamIDLobby, const char *pchKey)
{
return Components::Party::GetLobbyInfo(steamIDLobby, pchKey);
}
bool Matchmaking::SetLobbyData(SteamID steamIDLobby, const char *pchKey, const char *pchValue)
{
return true;
}
int Matchmaking::GetLobbyDataCount(SteamID steamIDLobby)
{
return 0;
}
bool Matchmaking::GetLobbyDataByIndex(SteamID steamIDLobby, int iLobbyData, char *pchKey, int cchKeyBufferSize, char *pchValue, int cchValueBufferSize)
{
return false;
}
bool Matchmaking::DeleteLobbyData(SteamID steamIDLobby, const char *pchKey)
{
return false;
}
const char *Matchmaking::GetLobbyMemberData(SteamID steamIDLobby, SteamID steamIDUser, const char *pchKey)
{
return "";
}
void Matchmaking::SetLobbyMemberData(SteamID steamIDLobby, const char *pchKey, const char *pchValue)
{
}
bool Matchmaking::SendLobbyChatMsg(SteamID steamIDLobby, const void *pvMsgBody, int cubMsgBody)
{
return true;
}
int Matchmaking::GetLobbyChatEntry(SteamID steamIDLobby, int iChatID, SteamID *pSteamIDUser, void *pvData, int cubData, int *peChatEntryType)
{
return 0;
}
bool Matchmaking::RequestLobbyData(SteamID steamIDLobby)
{
return false;
}
void Matchmaking::SetLobbyGameServer(SteamID steamIDLobby, unsigned int unGameServerIP, unsigned short unGameServerPort, SteamID steamIDGameServer)
{
}
bool Matchmaking::GetLobbyGameServer(SteamID steamIDLobby, unsigned int *punGameServerIP, unsigned short *punGameServerPort, SteamID *psteamIDGameServer)
{
return false;
}
bool Matchmaking::SetLobbyMemberLimit(SteamID steamIDLobby, int cMaxMembers)
{
return true;
}
int Matchmaking::GetLobbyMemberLimit(SteamID steamIDLobby)
{
return 0;
}
bool Matchmaking::SetLobbyType(SteamID steamIDLobby, int eLobbyType)
{
return true;
}
bool Matchmaking::SetLobbyJoinable(SteamID steamIDLobby, bool bLobbyJoinable)
{
return true;
}
SteamID Matchmaking::GetLobbyOwner(SteamID steamIDLobby)
{
return SteamUser()->GetSteamID();
}
bool Matchmaking::SetLobbyOwner(SteamID steamIDLobby, SteamID steamIDNewOwner)
{
return true;
}
}

View File

@ -0,0 +1,60 @@
namespace Steam
{
struct LobbyCreated
{
enum { CallbackID = 513 };
int m_eResult;
int m_pad;
SteamID m_ulSteamIDLobby;
};
struct LobbyEnter
{
enum { CallbackID = 504 };
SteamID m_ulSteamIDLobby;
int m_rgfChatPermissions;
bool m_bLocked;
int m_EChatRoomEnterResponse;
};
class Matchmaking
{
public:
virtual int GetFavoriteGameCount();
virtual bool GetFavoriteGame(int iGame, unsigned int *pnAppID, unsigned int *pnIP, unsigned short *pnConnPort, unsigned short *pnQueryPort, unsigned int *punFlags, unsigned int *pRTime32LastPlayedOnServer);
virtual int AddFavoriteGame(unsigned int nAppID, unsigned int nIP, unsigned short nConnPort, unsigned short nQueryPort, unsigned int unFlags, unsigned int rTime32LastPlayedOnServer);
virtual bool RemoveFavoriteGame(unsigned int nAppID, unsigned int nIP, unsigned short nConnPort, unsigned short nQueryPort, unsigned int unFlags);
virtual unsigned __int64 RequestLobbyList();
virtual void AddRequestLobbyListStringFilter(const char *pchKeyToMatch, const char *pchValueToMatch, int eComparisonType);
virtual void AddRequestLobbyListNumericalFilter(const char *pchKeyToMatch, int nValueToMatch, int eComparisonType);
virtual void AddRequestLobbyListNearValueFilter(const char *pchKeyToMatch, int nValueToBeCloseTo);
virtual void AddRequestLobbyListFilterSlotsAvailable(int nSlotsAvailable);
virtual SteamID GetLobbyByIndex(int iLobby);
virtual unsigned __int64 CreateLobby(int eLobbyType, int cMaxMembers);
virtual unsigned __int64 JoinLobby(SteamID steamIDLobby);
virtual void LeaveLobby(SteamID steamIDLobby);
virtual bool InviteUserToLobby(SteamID steamIDLobby, SteamID steamIDInvitee);
virtual int GetNumLobbyMembers(SteamID steamIDLobby);
virtual SteamID GetLobbyMemberByIndex(SteamID steamIDLobby, int iMember);
virtual const char *GetLobbyData(SteamID steamIDLobby, const char *pchKey);
virtual bool SetLobbyData(SteamID steamIDLobby, const char *pchKey, const char *pchValue);
virtual int GetLobbyDataCount(SteamID steamIDLobby);
virtual bool GetLobbyDataByIndex(SteamID steamIDLobby, int iLobbyData, char *pchKey, int cchKeyBufferSize, char *pchValue, int cchValueBufferSize);
virtual bool DeleteLobbyData(SteamID steamIDLobby, const char *pchKey);
virtual const char *GetLobbyMemberData(SteamID steamIDLobby, SteamID steamIDUser, const char *pchKey);
virtual void SetLobbyMemberData(SteamID steamIDLobby, const char *pchKey, const char *pchValue);
virtual bool SendLobbyChatMsg(SteamID steamIDLobby, const void *pvMsgBody, int cubMsgBody);
virtual int GetLobbyChatEntry(SteamID steamIDLobby, int iChatID, SteamID *pSteamIDUser, void *pvData, int cubData, int *peChatEntryType);
virtual bool RequestLobbyData(SteamID steamIDLobby);
virtual void SetLobbyGameServer(SteamID steamIDLobby, unsigned int unGameServerIP, unsigned short unGameServerPort, SteamID steamIDGameServer);
virtual bool GetLobbyGameServer(SteamID steamIDLobby, unsigned int *punGameServerIP, unsigned short *punGameServerPort, SteamID *psteamIDGameServer);
virtual bool SetLobbyMemberLimit(SteamID steamIDLobby, int cMaxMembers);
virtual int GetLobbyMemberLimit(SteamID steamIDLobby);
virtual bool SetLobbyType(SteamID steamIDLobby, int eLobbyType);
virtual bool SetLobbyJoinable(SteamID steamIDLobby, bool bLobbyJoinable);
virtual SteamID GetLobbyOwner(SteamID steamIDLobby);
virtual bool SetLobbyOwner(SteamID steamIDLobby, SteamID steamIDNewOwner);
};
}

View File

@ -0,0 +1,104 @@
#include "..\..\STDInclude.hpp"
namespace Steam
{
bool Networking::SendP2PPacket(SteamID steamIDRemote, const void *pubData, unsigned int cubData, int eP2PSendType)
{
return false;
}
bool Networking::IsP2PPacketAvailable(unsigned int *pcubMsgSize)
{
return false;
}
bool Networking::ReadP2PPacket(void *pubDest, unsigned int cubDest, unsigned int *pcubMsgSize, SteamID *psteamIDRemote)
{
return false;
}
bool Networking::AcceptP2PSessionWithUser(SteamID steamIDRemote)
{
return false;
}
bool Networking::CloseP2PSessionWithUser(SteamID steamIDRemote)
{
return false;
}
bool Networking::GetP2PSessionState(SteamID steamIDRemote, void *pConnectionState)
{
return false;
}
unsigned int Networking::CreateListenSocket(int nVirtualP2PPort, unsigned int nIP, unsigned short nPort, bool bAllowUseOfPacketRelay)
{
return NULL;
}
unsigned int Networking::CreateP2PConnectionSocket(SteamID steamIDTarget, int nVirtualPort, int nTimeoutSec, bool bAllowUseOfPacketRelay)
{
return NULL;
}
unsigned int Networking::CreateConnectionSocket(unsigned int nIP, unsigned short nPort, int nTimeoutSec)
{
return NULL;
}
bool Networking::DestroySocket(unsigned int hSocket, bool bNotifyRemoteEnd)
{
return false;
}
bool Networking::DestroyListenSocket(unsigned int hSocket, bool bNotifyRemoteEnd)
{
return false;
}
bool Networking::SendDataOnSocket(unsigned int hSocket, void *pubData, unsigned int cubData, bool bReliable)
{
return false;
}
bool Networking::IsDataAvailableOnSocket(unsigned int hSocket, unsigned int *pcubMsgSize)
{
return false;
}
bool Networking::RetrieveDataFromSocket(unsigned int hSocket, void *pubDest, unsigned int cubDest, unsigned int *pcubMsgSize)
{
return false;
}
bool Networking::IsDataAvailable(unsigned int hListenSocket, unsigned int *pcubMsgSize, unsigned int *phSocket)
{
return false;
}
bool Networking::RetrieveData(unsigned int hListenSocket, void *pubDest, unsigned int cubDest, unsigned int *pcubMsgSize, unsigned int *phSocket)
{
return false;
}
bool Networking::GetSocketInfo(unsigned int hSocket, SteamID *pSteamIDRemote, int *peSocketStatus, unsigned int *punIPRemote, unsigned short *punPortRemote)
{
return false;
}
bool Networking::GetListenSocketInfo(unsigned int hListenSocket, unsigned int *pnIP, unsigned short *pnPort)
{
return false;
}
int Networking::GetSocketConnectionType(unsigned int hSocket)
{
return 0;
}
int Networking::GetMaxPacketSize(unsigned int hSocket)
{
return 0;
}
}

View File

@ -0,0 +1,27 @@
namespace Steam
{
class Networking
{
public:
virtual bool SendP2PPacket(SteamID steamIDRemote, const void *pubData, unsigned int cubData, int eP2PSendType);
virtual bool IsP2PPacketAvailable(unsigned int *pcubMsgSize);
virtual bool ReadP2PPacket(void *pubDest, unsigned int cubDest, unsigned int *pcubMsgSize, SteamID *psteamIDRemote);
virtual bool AcceptP2PSessionWithUser(SteamID steamIDRemote);
virtual bool CloseP2PSessionWithUser(SteamID steamIDRemote);
virtual bool GetP2PSessionState(SteamID steamIDRemote, void *pConnectionState);
virtual unsigned int CreateListenSocket(int nVirtualP2PPort, unsigned int nIP, unsigned short nPort, bool bAllowUseOfPacketRelay);
virtual unsigned int CreateP2PConnectionSocket(SteamID steamIDTarget, int nVirtualPort, int nTimeoutSec, bool bAllowUseOfPacketRelay);
virtual unsigned int CreateConnectionSocket(unsigned int nIP, unsigned short nPort, int nTimeoutSec);
virtual bool DestroySocket(unsigned int hSocket, bool bNotifyRemoteEnd);
virtual bool DestroyListenSocket(unsigned int hSocket, bool bNotifyRemoteEnd);
virtual bool SendDataOnSocket(unsigned int hSocket, void *pubData, unsigned int cubData, bool bReliable);
virtual bool IsDataAvailableOnSocket(unsigned int hSocket, unsigned int *pcubMsgSize);
virtual bool RetrieveDataFromSocket(unsigned int hSocket, void *pubDest, unsigned int cubDest, unsigned int *pcubMsgSize);
virtual bool IsDataAvailable(unsigned int hListenSocket, unsigned int *pcubMsgSize, unsigned int *phSocket);
virtual bool RetrieveData(unsigned int hListenSocket, void *pubDest, unsigned int cubDest, unsigned int *pcubMsgSize, unsigned int *phSocket);
virtual bool GetSocketInfo(unsigned int hSocket, SteamID *pSteamIDRemote, int *peSocketStatus, unsigned int *punIPRemote, unsigned short *punPortRemote);
virtual bool GetListenSocketInfo(unsigned int hListenSocket, unsigned int *pnIP, unsigned short *pnPort);
virtual int GetSocketConnectionType(unsigned int hSocket);
virtual int GetMaxPacketSize(unsigned int hSocket);
};
}

View File

@ -0,0 +1,43 @@
#include "..\..\STDInclude.hpp"
namespace Steam
{
bool RemoteStorage::FileWrite(const char *pchFile, const void *pvData, int cubData)
{
return true;
}
int RemoteStorage::GetFileSize(const char *pchFile)
{
return 0;
}
int RemoteStorage::FileRead(const char *pchFile, void *pvData, int cubDataToRead)
{
OutputDebugStringA(pchFile);
return 0;
}
bool RemoteStorage::FileExists(const char *pchFile)
{
return false;
}
int RemoteStorage::GetFileCount()
{
return 0;
}
const char *RemoteStorage::GetFileNameAndSize(int iFile, int *pnFileSizeInBytes)
{
*pnFileSizeInBytes = 0;
return "";
}
bool RemoteStorage::GetQuota(int *pnTotalBytes, int *puAvailableBytes)
{
*pnTotalBytes = 0x10000000;
*puAvailableBytes = 0x10000000;
return false;
}
}

View File

@ -0,0 +1,14 @@
namespace Steam
{
class RemoteStorage
{
public:
virtual bool FileWrite(const char *pchFile, const void *pvData, int cubData);
virtual int GetFileSize(const char *pchFile);
virtual int FileRead(const char *pchFile, void *pvData, int cubDataToRead);
virtual bool FileExists(const char *pchFile);
virtual int GetFileCount();
virtual const char *GetFileNameAndSize(int iFile, int *pnFileSizeInBytes);
virtual bool GetQuota(int *pnTotalBytes, int *puAvailableBytes);
};
}

View File

@ -0,0 +1,106 @@
#include "..\..\STDInclude.hpp"
namespace Steam
{
int User::GetHSteamUser()
{
return NULL;
}
bool User::LoggedOn()
{
return true;
}
SteamID User::GetSteamID()
{
static int subId = 0;
SteamID id;
if (!subId)
{
if (Components::Dedicated::IsDedicated()) // Dedi guid
{
subId = ~0xDED1CADE;
}
else if (Components::Singleton::IsFirstInstance()) // Hardware guid
{
DATA_BLOB Data[2];
Data[0].pbData = (BYTE *)"AAAAAAAAAA";
Data[0].cbData = 10;
CryptProtectData(&Data[0], NULL, NULL, NULL, NULL, CRYPTPROTECT_LOCAL_MACHINE, &Data[1]);
subId = ::Utils::OneAtATime((char*)Data[1].pbData, 52);
}
else // Random guid
{
subId = (Game::Com_Milliseconds() + timeGetTime());
}
}
id.Bits = 0x110000100000000 | subId;
return id;
}
int User::InitiateGameConnection(void *pAuthBlob, int cbMaxAuthBlob, SteamID steamIDGameServer, unsigned int unIPServer, unsigned short usPortServer, bool bSecure)
{
// TODO: Generate auth ticket!
return 0;
}
void User::TerminateGameConnection(unsigned int unIPServer, unsigned short usPortServer)
{
}
void User::TrackAppUsageEvent(SteamID gameID, int eAppUsageEvent, const char *pchExtraInfo)
{
}
bool User::GetUserDataFolder(char *pchBuffer, int cubBuffer)
{
return false;
}
void User::StartVoiceRecording()
{
}
void User::StopVoiceRecording()
{
}
int User::GetCompressedVoice(void *pDestBuffer, unsigned int cbDestBufferSize, unsigned int *nBytesWritten)
{
return 0;
}
int User::DecompressVoice(void *pCompressed, unsigned int cbCompressed, void *pDestBuffer, unsigned int cbDestBufferSize, unsigned int *nBytesWritten)
{
return 0;
}
unsigned int User::GetAuthSessionTicket(void *pTicket, int cbMaxTicket, unsigned int *pcbTicket)
{
return 0;
}
int User::BeginAuthSession(const void *pAuthTicket, int cbAuthTicket, SteamID steamID)
{
return 0;
}
void User::EndAuthSession(SteamID steamID)
{
}
void User::CancelAuthTicket(unsigned int hAuthTicket)
{
}
unsigned int User::UserHasLicenseForApp(SteamID steamID, unsigned int appID)
{
return 1;
}
}

View File

@ -0,0 +1,24 @@
namespace Steam
{
class User
{
public:
virtual int GetHSteamUser();
virtual bool LoggedOn();
virtual SteamID GetSteamID();
virtual int InitiateGameConnection(void *pAuthBlob, int cbMaxAuthBlob, SteamID steamIDGameServer, unsigned int unIPServer, unsigned short usPortServer, bool bSecure);
virtual void TerminateGameConnection(unsigned int unIPServer, unsigned short usPortServer);
virtual void TrackAppUsageEvent(SteamID gameID, int eAppUsageEvent, const char *pchExtraInfo = "");
virtual bool GetUserDataFolder(char *pchBuffer, int cubBuffer);
virtual void StartVoiceRecording();
virtual void StopVoiceRecording();
virtual int GetCompressedVoice(void *pDestBuffer, unsigned int cbDestBufferSize, unsigned int *nBytesWritten);
virtual int DecompressVoice(void *pCompressed, unsigned int cbCompressed, void *pDestBuffer, unsigned int cbDestBufferSize, unsigned int *nBytesWritten);
virtual unsigned int GetAuthSessionTicket(void *pTicket, int cbMaxTicket, unsigned int *pcbTicket);
virtual int BeginAuthSession(const void *pAuthTicket, int cbAuthTicket, SteamID steamID);
virtual void EndAuthSession(SteamID steamID);
virtual void CancelAuthTicket(unsigned int hAuthTicket);
virtual unsigned int UserHasLicenseForApp(SteamID steamID, unsigned int appID);
};
}

View File

@ -0,0 +1,96 @@
#include "..\..\STDInclude.hpp"
namespace Steam
{
unsigned int Utils::GetSecondsSinceAppActive()
{
return 0;
}
unsigned int Utils::GetSecondsSinceComputerActive()
{
return 0;
}
int Utils::GetConnectedUniverse()
{
return 1;
}
unsigned int Utils::GetServerRealTime()
{
return 0;
}
const char* Utils::GetIPCountry()
{
return "US";
}
bool Utils::GetImageSize(int iImage, unsigned int *pnWidth, unsigned int *pnHeight)
{
return false;
}
bool Utils::GetImageRGBA(int iImage, unsigned char *pubDest, int nDestBufferSize)
{
return false;
}
bool Utils::GetCSERIPPort(unsigned int *unIP, unsigned short *usPort)
{
return false;
}
unsigned char Utils::GetCurrentBatteryPower()
{
return 255;
}
unsigned int Utils::GetAppID()
{
return 10190;
}
void Utils::SetOverlayNotificationPosition(int eNotificationPosition)
{
}
bool Utils::IsAPICallCompleted(unsigned __int64 hSteamAPICall, bool *pbFailed)
{
return false;
}
int Utils::GetAPICallFailureReason(unsigned __int64 hSteamAPICall)
{
return -1;
}
bool Utils::GetAPICallResult(unsigned __int64 hSteamAPICall, void *pCallback, int cubCallback, int iCallbackExpected, bool *pbFailed)
{
return false;
}
void Utils::RunFrame()
{
}
unsigned int Utils::GetIPCCallCount()
{
return 0;
}
void Utils::SetWarningMessageHook(void(*pFunction)(int hpipe, const char *message))
{
}
bool Utils::IsOverlayEnabled()
{
return false;
}
bool Utils::BOverlayNeedsPresent()
{
return false;
}
}

View File

@ -0,0 +1,26 @@
namespace Steam
{
class Utils
{
public:
virtual unsigned int GetSecondsSinceAppActive();
virtual unsigned int GetSecondsSinceComputerActive();
virtual int GetConnectedUniverse();
virtual unsigned int GetServerRealTime();
virtual const char *GetIPCountry();
virtual bool GetImageSize(int iImage, unsigned int *pnWidth, unsigned int *pnHeight);
virtual bool GetImageRGBA(int iImage, unsigned char *pubDest, int nDestBufferSize);
virtual bool GetCSERIPPort(unsigned int *unIP, unsigned short *usPort);
virtual unsigned char GetCurrentBatteryPower();
virtual unsigned int GetAppID();
virtual void SetOverlayNotificationPosition(int eNotificationPosition);
virtual bool IsAPICallCompleted(unsigned __int64 hSteamAPICall, bool *pbFailed);
virtual int GetAPICallFailureReason(unsigned __int64 hSteamAPICall);
virtual bool GetAPICallResult(unsigned __int64 hSteamAPICall, void *pCallback, int cubCallback, int iCallbackExpected, bool *pbFailed);
virtual void RunFrame();
virtual unsigned int GetIPCCallCount();
virtual void SetWarningMessageHook(void(*pFunction)(int hpipe, const char *message));
virtual bool IsOverlayEnabled();
virtual bool BOverlayNeedsPresent();
};
}

166
src/Steam/Steam.cpp Normal file
View File

@ -0,0 +1,166 @@
#include "..\STDInclude.hpp"
#include "Steam.hpp"
namespace Steam
{
uint64_t Callbacks::CallID = 0;
std::map<uint64_t, bool> Callbacks::Calls;
std::map<uint64_t, Callbacks::Base*> Callbacks::ResultHandlers;
std::vector<Callbacks::Result> Callbacks::Results;
std::vector<Callbacks::Base*> Callbacks::CallbackList;
uint64_t Callbacks::RegisterCall()
{
Callbacks::Calls[Callbacks::CallID] = false;
return Callbacks::CallID++;
}
void Callbacks::RegisterCallback(Callbacks::Base* handler, int callback)
{
handler->SetICallback(callback);
Callbacks::CallbackList.push_back(handler);
}
void Callbacks::RegisterCallResult(uint64_t call, Callbacks::Base* result)
{
Callbacks::ResultHandlers[call] = result;
}
void Callbacks::ReturnCall(void* data, int size, int type, uint64_t call)
{
Callbacks::Result result;
Callbacks::Calls[call] = true;
result.call = call;
result.data = data;
result.size = size;
result.type = type;
Callbacks::Results.push_back(result);
}
void Callbacks::RunCallbacks()
{
for (auto result : Callbacks::Results)
{
if (Callbacks::ResultHandlers.find(result.call) != Callbacks::ResultHandlers.end())
{
Callbacks::ResultHandlers[result.call]->Run(result.data, false, result.call);
}
for (auto callback : Callbacks::CallbackList)
{
if (callback && callback->GetICallback() == result.type)
{
callback->Run(result.data, false, 0);
}
}
if (result.data)
{
delete[] result.data;
}
}
Callbacks::Results.clear();
}
extern "C"
{
bool SteamAPI_Init()
{
return true;
}
void SteamAPI_RegisterCallResult(Callbacks::Base* result, uint64_t call)
{
Callbacks::RegisterCallResult(call, result);
}
void SteamAPI_RegisterCallback(Callbacks::Base* handler, int callback)
{
Callbacks::RegisterCallback(handler, callback);
}
void SteamAPI_RunCallbacks()
{
Callbacks::RunCallbacks();
}
void SteamAPI_Shutdown()
{
}
void SteamAPI_UnregisterCallResult()
{
}
void SteamAPI_UnregisterCallback()
{
}
bool SteamGameServer_Init()
{
return true;
}
void SteamGameServer_RunCallbacks()
{
}
void SteamGameServer_Shutdown()
{
}
Steam::Friends* SteamFriends()
{
static Steam::Friends iFriends;
return &iFriends;
}
Steam::Matchmaking* SteamMatchmaking()
{
static Steam::Matchmaking iMatchmaking;
return &iMatchmaking;
}
Steam::GameServer* SteamGameServer()
{
static Steam::GameServer iGameServer;
return &iGameServer;
}
Steam::MasterServerUpdater* SteamMasterServerUpdater()
{
static Steam::MasterServerUpdater iMasterServerUpdater;
return &iMasterServerUpdater;
}
Steam::Networking* SteamNetworking()
{
static Steam::Networking iNetworking;
return &iNetworking;
}
Steam::RemoteStorage* SteamRemoteStorage()
{
static Steam::RemoteStorage iRemoteStorage;
return &iRemoteStorage;
}
Steam::User* SteamUser()
{
static Steam::User iUser;
return &iUser;
}
Steam::Utils* SteamUtils()
{
static Steam::Utils iUtils;
return &iUtils;
}
}
}

91
src/Steam/Steam.hpp Normal file
View File

@ -0,0 +1,91 @@
#pragma once
#define STEAM_EXPORT extern "C" __declspec(dllexport)
typedef union
{
struct
{
unsigned int AccountID : 32;
unsigned int AccountInstance : 20;
unsigned int AccountType : 4;
int Universe : 8;
};
unsigned long long Bits;
} SteamID;
#include "Interfaces\SteamUser.hpp"
#include "Interfaces\SteamUtils.hpp"
#include "Interfaces\SteamFriends.hpp"
#include "Interfaces\SteamGameServer.hpp"
#include "Interfaces\SteamNetworking.hpp"
#include "Interfaces\SteamMatchmaking.hpp"
#include "Interfaces\SteamRemoteStorage.hpp"
#include "Interfaces\SteamMasterServerUpdater.hpp"
namespace Steam
{
class Callbacks
{
public:
class Base
{
public:
Base() : Flags(0), Callback(0) {};
virtual void Run(void *pvParam) = 0;
virtual void Run(void *pvParam, bool bIOFailure, uint64_t hSteamAPICall) = 0;
virtual int GetCallbackSizeBytes() = 0;
int GetICallback() { return Callback; }
void SetICallback(int iCallback) { Callback = iCallback; }
protected:
unsigned char Flags;
int Callback;
};
struct Result
{
void* data;
int size;
int type;
uint64_t call;
};
static uint64_t RegisterCall();
static void RegisterCallback(Base* handler, int callback);
static void RegisterCallResult(uint64_t call, Base* result);
static void ReturnCall(void* data, int size, int type, uint64_t call);
static void RunCallbacks();
private:
static uint64_t CallID;
static std::map<uint64_t, bool> Calls;
static std::map<uint64_t, Base*> ResultHandlers;
static std::vector<Result> Results;
static std::vector<Base*> CallbackList;
};
STEAM_EXPORT bool SteamAPI_Init();
STEAM_EXPORT void SteamAPI_RegisterCallResult(Callbacks::Base* result, uint64_t call);
STEAM_EXPORT void SteamAPI_RegisterCallback(Callbacks::Base* handler, int callback);
STEAM_EXPORT void SteamAPI_RunCallbacks();
STEAM_EXPORT void SteamAPI_Shutdown();
STEAM_EXPORT void SteamAPI_UnregisterCallResult();
STEAM_EXPORT void SteamAPI_UnregisterCallback();
STEAM_EXPORT bool SteamGameServer_Init();
STEAM_EXPORT void SteamGameServer_RunCallbacks();
STEAM_EXPORT void SteamGameServer_Shutdown();
STEAM_EXPORT Steam::Friends* SteamFriends();
STEAM_EXPORT Steam::Matchmaking* SteamMatchmaking();
STEAM_EXPORT Steam::GameServer* SteamGameServer();
STEAM_EXPORT Steam::MasterServerUpdater* SteamMasterServerUpdater();
STEAM_EXPORT Steam::Networking* SteamNetworking();
STEAM_EXPORT Steam::RemoteStorage* SteamRemoteStorage();
STEAM_EXPORT Steam::User* SteamUser();
STEAM_EXPORT Steam::Utils* SteamUtils();
}

116
src/Utils/Hooking.cpp Normal file
View File

@ -0,0 +1,116 @@
#include "..\STDInclude.hpp"
namespace Utils
{
Hook::~Hook()
{
if (Hook::Initialized)
{
Hook::Uninstall();
}
}
Hook* Hook::Initialize(DWORD place, void(*stub)(), bool useJump)
{
return Hook::Initialize(place, (void*)stub, useJump);
}
Hook* Hook::Initialize(DWORD place, void* stub, bool useJump)
{
return Hook::Initialize((void*)place, stub, useJump);
}
Hook* Hook::Initialize(void* place, void* stub, bool useJump)
{
if (Hook::Initialized) return this;
Hook::Initialized = true;
Hook::UseJump = useJump;
Hook::Place = place;
Hook::Stub = stub;
Hook::Original = (char*)Hook::Place + 5 + *(DWORD*)((DWORD)Hook::Place + 1);
return this;
}
Hook* Hook::Install()
{
Hook::StateMutex.lock();
if (!Hook::Initialized || Hook::Installed)
{
Hook::StateMutex.unlock();
return this;
}
Hook::Installed = true;
DWORD d;
VirtualProtect(Hook::Place, sizeof(Hook::Buffer), PAGE_EXECUTE_READWRITE, &d);
memcpy(Hook::Buffer, Hook::Place, sizeof(Hook::Buffer));
char* Code = (char*)Hook::Place;
*Code = (char)(Hook::UseJump ? 0xE9 : 0xE8);
*(size_t*)&Code[1] = (size_t)Hook::Stub - ((size_t)Hook::Place + 5);
VirtualProtect(Hook::Place, sizeof(Hook::Buffer), d, &d);
FlushInstructionCache(GetCurrentProcess(), Hook::Place, sizeof(Hook::Buffer));
Hook::StateMutex.unlock();
return this;
}
void Hook::Quick()
{
if (Hook::Installed)
{
Hook::Installed = false;
}
}
Hook* Hook::Uninstall()
{
Hook::StateMutex.lock();
if (!Hook::Initialized || !Hook::Installed)
{
Hook::StateMutex.unlock();
return this;
}
Hook::Installed = false;
DWORD d;
VirtualProtect(Hook::Place, sizeof(Hook::Buffer), PAGE_EXECUTE_READWRITE, &d);
memcpy(Hook::Place, Hook::Buffer, sizeof(Hook::Buffer));
VirtualProtect(Hook::Place, sizeof(Hook::Buffer), d, &d);
FlushInstructionCache(GetCurrentProcess(), Hook::Place, sizeof(Hook::Buffer));
Hook::StateMutex.unlock();
return this;
}
void* Hook::GetAddress()
{
return Hook::Place;
}
void Hook::Nop(void* place, size_t length)
{
memset(place, 0x90, length);
}
void Hook::Nop(DWORD place, size_t length)
{
Nop((void*)place, length);
}
}

104
src/Utils/Hooking.hpp Normal file
View File

@ -0,0 +1,104 @@
#pragma once
#define HOOK_JUMP true
#define HOOK_CALL false
namespace Utils
{
class Hook
{
public:
Hook() : Place(nullptr), Stub(nullptr), Initialized(false), Installed(false), UseJump(false) { ZeroMemory(Hook::Buffer, sizeof(Hook::Buffer)); }
Hook(void* place, void* stub, bool useJump = true) : Hook() { Hook::Initialize(place, stub, useJump); }
Hook(DWORD place, void* stub, bool useJump = true) : Hook((void*)place, stub, useJump) {}
~Hook();
Hook* Initialize(void* place, void* stub, bool useJump = true);
Hook* Initialize(DWORD place, void* stub, bool useJump = true);
Hook* Initialize(DWORD place, void(*stub)(), bool useJump = true); // For lambdas
Hook* Install();
Hook* Uninstall();
void* GetAddress();
void Quick();
template <typename T> static T Call(DWORD function)
{
__asm
{
mov eax, function
call eax
}
}
static void Nop(void* place, size_t length);
static void Nop(DWORD place, size_t length);
template <typename T> static void Set(void* place, T value)
{
*(T*)place = value;
FlushInstructionCache(GetCurrentProcess(), place, sizeof(T));
}
template <typename T> static void Set(DWORD place, T value)
{
return Set<T>((void*)place, value);
}
template <typename T> static void Xor(void* place, T value)
{
*(T*)place ^= value;
FlushInstructionCache(GetCurrentProcess(), place, sizeof(T));
}
template <typename T> static void Xor(DWORD place, T value)
{
return Xor<T>((void*)place, value);
}
template <typename T> static void Or(void* place, T value)
{
*(T*)place |= value;
FlushInstructionCache(GetCurrentProcess(), place, sizeof(T));
}
template <typename T> static void Or(DWORD place, T value)
{
return Or<T>((void*)place, value);
}
template <typename T> static void And(void* place, T value)
{
*(T*)place &= value;
FlushInstructionCache(GetCurrentProcess(), place, sizeof(T));
}
template <typename T> static void And(DWORD place, T value)
{
return And<T>((void*)place, value);
}
template <typename T> static T Get(void* place)
{
return *(T*)place;
}
template <typename T> static T Get(DWORD place)
{
return Get<T>((void*)place);
}
private:
bool Initialized;
bool Installed;
void* Place;
void* Stub;
void* Original;
char Buffer[5];
bool UseJump;
std::mutex StateMutex;
};
}

137
src/Utils/Utils.cpp Normal file
View File

@ -0,0 +1,137 @@
#include "..\STDInclude.hpp"
#define VA_BUFFER_COUNT 4
#define VA_BUFFER_SIZE 4096
namespace Utils
{
const char *VA(const char *fmt, ...)
{
static char g_vaBuffer[VA_BUFFER_COUNT][VA_BUFFER_SIZE];
static int g_vaNextBufferIndex = 0;
va_list ap;
va_start(ap, fmt);
char* dest = g_vaBuffer[g_vaNextBufferIndex];
vsprintf_s(g_vaBuffer[g_vaNextBufferIndex], fmt, ap);
g_vaNextBufferIndex = (g_vaNextBufferIndex + 1) % VA_BUFFER_COUNT;
va_end(ap);
return dest;
}
std::string StrToLower(std::string input)
{
std::transform(input.begin(), input.end(), input.begin(), ::tolower);
return input;
}
bool EndsWith(const char* heystack, const char* needle)
{
return (strstr(heystack, needle) == (heystack + strlen(heystack) - strlen(needle)));
}
std::vector<std::string> Explode(const std::string& str, char delim)
{
std::vector<std::string> result;
std::istringstream iss(str);
for (std::string token; std::getline(iss, token, delim);)
{
std::string _entry = std::move(token);
// Remove trailing 0x0 bytes
while (_entry.size() && !_entry[_entry.size() - 1])
{
_entry = _entry.substr(0, _entry.size() - 1);
}
result.push_back(_entry);
}
return result;
}
void Replace(std::string &string, std::string find, std::string replace)
{
size_t nPos = 0;
while ((nPos = string.find(find, nPos)) != std::string::npos)
{
string = string.replace(nPos, find.length(), replace);
nPos += replace.length();
}
}
unsigned int OneAtATime(char *key, size_t len)
{
unsigned int hash, i;
for (hash = i = 0; i < len; ++i)
{
hash += key[i];
hash += (hash << 10);
hash ^= (hash >> 6);
}
hash += (hash << 3);
hash ^= (hash >> 11);
hash += (hash << 15);
return hash;
}
// Infostring class
void InfoString::Set(std::string key, std::string value)
{
this->KeyValuePairs[key] = value;
}
std::string InfoString::Get(std::string key)
{
if (this->KeyValuePairs.find(key) != this->KeyValuePairs.end())
{
return this->KeyValuePairs[key];
}
return "";
}
std::string InfoString::Build()
{
std::string infoString;
bool first = true;
for (auto i = this->KeyValuePairs.begin(); i != this->KeyValuePairs.end(); i++)
{
if (first) first = false;
else infoString.append("\\");
infoString.append(i->first); // Key
infoString.append("\\");
infoString.append(i->second); // Value
}
return infoString;
}
void InfoString::Dump()
{
for (auto i = this->KeyValuePairs.begin(); i != this->KeyValuePairs.end(); i++)
{
OutputDebugStringA(Utils::VA("%s: %s", i->first.data(), i->second.data()));
}
}
void InfoString::Parse(std::string buffer)
{
if (buffer[0] == '\\')
{
buffer = buffer.substr(1);
}
std::vector<std::string> KeyValues = Utils::Explode(buffer, '\\');
for (unsigned int i = 0; i < (KeyValues.size() - 1); i+=2)
{
this->KeyValuePairs[KeyValues[i]] = KeyValues[i + 1];
}
}
}

28
src/Utils/Utils.hpp Normal file
View File

@ -0,0 +1,28 @@
namespace Utils
{
const char *VA(const char *fmt, ...);
std::string StrToLower(std::string input);
bool EndsWith(const char* heystack, const char* needle);
std::vector<std::string> Explode(const std::string& str, char delim);
void Replace(std::string &string, std::string find, std::string replace);
unsigned int OneAtATime(char *key, size_t len);
class InfoString
{
public:
InfoString() {};
InfoString(std::string buffer) :InfoString() { this->Parse(buffer); };
InfoString(const InfoString &obj) { this->KeyValuePairs = obj.KeyValuePairs; };
void Set(std::string key, std::string value);
std::string Get(std::string key);
std::string Build();
void Dump();
private:
std::map<std::string, std::string> KeyValuePairs;
void Parse(std::string buffer);
};
}