Merge branch 'v2features' into 'develop'

V2features
This commit is contained in:
momo5502 2017-05-31 12:09:19 +02:00
commit c0575fdc50
74 changed files with 646 additions and 302 deletions

View File

@ -64,6 +64,7 @@ namespace Components
Loader::Register(new Monitor());
Loader::Register(new Network());
Loader::Register(new Theatre());
Loader::Register(new Clantags());
Loader::Register(new Download());
Loader::Register(new Playlist());
Loader::Register(new RawFiles());
@ -81,6 +82,7 @@ namespace Components
Loader::Register(new Gametypes());
Loader::Register(new Materials());
Loader::Register(new Threading());
Loader::Register(new CardTitles());
Loader::Register(new FileSystem());
Loader::Register(new ModelSurfs());
Loader::Register(new PlayerName());
@ -94,6 +96,7 @@ namespace Components
Loader::Register(new AssetHandler());
Loader::Register(new Localization());
Loader::Register(new MusicalTalent());
Loader::Register(new ServerCommands());
Loader::Register(new StructuredData());
Loader::Register(new ConnectProtocol());
Loader::Register(new StartupMessages());
@ -111,7 +114,7 @@ namespace Components
#ifdef DEBUG
if(!Loader::PerformingUnitTests())
{
Logger::Print("Unregistering component: %s\n", component->getName());
Logger::Print("Unregistering component: %s\n", component->getName().data());
}
#endif
delete component;
@ -164,7 +167,7 @@ namespace Components
for (auto component : Loader::Components)
{
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
Logger::Print("Testing '%s'...\n", component->getName());
Logger::Print("Testing '%s'...\n", component->getName().data());
#endif
auto startTime = std::chrono::high_resolution_clock::now();
bool testRes = component->unitTest();
@ -192,7 +195,7 @@ namespace Components
#ifdef DEBUG
if(!Loader::PerformingUnitTests())
{
Logger::Print("Component registered: %s\n", component->getName());
Logger::Print("Component registered: %s\n", component->getName().data());
}
#endif
Loader::Components.push_back(component);

View File

@ -9,7 +9,12 @@ namespace Components
virtual ~Component() {};
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
virtual const char* getName() { return "Unknown"; };
virtual std::string getName()
{
std::string name = typeid(*this).name();
Utils::String::Replace(name, "class Components::", "");
return name;
};
#endif
// It's illegal to spawn threads in DLLMain, and apparently it causes problems if they are destroyed there as well.
@ -34,6 +39,20 @@ namespace Components
static bool IsPostgame();
static bool IsComInitialized();
template <typename T>
static T* GetInstance()
{
for (auto& component : Loader::Components)
{
if (typeid(*component) == typeid(T))
{
return reinterpret_cast<T*>(component);
}
}
return nullptr;
}
static Utils::Memory::Allocator* GetAlloctor();
private:
@ -75,6 +94,7 @@ namespace Components
#include "Modules/Logger.hpp"
#include "Modules/Friends.hpp"
#include "Modules/IPCPipe.hpp"
#include "Modules/Clantags.hpp"
#include "Modules/Download.hpp"
#include "Modules/Playlist.hpp"
#include "Modules/RawFiles.hpp"
@ -91,6 +111,7 @@ namespace Components
#include "Modules/Materials.hpp"
#include "Modules/Singleton.hpp"
#include "Modules/Threading.hpp"
#include "Modules/CardTitles.hpp"
#include "Modules/FileSystem.hpp"
#include "Modules/ModelSurfs.hpp"
#include "Modules/PlayerName.hpp"
@ -103,6 +124,7 @@ namespace Components
#include "Modules/AssetHandler.hpp"
#include "Modules/Localization.hpp"
#include "Modules/MusicalTalent.hpp"
#include "Modules/ServerCommands.hpp"
#include "Modules/StructuredData.hpp"
#include "Modules/ConnectProtocol.hpp"
#include "Modules/StartupMessages.hpp"

View File

@ -16,10 +16,6 @@ namespace Components
AntiCheat();
~AntiCheat();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "AntiCheat"; };
#endif
static void CrashClient();
static void InitLoadLibHook();

View File

@ -7,10 +7,6 @@ namespace Components
public:
ArenaLength();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "ArenaLength"; };
#endif
static Game::newMapArena_t NewArenas[128];
private:

View File

@ -22,10 +22,6 @@ namespace Components
AssetHandler();
~AssetHandler();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "AssetHandler"; };
#endif
static void OnFind(Game::XAssetType type, Utils::Slot<Callback> callback);
static void OnLoad(Utils::Slot<RestrictCallback> callback);

