Implement the stuff B3 needs.

This commit is contained in:
momo5502 2016-03-04 14:48:31 +01:00
parent 69db2c0734
commit 3b8e47fecc
7 changed files with 242 additions and 6 deletions

View File

@ -4,6 +4,7 @@ namespace Components
{
std::vector<Game::cmd_function_t*> Command::Functions;
std::map<std::string, wink::slot<Command::Callback>> Command::FunctionMap;
std::map<std::string, wink::slot<Command::Callback>> Command::FunctionMapSV;
char* Command::Params::operator[](size_t index)
{
@ -12,12 +13,26 @@ namespace Components
return "";
}
return Game::cmd_argv[this->CommandId][index];
if (this->IsSV)
{
return Game::cmd_argv_sv[this->CommandId][index];
}
else
{
return Game::cmd_argv[this->CommandId][index];
}
}
size_t Command::Params::Length()
{
return Game::cmd_argc[this->CommandId];
if (this->IsSV)
{
return Game::cmd_argc_sv[this->CommandId];
}
else
{
return Game::cmd_argc[this->CommandId];
}
}
std::string Command::Params::Join(size_t startIndex)
@ -39,6 +54,28 @@ namespace Components
Game::Cmd_AddCommand(name, Command::MainCallback, Command::Allocate(), 0);
}
void Command::AddSV(const char* name, Command::Callback* callback)
{
Command::FunctionMapSV[Utils::StrToLower(name)] = callback;
Game::Cmd_AddServerCommand(name, Command::MainCallbackSV, Command::Allocate());
// If the main command is registered as Cbuf_AddServerText, the command will be redirected to the SV handler
Command::AddRaw(name, Game::Cbuf_AddServerText);
}
void Command::AddRaw(const char* name, void(*callback)())
{
Game::Cmd_AddCommand(name, callback, Command::Allocate(), 0);
}
void Command::AddRawSV(const char* name, void(*callback)())
{
Game::Cmd_AddServerCommand(name, callback, Command::Allocate());
// If the main command is registered as Cbuf_AddServerText, the command will be redirected to the SV handler
Command::AddRaw(name, Game::Cbuf_AddServerText);
}
void Command::Execute(std::string command, bool sync)
{
command.append("\n"); // Make sure it's terminated
@ -63,7 +100,7 @@ namespace Components
void Command::MainCallback()
{
Command::Params params(*Game::cmd_id);
Command::Params params(false, *Game::cmd_id);
std::string command = Utils::StrToLower(params[0]);
@ -73,6 +110,18 @@ namespace Components
}
}
void Command::MainCallbackSV()
{
Command::Params params(true, *Game::cmd_id_sv);
std::string command = Utils::StrToLower(params[0]);
if (Command::FunctionMapSV.find(command) != Command::FunctionMapSV.end())
{
Command::FunctionMapSV[command](params);
}
}
Command::Command()
{
// TODO: Add commands here?
@ -86,5 +135,7 @@ namespace Components
}
Command::Functions.clear();
Command::FunctionMap.clear();
Command::FunctionMapSV.clear();
}
}

View File

@ -6,9 +6,9 @@ namespace Components
class Params
{
public:
Params(DWORD id) : CommandId(id) {};
Params(const Params &obj) { this->CommandId = obj.CommandId; };
Params() : Params(*Game::cmd_id) {};
Params(bool sv, DWORD id) : CommandId(id), IsSV(sv) {};
Params(const Params &obj) : CommandId(obj.CommandId), IsSV(obj.IsSV) {};
Params() : Params(false, *Game::cmd_id) {};
char* operator[](size_t index);
size_t Length();
@ -16,6 +16,7 @@ namespace Components
std::string Join(size_t startIndex);
private:
bool IsSV;
DWORD CommandId;
};
@ -26,12 +27,17 @@ namespace Components
const char* GetName() { return "Command"; };
static void Add(const char* name, Callback* callback);
static void AddSV(const char* name, Callback* callback);
static void AddRaw(const char* name, void(*callback)());
static void AddRawSV(const char* name, void(*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, wink::slot<Callback>> FunctionMap;
static std::map<std::string, wink::slot<Callback>> FunctionMapSV;
static void MainCallback();
static void MainCallbackSV();
};
}

View File