View File

@ -8,10 +8,6 @@ namespace Components
Auth();
~Auth();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "Auth"; };
#endif
void preDestroy() override;
bool unitTest() override;

View File

@ -10,10 +10,6 @@ namespace Components
Bans();
~Bans();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "Bans"; };
#endif
static void BanClientNum(int num, std::string reason);
static bool IsBanned(Entry entry);

View File

@ -8,10 +8,6 @@ namespace Components
Bots();
~Bots();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "Bots"; };
#endif
private:
static std::vector<std::string> BotNames;

View File

@ -0,0 +1,230 @@
#include "STDInclude.hpp"
namespace Components
{
std::string CardTitles::CustomTitles[18];
Dvar::Var CardTitles::CustomTitleDvar;
CClient* CardTitles::GetClientByIndex(std::uint32_t index)
{
return &reinterpret_cast<CClient*>(0x8E77B0)[index];
}
std::int32_t CardTitles::GetPlayerCardClientInfo(std::int32_t lookupResult, playercarddata_s* data)
{
std::int32_t returnResult = lookupResult;
std::string username = Dvar::Var("name").get<std::string>();
if (data->name == username)
{
returnResult += 0xFE000000;
}
else
{
for (auto clientNum = 0; clientNum < 18; clientNum++)
{
CClient* c = GetClientByIndex(clientNum);
if (c != nullptr)
{
if (!strcmp(data->name, c->Name))
{
// Since a 4 byte integer is overkill for a row num: We can use it to store the customprefix + clientNum and use a 2 byte integer for the row number
returnResult += 0xFF000000;
returnResult += clientNum * 0x10000;
break;
}
}
}
}
return returnResult;
}
void __declspec(naked) CardTitles::GetPlayerCardClientInfoStub()
{
__asm
{
push eax
pushad
push esi
push eax
call GetPlayerCardClientInfo
add esp, 8
mov [esp + 20h], eax
popad
pop eax
pop esi
pop ebp
mov[ebx + 4], eax
pop ebx
push 62EB2Ch
retn
}
}
const char* CardTitles::TableLookupByRowHook(Game::Operand* operand, tablelookuprequest_s* request)
{
std::uint8_t prefix = (request->tableRow >> (8 * 3)) & 0xFF;
std::uint8_t data = (request->tableRow >> (8 * 2)) & 0xFF;
if (request->tablename == "mp/cardTitleTable.csv"s)
{
if (prefix != 0x00)
{
// Column 1 = CardTitle
if (request->tableColumn == 1)
{
if (prefix == 0xFE)
{
if (!CustomTitleDvar.get<std::string>().empty())
{
// 0xFF in front of the title to skip localization. Or else it will wait for a couple of seconds for the asset of type localize
const char* title = Utils::String::VA("\x15%s", CustomTitleDvar.get<const char*>());
// prepare return value
operand->internals.stringVal.string = title;
operand->dataType = Game::VAL_STRING;
return title;
}
}
else if (prefix == 0xFF)
{
if (!CustomTitles[data].empty())
{
const char* title = Utils::String::VA("\x15%s", CustomTitles[data].data());
// prepare return value
operand->internals.stringVal.string = title;
operand->dataType = Game::VAL_STRING;
return title;
}
}
}
// If the title was changed it already returned at this point so...
// Remove prefix and data to make being readable to the normal lookuprequest
request->tableRow = static_cast<std::int32_t>(*(reinterpret_cast<WORD*>(&request->tableRow)));
}
}
return nullptr;
}
__declspec(naked) void CardTitles::TableLookupByRowHookStub()
{
__asm
{
push eax
pushad
push esi
push ebx
call TableLookupByRowHook
add esp, 8
mov [esp + 20h], eax
popad
pop eax
cmp eax, 0
jz OriginalTitle
pop ecx
mov ecx, DWORD ptr[esi + 4]
retn
OriginalTitle:
mov eax, [esi + 50h]
cmp eax, 3
push 62DCC7h
retn
}
}
void CardTitles::SendCustomTitlesToClients()
{
std::string list;
for (int i = 0; i < 18; i++)
{
char playerTitle[18];
if (Game::svs_clients[i].state >= 3)
{
strncpy_s(playerTitle, Game::Info_ValueForKey(Game::svs_clients[i].connectInfoString, "customTitle"), 17);
}
else
{
memset(playerTitle, 0, 18);
}
list.append(Utils::String::VA("\\%s\\%s", std::to_string(i).c_str(), playerTitle));
}
std::string command = Utils::String::VA("%c customTitles \"%s\"", 21, list.data());
Game::SV_GameSendServerCommand(-1, 0, command.data());
}
void CardTitles::ParseCustomTitles(const char* msg)
{
for (int i = 0; i < 18; ++i)
{
const char* playerTitle = Game::Info_ValueForKey(msg, std::to_string(i).c_str());
if (playerTitle) CardTitles::CustomTitles[i] = playerTitle;
else CardTitles::CustomTitles[i].clear();
}
}
CardTitles::CardTitles()
{
Dvar::OnInit([]()
{
CardTitles::CustomTitleDvar = Dvar::Register<const char*>("customtitle", "", Game::dvar_flag::DVAR_FLAG_USERINFO | Game::dvar_flag::DVAR_FLAG_SAVED, "Custom card title");
});
ServerCommands::OnCommand(21, [](Command::Params* params)
{
if (params->get(1) == "customTitles"s && !Dedicated::IsEnabled())
{
if (params->length() == 3)
{
CardTitles::ParseCustomTitles(params->get(2));
return true;
}
}
return false;
});
for(int i = 0; i < ARRAYSIZE(CardTitles::CustomTitles); ++i)
{
CardTitles::CustomTitles[i].clear();
}
Utils::Hook(0x62EB26, CardTitles::GetPlayerCardClientInfoStub).install()->quick();
// Table lookup stuff
Utils::Hook(0x62DCC1, CardTitles::TableLookupByRowHookStub).install()->quick();
Utils::Hook::Nop(0x62DCC6, 1);
}
CardTitles::~CardTitles()
{
for (int i = 0; i < ARRAYSIZE(CardTitles::CustomTitles); ++i)
{
CardTitles::CustomTitles[i].clear();
}
}
}

View File

@ -0,0 +1,74 @@
#pragma once
namespace Components
{
struct tablelookuprequest_s
{
std::uint8_t padding[4];
char* tablename;
std::uint8_t padding2[4];
std::int32_t tableRow;
std::uint8_t padding3[4];
std::int32_t tableColumn;
};
struct playercarddata_s
{
std::uint32_t padding;
std::uint32_t playercardNumber;
std::uint32_t unknown;
std::uint32_t unknown2;
std::uint32_t level; //Level is counted from 0 -> Value 69 is Level 70
std::uint32_t prestige;
std::uint32_t padding2;
char name[40];
};
struct CClient
{
std::uint32_t IsValid; // 0x0000
std::uint32_t IsValid2; // 0x0004
std::uint32_t ClientNumber; // 0x0008
char Name[16]; // 0x000C
std::uint32_t Team; // 0x001C
std::uint32_t Team2; // 0x0020
std::uint32_t Rank; // 0x0024 (rank - 1)
std::uint32_t Prestige; // 0x0028
std::uint32_t Perks; // 0x002C
std::uint32_t Kills; // 0x0030
std::uint32_t Score; // 0x0034
std::uint8_t _0x0038[968];
std::uint32_t ViewAngles; // 0x0400
std::uint8_t _0x040C[136];
std::uint32_t IsShooting; // 0x0494
std::uint8_t _0x0498[4];
std::uint32_t IsZoomed; // 0x049C
std::uint8_t _0x04A0[68];
std::uint32_t weaponID; // 0x04E4
std::uint8_t _0x04E8[24];
std::uint32_t weaponID2; // 0x0500
std::uint8_t _0x0504[40];
std::uint8_t _padding[8];
};
class CardTitles : public Component
{
public:
static Dvar::Var CustomTitleDvar;
static std::string CustomTitles[18];
static void SendCustomTitlesToClients();
static void ParseCustomTitles(const char * msg);
CardTitles();
~CardTitles();
private:
static CClient * GetClientByIndex(std::uint32_t index);
static std::int32_t GetPlayerCardClientInfo(std::int32_t lookupResult, playercarddata_s * data);
static void GetPlayerCardClientInfoStub();
static const char* TableLookupByRowHook(Game::Operand * operand, tablelookuprequest_s * request);
static void TableLookupByRowHookStub();
};
}

View File

@ -8,10 +8,6 @@ namespace Components
Changelog();
~Changelog();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "Changelog"; };
#endif
static void LoadChangelog();
private:

View File