@ -5,6 +5,8 @@ namespace Components
wink::signal<wink::slot<Dedicated::Callback>> Dedicated::FrameSignal;
wink::signal<wink::slot<Dedicated::Callback>> Dedicated::FrameOnceSignal;
bool Dedicated::SendChat;
bool Dedicated::IsDedicated()
{
return Flags::HasFlag("dedicated");
@ -58,6 +60,62 @@ namespace Components
}
}
const char* Dedicated::EvaluateSay(char* text)
{
Dedicated::SendChat = true;
if (text[1] == '/')
{
Dedicated::SendChat = false;
text[1] = text[0];
++text;
}
return text;
}
void __declspec(naked) Dedicated::PreSayStub()
{
__asm
{
mov eax, [esp + 100h + 10h]
push eax
call EvaluateSay
add esp, 4h
mov [esp + 100h + 10h], eax
jmp Colors::CleanStrStub
}
}
void __declspec(naked) Dedicated::PostSayStub()
{
__asm
{
// eax is used by the callee
push eax
xor eax, eax
mov al, Dedicated::SendChat
test al, al
jnz return
// Don't send the chat
pop eax
retn
return:
pop eax
// Jump to the target
push 5DF620h
retn
}
}
void Dedicated::MapRotate()
{
if (!Dedicated::IsDedicated() && Dvar::Var("sv_dontrotate").Get<bool>())
@ -228,6 +286,11 @@ namespace Components
// Dedicated frame handler
Utils::Hook(0x4B0F81, Dedicated::FrameStub, HOOK_CALL).Install()->Quick();
// Intercept chat sending
Utils::Hook(0x4D000B, Dedicated::PreSayStub, HOOK_CALL).Install()->Quick();
Utils::Hook(0x4D00D4, Dedicated::PostSayStub, HOOK_CALL).Install()->Quick();
Utils::Hook(0x4D0110, Dedicated::PostSayStub, HOOK_CALL).Install()->Quick();
if (!ZoneBuilder::IsEnabled())
{
// Post initialization point
@ -248,6 +311,93 @@ namespace Components
});
#endif
}
Dvar::OnInit([] ()
{
Dvar::Register<const char*>("sv_sayName", "^7Console", Game::dvar_flag::DVAR_FLAG_NONE, "The name to pose as for 'say' commands");
// Say command
Command::AddSV("say", [] (Command::Params params)
{
if (params.Length() < 2) return;
std::string message = params.Join(1);
std::string name = Dvar::Var("sv_sayName").Get<std::string>();
if (!name.empty())
{
Game::SV_GameSendServerCommand(-1, 0, Utils::VA("%c \"%s: %s\"", 104, name.data(), message.data()));
Game::Com_Printf(15, "%s: %s\n", name.data(), message.data());
}
else
{
Game::SV_GameSendServerCommand(-1, 0, Utils::VA("%c \"Console: %s\"", 104, message.data()));
Game::Com_Printf(15, "Console: %s\n", message.data());
}
});
// Tell command
Command::AddSV("tell", [] (Command::Params params)
{
if (params.Length() < 3) return;
int client = atoi(params[1]);
std::string message = params.Join(2);
std::string name = Dvar::Var("sv_sayName").Get<std::string>();
if (!name.empty())
{
Game::SV_GameSendServerCommand(client, 0, Utils::VA("%c \"%s: %s\"", 104, name.data(), message.data()));
Game::Com_Printf(15, "%s -> %i: %s\n", name.data(), client, message.data());
}
else
{
Game::SV_GameSendServerCommand(client, 0, Utils::VA("%c \"Console: %s\"", 104, message.data()));
Game::Com_Printf(15, "Console -> %i: %s\n", client, message.data());
}
});
// Sayraw command
Command::AddSV("sayraw", [] (Command::Params params)
{
if (params.Length() < 2) return;
std::string message = params.Join(1);
Game::SV_GameSendServerCommand(-1, 0, Utils::VA("%c \"%s\"", 104, message.data()));
Game::Com_Printf(15, "Raw: %s\n", message.data());
});
// Tellraw command
Command::AddSV("tellraw", [] (Command::Params params)
{
if (params.Length() < 3) return;
int client = atoi(params[1]);
std::string message = params.Join(2);
Game::SV_GameSendServerCommand(client, 0, Utils::VA("%c \"%s\"", 104, message.data()));
Game::Com_Printf(15, "Raw -> %i: %s\n", client, message.data());
});
// ! command
Command::AddSV("!", [] (Command::Params params)
{
if (params.Length() != 2) return;
int client = -1;
if (std::string(params[1]) != "all")
{
client = atoi(params[1]);
if (client >= *reinterpret_cast<int*>(0x31D938C))
{
Game::Com_Printf(0, "Invalid player.\n");
return;
}
}
Game::SV_GameSendServerCommand(client, 0, Utils::VA("%c \"\"", 106));
});
});
}
}

View File

@ -20,11 +20,18 @@ namespace Components
static wink::signal<wink::slot<Callback>> FrameSignal;
static wink::signal<wink::slot<Callback>> FrameOnceSignal;
static bool SendChat;
static void MapRotate();
static void FrameStub();
static void InitDedicatedServer();
static void PostInitialization();
static void PostInitializationStub();
static const char* EvaluateSay(char* text);
static void PreSayStub();
static void PostSayStub();
};
}