@ -0,0 +1,107 @@
#include "STDInclude.hpp"
namespace Components
{
std::string Clantags::Tags[18];
void Clantags::ParseClantags(const char* infoString)
{
for (int i = 0; i < 18; i++)
{
const char* clantag = Game::Info_ValueForKey(infoString, std::to_string(i).data());
if (clantag) Clantags::Tags[i] = clantag;
else Clantags::Tags[i].clear();
}
}
void Clantags::SendClantagsToClients()
{
std::string list;
for (int i = 0; i < 18; ++i)
{
char clantag[5] = { 0 };
if (Game::svs_clients[i].state >= 3)
{
strncpy_s(clantag, Game::Info_ValueForKey(Game::svs_clients[i].connectInfoString, "iw4x_clantag"), 4);
}
list.append(Utils::String::VA("\\%s\\%s", std::to_string(i).data(), clantag));
}
std::string command = Utils::String::VA("%c clantags \"%s\"", 22, list.data());
Game::SV_GameSendServerCommand(-1, 0, command.data());
}
const char* Clantags::GetUserClantag(std::uint32_t clientnum, const char* playername)
{
if (Clantags::Tags[clientnum].empty()) return playername;
return Utils::String::VA("[%s] %s", Clantags::Tags[clientnum].data(), playername);
}
__declspec(naked) void Clantags::DrawPlayerNameOnScoreboard()
{
__asm
{
push eax
pushad
push edi
push [ebp]
call Clantags::GetUserClantag
add esp, 8
mov [esp + 20h], eax
popad
pop edi
push 591247h // Return address
push 5909E0h // Draw string func
retn
}
}
Clantags::Clantags()
{
// Create clantag dvar
Dvar::OnInit([]()
{
Dvar::Register<const char*>("iw4x_clantag", "", Game::dvar_flag::DVAR_FLAG_USERINFO | Game::dvar_flag::DVAR_FLAG_SAVED, "If set, your clantag will be shown on the scoreboard.");
});
// Servercommand hook
ServerCommands::OnCommand(22, [](Command::Params* params)
{
if (params->get(1) == "clantags"s && !Dedicated::IsEnabled())
{
if (params->length() == 3)
{
Clantags::ParseClantags(params->get(2));
return true;
}
}
return false;
});
for (int i = 0; i < ARRAYSIZE(Clantags::Tags); ++i)
{
Clantags::Tags[i].clear();
}
// Draw clantag before playername
Utils::Hook(0x591242, Clantags::DrawPlayerNameOnScoreboard).install()->quick();
}
Clantags::~Clantags()
{
for (int i = 0; i < ARRAYSIZE(Clantags::Tags); ++i)
{
Clantags::Tags[i].clear();
}
}
}

View File

@ -0,0 +1,21 @@
#pragma once
namespace Components
{
class Clantags : public Component
{
public:
static void ParseClantags(const char * infoString);
static void SendClantagsToClients();
Clantags();
~Clantags();
private:
static std::string Clantags::Tags[18];
static const char* GetUserClantag(std::uint32_t clientnum, const char * playername);
static void DrawPlayerNameOnScoreboard();
};
}

View File

@ -8,10 +8,6 @@ namespace Components
Colors();
~Colors();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "Colors"; };
#endif
static void Strip(const char* in, char* out, int max);
static std::string Strip(std::string in);

View File

@ -50,10 +50,6 @@ namespace Components
Command();
~Command();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "Command"; };
#endif
static Game::cmd_function_t* Allocate();
static void Add(const char* name, Utils::Slot<Callback> callback);

View File

@ -7,10 +7,6 @@ namespace Components
public:
ConnectProtocol();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "ConnectProtocol"; };
#endif
static bool IsEvaluated();
static bool Used();

View File

@ -11,10 +11,6 @@ namespace Components
Console();
~Console();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "Console"; };
#endif
static void SetSkipShutdown();
static void FreeNativeConsole();

View File

@ -7,10 +7,6 @@ namespace Components
public:
D3D9Ex();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "D3D9Ex"; };
#endif
private:
class D3D9Device : public IDirect3DDevice9

View File

@ -185,56 +185,6 @@ namespace Components
Game::Com_Error(code, message);
}
__declspec(naked) void Dedicated::OnServerCommandStub()
{
__asm
{
push eax
pushad
call Dedicated::OnServerCommand
mov [esp + 20h], eax
popad
pop eax
test al, al
jnz returnSafe
push 5944AEh
retn
returnSafe:
push 594536h
retn
}
}
int Dedicated::OnServerCommand()
{
Command::ClientParams params;
ZeroMemory(Dedicated::PlayerGuids, sizeof(Dedicated::PlayerGuids));
if (params.length() >= (18 * 2 + 1) && params.get(0)[0] == 20)
{
for (int client = 0; client < 18; client++)
{
Dedicated::PlayerGuids[client][0].bits = strtoull(params.get(2 * client + 1), nullptr, 16);
Dedicated::PlayerGuids[client][1].bits = strtoull(params.get(2 * client + 2), nullptr, 16);
if(Steam::Proxy::SteamFriends && Dedicated::PlayerGuids[client][1].bits != 0)
{
Steam::Proxy::SteamFriends->SetPlayedWith(Dedicated::PlayerGuids[client][1]);
}
}
return 1;
}
return 0;
}
void Dedicated::MapRotate()
{
if (!Dedicated::IsEnabled() && Dvar::Var("sv_dontrotate").get<bool>())
@ -452,6 +402,20 @@ namespace Components
// Post initialization point
Utils::Hook(0x60BFBF, Dedicated::PostInitializationStub, HOOK_JUMP).install()->quick();
// Transmit custom data
Dedicated::OnFrame([]()
{
static std::uint64_t LastUpdate = 0;
if ((GetTickCount64() - LastUpdate) > 10000)
{
CardTitles::SendCustomTitlesToClients();
Clantags::SendClantagsToClients();
LastUpdate = GetTickCount64();
}
});
#ifdef USE_LEGACY_SERVER_LIST
// Heartbeats
@ -565,7 +529,21 @@ namespace Components
}
// Intercept server commands
Utils::Hook(0x59449F, Dedicated::OnServerCommandStub, HOOK_JUMP).install()->quick();
ServerCommands::OnCommand(20, [](Command::Params* params)
{
for (int client = 0; client < 18; client++)
{
Dedicated::PlayerGuids[client][0].bits = strtoull(params->get(2 * client + 1), nullptr, 16);
Dedicated::PlayerGuids[client][1].bits = strtoull(params->get(2 * client + 2), nullptr, 16);
if (Steam::Proxy::SteamFriends && Dedicated::PlayerGuids[client][1].bits != 0)
{
Steam::Proxy::SteamFriends->SetPlayedWith(Dedicated::PlayerGuids[client][1]);
}
}
return true;
});
}
QuickPatch::OnFrame([]()

View File

@ -10,10 +10,6 @@ namespace Components
Dedicated();
~Dedicated();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "Dedicated"; };
#endif
static SteamID PlayerGuids[18][2];
static bool IsEnabled();
@ -29,9 +25,6 @@ namespace Components
static bool SendChat;
static void OnServerCommandStub();
static int OnServerCommand();
static void MapRotate();
static void FrameHandler();
static void FrameStub();

View File

@ -8,10 +8,6 @@ namespace Components
Discovery();
~Discovery();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "Discovery"; };
#endif
void preDestroy() override;
static void Perform();

View File

@ -9,10 +9,6 @@ namespace Components
Download();
~Download();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "Download"; };
#endif
void preDestroy() override;
static void InitiateClientDownload(std::string mod, bool map = false);

View File

@ -44,10 +44,6 @@ namespace Components
Dvar();
~Dvar();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "Dvar"; };
#endif
static void OnInit(Utils::Slot<Callback> callback);
// Only strings and bools use this type of declaration

View File

@ -8,9 +8,6 @@ namespace Components
Exception();
~Exception();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "Exception"; };
#endif
static LPTOP_LEVEL_EXCEPTION_FILTER Hook();
static void SetMiniDumpType(bool codeseg, bool dataseg);

View File

@ -8,10 +8,6 @@ namespace Components
FastFiles();
~FastFiles();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "FastFiles"; };
#endif
static void AddZonePath(std::string path);
static std::string Current();
static bool Ready();

View File

@ -88,10 +88,6 @@ namespace Components
FileSystem();
~FileSystem();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "FileSystem"; };
#endif
static std::vector<std::string> GetFileList(std::string path, std::string extension);
static std::vector<std::string> GetSysFileList(std::string path, std::string extension, bool folders = false);
static void DeleteFile(std::string folder, std::string file);

View File

@ -8,10 +8,6 @@ namespace Components
Flags();
~Flags();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "Flags"; };
#endif
static bool HasFlag(std::string flag);
private:

View File

@ -7,10 +7,6 @@ namespace Components
public:
FrameTime();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "FrameTime"; };
#endif
private:
static void SVFrameWaitStub();
static void SVFrameWaitFunc();

View File