View File

@ -88,6 +88,8 @@ namespace Components
Utils::Hook::Set<void*>(0x4D90B7, Maps::WorldMP);
}
AntiCheat::EmptyHash();
_snprintf(buffer, size, format, mapname);
}

View File

@ -5,6 +5,7 @@ namespace Game
// C-Style casts are fine here, that's where we're doing our dirty stuff anyways...
BG_LoadWeaponDef_LoadObj_t BG_LoadWeaponDef_LoadObj = (BG_LoadWeaponDef_LoadObj_t)0x57B5F0;
Cbuf_AddServerText_t Cbuf_AddServerText = (Cbuf_AddServerText_t)0x4BB9B0;
Cbuf_AddText_t Cbuf_AddText = (Cbuf_AddText_t)0x404B20;
CL_GetClientName_t CL_GetClientName = (CL_GetClientName_t)0x4563D0;
@ -12,6 +13,7 @@ namespace Game
CL_ConnectFromParty_t CL_ConnectFromParty = (CL_ConnectFromParty_t)0x433D30;
Cmd_AddCommand_t Cmd_AddCommand = (Cmd_AddCommand_t)0x470090;
Cmd_AddServerCommand_t Cmd_AddServerCommand = (Cmd_AddServerCommand_t)0x4DCE00;
Cmd_ExecuteSingleCommand_t Cmd_ExecuteSingleCommand = (Cmd_ExecuteSingleCommand_t)0x609540;
Com_Error_t Com_Error = (Com_Error_t)0x4B22D0;
@ -130,6 +132,7 @@ namespace Game
Steam_JoinLobby_t Steam_JoinLobby = (Steam_JoinLobby_t)0x49CF70;
SV_GameClientNum_Score_t SV_GameClientNum_Score = (SV_GameClientNum_Score_t)0x469AC0;
SV_GameSendServerCommand_t SV_GameSendServerCommand = (SV_GameSendServerCommand_t)0x4BC3A0;
Sys_IsMainThread_t Sys_IsMainThread = (Sys_IsMainThread_t)0x4C37D0;
Sys_SendPacket_t Sys_SendPacket = (Sys_SendPacket_t)0x60FDC0;
@ -147,6 +150,10 @@ namespace Game
DWORD* cmd_argc = (DWORD*)0x1AAC614;
char*** cmd_argv = (char***)0x1AAC634;
DWORD* cmd_id_sv = (DWORD*)0x1ACF8A0;
DWORD* cmd_argc_sv = (DWORD*)0x1ACF8E4;
char*** cmd_argv_sv = (char***)0x1ACF904;
source_t **sourceFiles = (source_t **)0x7C4A98;
keywordHash_t **menuParseKeywordHash = (keywordHash_t **)0x63AE928;

View File

@ -3,6 +3,9 @@ namespace Game
typedef void*(__cdecl * BG_LoadWeaponDef_LoadObj_t)(const char* filename);
extern BG_LoadWeaponDef_LoadObj_t BG_LoadWeaponDef_LoadObj;
typedef void(__cdecl * Cbuf_AddServerText_t)();
extern Cbuf_AddServerText_t Cbuf_AddServerText;
typedef void(__cdecl * Cbuf_AddText_t)(int localClientNum, const char *text);
extern Cbuf_AddText_t Cbuf_AddText;
@ -18,6 +21,9 @@ namespace Game
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_AddServerCommand_t)(const char* name, void(*callback), cmd_function_t* data);
extern Cmd_AddServerCommand_t Cmd_AddServerCommand;
typedef void(__cdecl * Cmd_ExecuteSingleCommand_t)(int controller, int a2, const char* cmd);
extern Cmd_ExecuteSingleCommand_t Cmd_ExecuteSingleCommand;
@ -302,6 +308,9 @@ namespace Game
typedef int(__cdecl* SV_GameClientNum_Score_t)(int clientID);
extern SV_GameClientNum_Score_t SV_GameClientNum_Score;
typedef void(__cdecl * SV_GameSendServerCommand_t)(int clientNum, /*svscmd_type*/int type, const char* text);
extern SV_GameSendServerCommand_t SV_GameSendServerCommand;
typedef bool(__cdecl * Sys_IsMainThread_t)();
extern Sys_IsMainThread_t Sys_IsMainThread;
@ -327,6 +336,10 @@ namespace Game
extern DWORD* cmd_argc;
extern char*** cmd_argv;
extern DWORD* cmd_id_sv;
extern DWORD* cmd_argc_sv;
extern char*** cmd_argv_sv;
extern int* svs_numclients;
extern client_t* svs_clients;