@ -8,10 +8,6 @@ namespace Components
Friends();
~Friends();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "Friends"; };
#endif
static void UpdateFriends();
static void UpdateRank();
static void UpdateServer(Network::Address server, std::string hostname, std::string mapname);

View File

@ -7,10 +7,6 @@ namespace Components
public:
Gametypes();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "Gametypes"; };
#endif
private:
static unsigned int GetGametypeCount();
static const char* GetGametypeText(unsigned int index, int column);

View File

@ -65,10 +65,6 @@ namespace Components
public:
IPCPipe();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "IPCPipe"; };
#endif
void preDestroy() override;
static bool Write(std::string command, std::string data);

View File

@ -10,10 +10,6 @@ namespace Components
public:
Lean();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "Lean"; };
#endif
private:
static Game::kbutton_t in_leanleft;
static Game::kbutton_t in_leanright;

View File

@ -8,10 +8,6 @@ namespace Components
Localization();
~Localization();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "Localization"; };
#endif
static void Set(std::string key, std::string value);
static const char* Get(const char* key);

View File

@ -8,10 +8,6 @@ namespace Components
Logger();
~Logger();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "Logger"; };
#endif
static void MessagePrint(int channel, std::string message);
static void Print(int channel, const char* message, ...);
static void Print(const char* message, ...);

View File

@ -49,10 +49,6 @@ namespace Components
Maps();
~Maps();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "Maps"; };
#endif
static void HandleAsSPMap();
static void AddDependency(std::string expression, std::string zone);

View File

@ -8,10 +8,6 @@ namespace Components
Materials();
~Materials();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "Materials"; };
#endif
static int FormatImagePath(char* buffer, size_t size, int, int, const char* image);
private:

View File

@ -11,10 +11,6 @@ namespace Components
Menus();
~Menus();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "Menus"; };
#endif
static void FreeEverything();
static void Add(std::string menu);

View File

@ -8,10 +8,6 @@ namespace Components
ModList();
~ModList();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "ModList"; };
#endif
static void RunMod(std::string mod);
private:

View File

@ -8,10 +8,6 @@ namespace Components
ModelSurfs();
~ModelSurfs();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "ModelSurfs"; };
#endif
private:
static std::unordered_map<void*, IUnknown*> BufferMap;
static std::unordered_map<std::string, Game::CModelAllocData*> AllocMap;

View File

@ -7,10 +7,6 @@ namespace Components
public:
Monitor();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "Monitor"; };
#endif
static bool IsEnabled();
private:

View File

@ -8,10 +8,6 @@ namespace Components
MusicalTalent();
~MusicalTalent();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "MusicalTalent"; };
#endif
static void Replace(std::string sound, const char* file);
private:

View File

@ -58,10 +58,6 @@ namespace Components
Network();
~Network();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "Network"; };
#endif
static void Handle(std::string packet, Utils::Slot<Callback> callback);
static void OnStart(Utils::Slot<CallbackRaw> callback);

View File

@ -8,10 +8,6 @@ namespace Components
News();
~News();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "News"; };
#endif
void preDestroy() override;
bool unitTest() override;

View File

@ -21,10 +21,6 @@ namespace Components
Node();
~Node();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "Node"; };
#endif
bool unitTest() override;
static void SyncNodeList();

View File

@ -8,10 +8,6 @@ namespace Components
Party();
~Party();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "Party"; };
#endif
static Network::Address Target();
static void Connect(Network::Address target);
static const char* GetLobbyInfo(SteamID lobby, std::string key);

View File

@ -8,10 +8,6 @@ namespace Components
PlayerName();
~PlayerName();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "PlayerName"; };
#endif
private:
static std::string PlayerNames[18];

View File

@ -10,10 +10,6 @@ namespace Components
Playlist();
~Playlist();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "Playlist"; };
#endif
static void LoadPlaylist();
static std::string ReceivedPlaylistBuffer;

View File

@ -10,10 +10,6 @@ namespace Components
QuickPatch();
~QuickPatch();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "QuickPatch"; };
#endif
bool unitTest() override;
static void UnlockStats();

View File

@ -8,10 +8,6 @@ namespace Components
RCon();
~RCon();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "RCon"; };
#endif
private:
class Container
{

View File

@ -7,10 +7,6 @@ namespace Components
public:
RawFiles();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "RawFiles"; };
#endif
static void* RawFiles::LoadModdableRawfileFunc(const char* filename);
};
}

View File

@ -11,10 +11,6 @@ namespace Components
Renderer();
~Renderer();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "Renderer"; };
#endif
static int Width();
static int Height();

View File

@ -26,10 +26,6 @@ namespace Components
Script();
~Script();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "Script"; };
#endif
static int LoadScriptAndLabel(std::string script, std::string label);
static void AddFunction(std::string name, Game::scr_function_t function, bool isDev = false);

View File

@ -0,0 +1,106 @@
#include "STDInclude.hpp"
namespace Components
{
std::unordered_map<std::int32_t, std::function<bool(Command::Params*)>> ServerCommands::Commands;
std::uint32_t ServerCommands::LastServerCommand;
void ServerCommands::OnCommand(std::int32_t cmd, std::function<bool(Command::Params*)> cb)
{
ServerCommands::Commands[cmd] = cb;
}
bool ServerCommands::OnServerCommand()
{
Command::ClientParams params(*Game::cmd_id);
for (auto &serverCommandCB : ServerCommands::Commands)
{
if (params.length() >= 1)
{
if (params.get(0)[0] == serverCommandCB.first)
{
return serverCommandCB.second(&params);
}
}
}
return false;
}
__declspec(naked) void ServerCommands::OnServerCommandStub()
{
__asm
{
push eax
pushad
call ServerCommands::OnServerCommand
mov [esp + 20h], eax
popad
pop eax
test al, al
jnz jumpback
push 5944AEh
retn
jumpback:
push 594536h
retn
}
}
__declspec(naked) void ServerCommands::OnServerCommandPreFailStub()
{
__asm
{
mov ServerCommands::LastServerCommand, ecx
cmp ecx, 79h
jl above
push 59449Fh
retn
above:
push 593C28h
retn
}
}
void ServerCommands::OnServerCommandFailPrint(int type, const char *, ...)
{
Command::ClientParams params(*Game::cmd_id);
Game::Com_Printf(type, "Unknown client game command: %i %s\n", LastServerCommand, params.join(1));
}
__declspec(naked) void ServerCommands::OnServerCommandFailPrintStub()
{
__asm
{
pushad
call ServerCommands::OnServerCommandFailPrint
popad
push 5944C0h
retn
}
}
ServerCommands::ServerCommands()
{
// Server command receive hook
Utils::Hook(0x59449F, ServerCommands::OnServerCommandStub).install()->quick();
// Server command fail hooks
Utils::Hook(0x593C1F, ServerCommands::OnServerCommandPreFailStub).install()->quick();
Utils::Hook(0x5944BB, ServerCommands::OnServerCommandFailPrintStub).install()->quick();
Utils::Hook::Set<std::uint8_t>(0x5944D3, 0xEB);
}
ServerCommands::~ServerCommands()
{
ServerCommands::Commands.clear();
}
}

View File

@ -0,0 +1,23 @@
#pragma once
namespace Components
{
class ServerCommands : public Component
{
public:
ServerCommands();
~ServerCommands();
static void OnCommand(std::int32_t cmd, std::function<bool(Command::Params*)> cb);
private:
static std::unordered_map<std::int32_t, std::function<bool(Command::Params*)>> Commands;
static std::uint32_t LastServerCommand;
static bool OnServerCommand();
static void OnServerCommandStub();
static void OnServerCommandPreFailStub();
static void OnServerCommandFailPrint(int type, const char * trash, ...);
static void OnServerCommandFailPrintStub();
};
}

View File

@ -8,10 +8,6 @@ namespace Components
ServerInfo();
~ServerInfo();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "ServerInfo"; };
#endif
static Utils::InfoString GetInfo();
private:

View File

@ -32,10 +32,6 @@ namespace Components
ServerList();
~ServerList();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "ServerList"; };
#endif
static void Refresh(UIScript::Token);
static void RefreshVisibleList(UIScript::Token);
static void UpdateVisibleList(UIScript::Token);

View File

@ -7,10 +7,6 @@ namespace Components
public:
Singleton();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "Singleton"; };
#endif
static bool IsFirstInstance();
private:

View File

@ -10,10 +10,6 @@ namespace Components
public:
SlowMotion();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "SlowMotion"; };
#endif
private:
static int Delay;

View File

@ -7,10 +7,6 @@ namespace Components
public:
StartupMessages();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "StartupMessages"; };
#endif
static void AddMessage(std::string message);
private:

View File

@ -8,10 +8,6 @@ namespace Components
Stats();
~Stats();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "Stats"; };
#endif
static bool IsMaxLevel();
private:

View File

@ -8,10 +8,6 @@ namespace Components
StringTable();
~StringTable();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "StringTable"; };
#endif
private:
static std::unordered_map<std::string, Game::StringTable*> StringTableMap;

View File

@ -26,10 +26,6 @@ namespace Components
StructuredData();
~StructuredData();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "StructuredData"; };
#endif
private:
static bool UpdateVersionOffsets(Game::StructuredDataDefSet *set, Game::StructuredDataBuffer *buffer, Game::StructuredDataDef *oldDef);

View File

@ -7,10 +7,6 @@ namespace Components
public:
Theatre();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "Theatre"; };
#endif
static void StopRecording();
private:

View File

@ -7,10 +7,6 @@ namespace Components
public:
Threading();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "Threading"; };
#endif
private:
static void FrameEpilogueStub();
static void PacketEventStub();

View File

@ -11,10 +11,6 @@ namespace Components
typedef WinToastLib::WinToastTemplate Template;
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "Toast"; };
#endif
static void Show(std::string image, std::string title, std::string description, int length);
static bool ShowNative(const WinToastLib::WinToastTemplate& toast);

View File

@ -19,10 +19,6 @@ namespace Components
UIFeeder();
~UIFeeder();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "UIFeeder"; };
#endif
static void Add(float feeder, GetItemCount_t itemCountCb, GetItemText_t itemTextCb, Select_t selectCb);
private:

View File

@ -8,10 +8,6 @@ namespace Components
UIScript();
~UIScript();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "UIScript"; };
#endif
class Token
{
public:

View File

@ -420,6 +420,22 @@ namespace Components
Utils::Hook::Set<DWORD>(0x4F7630, 0x12DC + (sizeof(bg_sharedAmmoCaps) - (1200 * 4)));
}
void* Weapon::LoadNoneWeaponHook()
{
// load anim scripts now, rather than a bit later on
Utils::Hook::Call<void()>(0x4E46A0)();
return Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_WEAPON, "none").data;
}
void __declspec(naked) Weapon::LoadNoneWeaponHookStub()
{
__asm
{
jmp LoadNoneWeaponHook
}
}
Weapon::Weapon()
{
Weapon::PatchLimit();
@ -436,6 +452,10 @@ namespace Components
// Skip double loading for fs_game
Utils::Hook::Set<BYTE>(0x4081FD, 0xEB);
// Weapon swap fix
Utils::Hook::Nop(0x4B3670, 5);
Utils::Hook(0x57B4F0, LoadNoneWeaponHookStub).install()->quick();
// Don't load bounce sounds for now, it causes crashes
// TODO: Actually check the weaponfiles and/or reset the soundtable correctly!
//Utils::Hook::Nop(0x57A360, 5);

View File

@ -12,13 +12,11 @@ namespace Components
public:
Weapon();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "Weapon"; };
#endif
private:
static Game::XAssetHeader WeaponFileLoad(Game::XAssetType type, std::string filename);
static void PatchLimit();
static void* LoadNoneWeaponHook();
static void LoadNoneWeaponHookStub();
static void PatchConfigStrings();
static const char* GetWeaponConfigString(int index);

View File

@ -7,10 +7,6 @@ namespace Components
public:
Window();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "Window"; };
#endif
static int Width();
static int Height();
static int Width(HWND window);

View File

@ -95,7 +95,6 @@ namespace Components
~ZoneBuilder();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "ZoneBuilder"; };
bool unitTest() override;
#endif

View File

@ -12,10 +12,6 @@ namespace Components
Zones();
~Zones();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() override { return "Zones"; };
#endif
static void SetVersion(int version);
static int Version() { return Zones::ZoneVersion; };

View File

@ -121,6 +121,8 @@ namespace Game
Image_LoadFromFileWithReader_t Image_LoadFromFileWithReader = Image_LoadFromFileWithReader_t(0x53ABF0);
Image_Release_t Image_Release = Image_Release_t(0x51F010);
Info_ValueForKey_t Info_ValueForKey = Info_ValueForKey_t(0x47C820);
Key_SetCatcher_t Key_SetCatcher = Key_SetCatcher_t(0x43BD00);
LargeLocalInit_t LargeLocalInit = LargeLocalInit_t(0x4A62A0);

View File

@ -304,6 +304,9 @@ namespace Game
typedef void(__cdecl * Image_Release_t)(GfxImage* image);
extern Image_Release_t Image_Release;
typedef char*(__cdecl * Info_ValueForKey_t)(const char* infoString, const char* key);
extern Info_ValueForKey_t Info_ValueForKey;
typedef void(__cdecl * Key_SetCatcher_t)(int localClientNum, int catcher);
extern Key_SetCatcher_t Key_SetCatcher;