aboutsummaryrefslogtreecommitdiff
path: root/NorthstarDedicatedTest/serverauthentication.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'NorthstarDedicatedTest/serverauthentication.cpp')
-rw-r--r--NorthstarDedicatedTest/serverauthentication.cpp166
1 files changed, 108 insertions, 58 deletions
diff --git a/NorthstarDedicatedTest/serverauthentication.cpp b/NorthstarDedicatedTest/serverauthentication.cpp
index 5235761a..112db2a4 100644
--- a/NorthstarDedicatedTest/serverauthentication.cpp
+++ b/NorthstarDedicatedTest/serverauthentication.cpp
@@ -18,33 +18,36 @@ const char* AUTHSERVER_VERIFY_STRING = "I am a northstar server!";
// hook types
-typedef void*(*CBaseServer__ConnectClientType)(void* server, void* a2, void* a3, uint32_t a4, uint32_t a5, int32_t a6, void* a7, void* a8, char* serverFilter, void* a10, char a11, void* a12, char a13, char a14, int64_t uid, uint32_t a16, uint32_t a17);
+typedef void* (*CBaseServer__ConnectClientType)(
+ void* server, void* a2, void* a3, uint32_t a4, uint32_t a5, int32_t a6, void* a7, void* a8, char* serverFilter, void* a10, char a11,
+ void* a12, char a13, char a14, int64_t uid, uint32_t a16, uint32_t a17);
CBaseServer__ConnectClientType CBaseServer__ConnectClient;
-typedef bool(*CBaseClient__ConnectType)(void* self, char* name, __int64 netchan_ptr_arg, char b_fake_player_arg, __int64 a5, char* Buffer, void* a7);
+typedef bool (*CBaseClient__ConnectType)(
+ void* self, char* name, __int64 netchan_ptr_arg, char b_fake_player_arg, __int64 a5, char* Buffer, void* a7);
CBaseClient__ConnectType CBaseClient__Connect;
-typedef void(*CBaseClient__ActivatePlayerType)(void* self);
+typedef void (*CBaseClient__ActivatePlayerType)(void* self);
CBaseClient__ActivatePlayerType CBaseClient__ActivatePlayer;
CBaseClient__DisconnectType CBaseClient__Disconnect;
-typedef char(*CGameClient__ExecuteStringCommandType)(void* self, uint32_t unknown, const char* pCommandString);
+typedef char (*CGameClient__ExecuteStringCommandType)(void* self, uint32_t unknown, const char* pCommandString);
CGameClient__ExecuteStringCommandType CGameClient__ExecuteStringCommand;
-typedef char(*__fastcall CNetChan___ProcessMessagesType)(void* self, void* buf);
+typedef char (*__fastcall CNetChan___ProcessMessagesType)(void* self, void* buf);
CNetChan___ProcessMessagesType CNetChan___ProcessMessages;
-typedef char(*CBaseClient__SendServerInfoType)(void* self);
+typedef char (*CBaseClient__SendServerInfoType)(void* self);
CBaseClient__SendServerInfoType CBaseClient__SendServerInfo;
-typedef bool(*ProcessConnectionlessPacketType)(void* a1, netpacket_t* packet);
+typedef bool (*ProcessConnectionlessPacketType)(void* a1, netpacket_t* packet);
ProcessConnectionlessPacketType ProcessConnectionlessPacket;
-typedef void(*CServerGameDLL__OnRecievedSayTextMessageType)(void* self, unsigned int senderClientIndex, const char* message, char unknown);
+typedef void (*CServerGameDLL__OnRecievedSayTextMessageType)(void* self, unsigned int senderClientIndex, const char* message, char unknown);
CServerGameDLL__OnRecievedSayTextMessageType CServerGameDLL__OnRecievedSayTextMessage;
-typedef void(*ConCommand__DispatchType)(ConCommand* command, const CCommand& args, void* a3);
+typedef void (*ConCommand__DispatchType)(ConCommand* command, const CCommand& args, void* a3);
ConCommand__DispatchType ConCommand__Dispatch;
// global vars
@@ -71,23 +74,36 @@ void ServerAuthenticationManager::StartPlayerAuthServer()
m_runningPlayerAuthThread = true;
// listen is a blocking call so thread this
- std::thread serverThread([this] {
- // this is just a super basic way to verify that servers have ports open, masterserver will try to read this before ensuring server is legit
- m_playerAuthServer.Get("/verify", [](const httplib::Request& request, httplib::Response& response) {
- response.set_content(AUTHSERVER_VERIFY_STRING, "text/plain");
- });
-
- m_playerAuthServer.Post("/authenticate_incoming_player", [this](const httplib::Request& request, httplib::Response& response) {
- // can't just do request.remote_addr == Cvar_ns_masterserver_hostname->m_pszString because the cvar can be a url, gotta resolve an ip from it for comparisons
- //unsigned long remoteAddr = inet_addr(request.remote_addr.c_str());
+ std::thread serverThread(
+ [this]
+ {
+ // this is just a super basic way to verify that servers have ports open, masterserver will try to read this before ensuring
+ // server is legit
+ m_playerAuthServer.Get(
+ "/verify", [](const httplib::Request& request, httplib::Response& response)
+ { response.set_content(AUTHSERVER_VERIFY_STRING, "text/plain"); });
+
+ m_playerAuthServer.Post(
+ "/authenticate_incoming_player",
+ [this](const httplib::Request& request, httplib::Response& response)
+ {
+ // can't just do request.remote_addr == Cvar_ns_masterserver_hostname->m_pszString because the cvar can be a url, gotta
+ // resolve an ip from it for comparisons
+ // unsigned long remoteAddr = inet_addr(request.remote_addr.c_str());
//
- //char* addrPtr = Cvar_ns_masterserver_hostname->m_pszString;
- //char* typeStart = strstr(addrPtr, "://");
- //if (typeStart)
+ // char* addrPtr = Cvar_ns_masterserver_hostname->m_pszString;
+ // char* typeStart = strstr(addrPtr, "://");
+ // if (typeStart)
// addrPtr = typeStart + 3;
- //hostent* resolvedRemoteAddr = gethostbyname((const char*)addrPtr);
-
- if (!request.has_param("id") || !request.has_param("authToken") || request.body.size() >= 65335 || !request.has_param("serverAuthToken") || strcmp(g_MasterServerManager->m_ownServerAuthToken, request.get_param_value("serverAuthToken").c_str()))// || !resolvedRemoteAddr || ((in_addr**)resolvedRemoteAddr->h_addr_list)[0]->S_un.S_addr != remoteAddr)
+ // hostent* resolvedRemoteAddr = gethostbyname((const char*)addrPtr);
+
+ if (!request.has_param("id") || !request.has_param("authToken") || request.body.size() >= 65335 ||
+ !request.has_param("serverAuthToken") ||
+ strcmp(
+ g_MasterServerManager->m_ownServerAuthToken,
+ request.get_param_value("serverAuthToken")
+ .c_str())) // || !resolvedRemoteAddr || ((in_addr**)resolvedRemoteAddr->h_addr_list)[0]->S_un.S_addr !=
+ // remoteAddr)
{
response.set_content("{\"success\":false}", "application/json");
return;
@@ -109,7 +125,7 @@ void ServerAuthenticationManager::StartPlayerAuthServer()
m_playerAuthServer.listen("0.0.0.0", Cvar_ns_player_auth_port->m_nValue);
});
-
+
serverThread.detach();
}
@@ -170,7 +186,6 @@ bool ServerAuthenticationManager::AuthenticatePlayer(void* player, int64_t uid,
}
}
-
if (authFail)
{
// set persistent data as ready, we use 0x3 internally to mark the client as using local persistence
@@ -191,7 +206,7 @@ bool ServerAuthenticationManager::AuthenticatePlayer(void* player, int64_t uid,
std::fstream pdataStream(pdataPath, std::ios_base::in);
if (pdataStream.fail()) // file doesn't exist, use placeholder
pdataStream = std::fstream(GetNorthstarPrefix() + "/placeholder_playerdata.pdata");
-
+
// get file length
pdataStream.seekg(0, pdataStream.end);
auto length = pdataStream.tellg();
@@ -238,7 +253,8 @@ void ServerAuthenticationManager::WritePersistentData(void* player)
// we use 0x4 internally to mark clients as using remote persistence
if (*((char*)player + 0x4A0) == (char)0x4)
{
- g_MasterServerManager->WritePlayerPersistentData((char*)player + 0xF500, (char*)player + 0x4FA, m_additionalPlayerData[player].pdataSize);
+ g_MasterServerManager->WritePlayerPersistentData(
+ (char*)player + 0xF500, (char*)player + 0x4FA, m_additionalPlayerData[player].pdataSize);
}
else if (CVar_ns_auth_allow_insecure_write->m_nValue)
{
@@ -246,7 +262,6 @@ void ServerAuthenticationManager::WritePersistentData(void* player)
}
}
-
// auth hooks
// store these in vars so we can use them in CBaseClient::Connect
@@ -254,7 +269,9 @@ void ServerAuthenticationManager::WritePersistentData(void* player)
char* nextPlayerToken;
uint64_t nextPlayerUid;
-void* CBaseServer__ConnectClientHook(void* server, void* a2, void* a3, uint32_t a4, uint32_t a5, int32_t a6, void* a7, void* a8, char* serverFilter, void* a10, char a11, void* a12, char a13, char a14, int64_t uid, uint32_t a16, uint32_t a17)
+void* CBaseServer__ConnectClientHook(
+ void* server, void* a2, void* a3, uint32_t a4, uint32_t a5, int32_t a6, void* a7, void* a8, char* serverFilter, void* a10, char a11,
+ void* a12, char a13, char a14, int64_t uid, uint32_t a16, uint32_t a17)
{
// auth tokens are sent with serverfilter, can't be accessed from player struct to my knowledge, so have to do this here
nextPlayerToken = serverFilter;
@@ -268,7 +285,7 @@ bool CBaseClient__ConnectHook(void* self, char* name, __int64 netchan_ptr_arg, c
// try to auth player, dc if it fails
// we connect irregardless of auth, because returning bad from this function can fuck client state p bad
bool ret = CBaseClient__Connect(self, name, netchan_ptr_arg, b_fake_player_arg, a5, Buffer, a7);
-
+
if (!ret)
return ret;
@@ -280,7 +297,9 @@ bool CBaseClient__ConnectHook(void* self, char* name, __int64 netchan_ptr_arg, c
if (strlen(name) >= 64) // fix for name overflow bug
CBaseClient__Disconnect(self, 1, "Invalid name");
- else if (!g_ServerAuthenticationManager->AuthenticatePlayer(self, nextPlayerUid, nextPlayerToken) && g_MasterServerManager->m_bRequireClientAuth)
+ else if (
+ !g_ServerAuthenticationManager->AuthenticatePlayer(self, nextPlayerUid, nextPlayerToken) &&
+ g_MasterServerManager->m_bRequireClientAuth)
CBaseClient__Disconnect(self, 1, "Authentication Failed");
if (!g_ServerAuthenticationManager->m_additionalPlayerData.count(self))
@@ -298,7 +317,8 @@ bool CBaseClient__ConnectHook(void* self, char* name, __int64 netchan_ptr_arg, c
void CBaseClient__ActivatePlayerHook(void* self)
{
// if we're authed, write our persistent data
- // RemovePlayerAuthData returns true if it removed successfully, i.e. on first call only, and we only want to write on >= second call (since this func is called on map loads)
+ // RemovePlayerAuthData returns true if it removed successfully, i.e. on first call only, and we only want to write on >= second call
+ // (since this func is called on map loads)
if (*((char*)self + 0x4A0) >= (char)0x3 && !g_ServerAuthenticationManager->RemovePlayerAuthData(self))
{
g_ServerAuthenticationManager->m_bForceReadLocalPlayerPersistenceFromDisk = false;
@@ -340,7 +360,7 @@ void CBaseClient__DisconnectHook(void* self, uint32_t unknownButAlways1, const c
}
// maybe this should be done outside of auth code, but effort to refactor rn and it sorta fits
-typedef bool(*CCommand__TokenizeType)(CCommand& self, const char* pCommandString, cmd_source_t commandSource);
+typedef bool (*CCommand__TokenizeType)(CCommand& self, const char* pCommandString, cmd_source_t commandSource);
CCommand__TokenizeType CCommand__Tokenize;
char CGameClient__ExecuteStringCommandHook(void* self, uint32_t unknown, const char* pCommandString)
@@ -357,7 +377,8 @@ char CGameClient__ExecuteStringCommandHook(void* self, uint32_t unknown, const c
}
g_ServerAuthenticationManager->m_additionalPlayerData[self].numClientCommandsInQuota++;
- if (g_ServerAuthenticationManager->m_additionalPlayerData[self].numClientCommandsInQuota > CVar_sv_quota_stringcmdspersecond->m_nValue)
+ if (g_ServerAuthenticationManager->m_additionalPlayerData[self].numClientCommandsInQuota >
+ CVar_sv_quota_stringcmdspersecond->m_nValue)
{
// too many stringcmds, dc player
CBaseClient__Disconnect(self, 1, "Sent too many stringcmd commands");
@@ -394,7 +415,7 @@ char __fastcall CNetChan___ProcessMessagesHook(void* self, void* buf)
{
double startTime = Plat_FloatTime();
char ret = CNetChan___ProcessMessages(self, buf);
-
+
// check processing limits, unless we're in a level transition
if (g_pHostState->m_iCurrentState == HostState_t::HS_RUN && ThreadInServerFrameThread())
{
@@ -407,17 +428,23 @@ char __fastcall CNetChan___ProcessMessagesHook(void* self, void* buf)
return ret;
// reset every second
- if (startTime - g_ServerAuthenticationManager->m_additionalPlayerData[sender].lastNetChanProcessingLimitStart >= 1.0 || g_ServerAuthenticationManager->m_additionalPlayerData[sender].lastNetChanProcessingLimitStart == -1.0)
+ if (startTime - g_ServerAuthenticationManager->m_additionalPlayerData[sender].lastNetChanProcessingLimitStart >= 1.0 ||
+ g_ServerAuthenticationManager->m_additionalPlayerData[sender].lastNetChanProcessingLimitStart == -1.0)
{
g_ServerAuthenticationManager->m_additionalPlayerData[sender].lastNetChanProcessingLimitStart = startTime;
g_ServerAuthenticationManager->m_additionalPlayerData[sender].netChanProcessingLimitTime = 0.0;
}
- g_ServerAuthenticationManager->m_additionalPlayerData[sender].netChanProcessingLimitTime += (Plat_FloatTime() * 1000) - (startTime * 1000);
+ g_ServerAuthenticationManager->m_additionalPlayerData[sender].netChanProcessingLimitTime +=
+ (Plat_FloatTime() * 1000) - (startTime * 1000);
- if (g_ServerAuthenticationManager->m_additionalPlayerData[sender].netChanProcessingLimitTime >= Cvar_net_chan_limit_msec_per_sec->m_nValue)
+ if (g_ServerAuthenticationManager->m_additionalPlayerData[sender].netChanProcessingLimitTime >=
+ Cvar_net_chan_limit_msec_per_sec->m_nValue)
{
- spdlog::warn("Client {} hit netchan processing limit with {}ms of processing time this second (max is {})", (char*)sender + 0x16, g_ServerAuthenticationManager->m_additionalPlayerData[sender].netChanProcessingLimitTime, Cvar_net_chan_limit_msec_per_sec->m_nValue);
-
+ spdlog::warn(
+ "Client {} hit netchan processing limit with {}ms of processing time this second (max is {})", (char*)sender + 0x16,
+ g_ServerAuthenticationManager->m_additionalPlayerData[sender].netChanProcessingLimitTime,
+ Cvar_net_chan_limit_msec_per_sec->m_nValue);
+
// nonzero = kick, 0 = warn
if (Cvar_net_chan_limit_mode->m_nValue)
{
@@ -437,12 +464,14 @@ void CBaseClient__SendServerInfoHook(void* self)
bWasWritingStringTableSuccessful = true;
CBaseClient__SendServerInfo(self);
if (!bWasWritingStringTableSuccessful)
- CBaseClient__Disconnect(self, 1, "Overflowed CNetworkStringTableContainer::WriteBaselines, try restarting your client and reconnecting");
+ CBaseClient__Disconnect(
+ self, 1, "Overflowed CNetworkStringTableContainer::WriteBaselines, try restarting your client and reconnecting");
}
bool ProcessConnectionlessPacketHook(void* a1, netpacket_t* packet)
{
- if (packet->adr.type == NA_IP && (!(packet->data[4] == 'N' && Cvar_net_datablock_enabled->m_nValue) || !Cvar_net_datablock_enabled->m_nValue))
+ if (packet->adr.type == NA_IP &&
+ (!(packet->data[4] == 'N' && Cvar_net_datablock_enabled->m_nValue) || !Cvar_net_datablock_enabled->m_nValue))
{
// bad lookup: optimise later tm
UnconnectedPlayerSendData* sendData = nullptr;
@@ -474,7 +503,9 @@ bool ProcessConnectionlessPacketHook(void* a1, netpacket_t* packet)
if (sendData->packetCount >= Cvar_sv_querylimit_per_sec->m_nValue)
{
- spdlog::warn("Client went over connectionless ratelimit of {} per sec with packet of type {}", Cvar_sv_querylimit_per_sec->m_nValue, packet->data[4]);
+ spdlog::warn(
+ "Client went over connectionless ratelimit of {} per sec with packet of type {}", Cvar_sv_querylimit_per_sec->m_nValue,
+ packet->data[4]);
// timeout for a minute
sendData->timeoutEnd = Plat_FloatTime() + 60.0;
@@ -523,14 +554,23 @@ void InitialiseServerAuthentication(HMODULE baseAddress)
{
g_ServerAuthenticationManager = new ServerAuthenticationManager;
- Cvar_ns_erase_auth_info = RegisterConVar("ns_erase_auth_info", "1", FCVAR_GAMEDLL, "Whether auth info should be erased from this server on disconnect or crash");
- CVar_ns_auth_allow_insecure = RegisterConVar("ns_auth_allow_insecure", "0", FCVAR_GAMEDLL, "Whether this server will allow unauthenicated players to connect");
- CVar_ns_auth_allow_insecure_write = RegisterConVar("ns_auth_allow_insecure_write", "0", FCVAR_GAMEDLL, "Whether the pdata of unauthenticated clients will be written to disk when changed");
+ Cvar_ns_erase_auth_info = RegisterConVar(
+ "ns_erase_auth_info", "1", FCVAR_GAMEDLL, "Whether auth info should be erased from this server on disconnect or crash");
+ CVar_ns_auth_allow_insecure =
+ RegisterConVar("ns_auth_allow_insecure", "0", FCVAR_GAMEDLL, "Whether this server will allow unauthenicated players to connect");
+ CVar_ns_auth_allow_insecure_write = RegisterConVar(
+ "ns_auth_allow_insecure_write", "0", FCVAR_GAMEDLL,
+ "Whether the pdata of unauthenticated clients will be written to disk when changed");
// literally just stolen from a fix valve used in csgo
- CVar_sv_quota_stringcmdspersecond = RegisterConVar("sv_quota_stringcmdspersecond", "60", FCVAR_GAMEDLL, "How many string commands per second clients are allowed to submit, 0 to disallow all string commands");
+ CVar_sv_quota_stringcmdspersecond = RegisterConVar(
+ "sv_quota_stringcmdspersecond", "60", FCVAR_GAMEDLL,
+ "How many string commands per second clients are allowed to submit, 0 to disallow all string commands");
// https://blog.counter-strike.net/index.php/2019/07/24922/ but different because idk how to check what current tick number is
- Cvar_net_chan_limit_mode = RegisterConVar("net_chan_limit_mode", "0", FCVAR_GAMEDLL, "The mode for netchan processing limits: 0 = log, 1 = kick");
- Cvar_net_chan_limit_msec_per_sec = RegisterConVar("net_chan_limit_msec_per_sec", "0", FCVAR_GAMEDLL, "Netchannel processing is limited to so many milliseconds, abort connection if exceeding budget");
+ Cvar_net_chan_limit_mode =
+ RegisterConVar("net_chan_limit_mode", "0", FCVAR_GAMEDLL, "The mode for netchan processing limits: 0 = log, 1 = kick");
+ Cvar_net_chan_limit_msec_per_sec = RegisterConVar(
+ "net_chan_limit_msec_per_sec", "0", FCVAR_GAMEDLL,
+ "Netchannel processing is limited to so many milliseconds, abort connection if exceeding budget");
Cvar_ns_player_auth_port = RegisterConVar("ns_player_auth_port", "8081", FCVAR_GAMEDLL, "");
Cvar_sv_querylimit_per_sec = RegisterConVar("sv_querylimit_per_sec", "15", FCVAR_GAMEDLL, "");
Cvar_sv_max_chat_messages_per_sec = RegisterConVar("sv_max_chat_messages_per_sec", "5", FCVAR_GAMEDLL, "");
@@ -538,14 +578,22 @@ void InitialiseServerAuthentication(HMODULE baseAddress)
RegisterConCommand("ns_resetpersistence", ResetPdataCommand, "resets your pdata when you next enter the lobby", FCVAR_NONE);
HookEnabler hook;
- ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x114430, &CBaseServer__ConnectClientHook, reinterpret_cast<LPVOID*>(&CBaseServer__ConnectClient));
+ ENABLER_CREATEHOOK(
+ hook, (char*)baseAddress + 0x114430, &CBaseServer__ConnectClientHook, reinterpret_cast<LPVOID*>(&CBaseServer__ConnectClient));
ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x101740, &CBaseClient__ConnectHook, reinterpret_cast<LPVOID*>(&CBaseClient__Connect));
- ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x100F80, &CBaseClient__ActivatePlayerHook, reinterpret_cast<LPVOID*>(&CBaseClient__ActivatePlayer));
- ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x1012C0, &CBaseClient__DisconnectHook, reinterpret_cast<LPVOID*>(&CBaseClient__Disconnect));
- ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x1022E0, &CGameClient__ExecuteStringCommandHook, reinterpret_cast<LPVOID*>(&CGameClient__ExecuteStringCommand));
- ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x2140A0, &CNetChan___ProcessMessagesHook, reinterpret_cast<LPVOID*>(&CNetChan___ProcessMessages));
- ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x104FB0, &CBaseClient__SendServerInfoHook, reinterpret_cast<LPVOID*>(&CBaseClient__SendServerInfo));
- ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x117800, &ProcessConnectionlessPacketHook, reinterpret_cast<LPVOID*>(&ProcessConnectionlessPacket));
+ ENABLER_CREATEHOOK(
+ hook, (char*)baseAddress + 0x100F80, &CBaseClient__ActivatePlayerHook, reinterpret_cast<LPVOID*>(&CBaseClient__ActivatePlayer));
+ ENABLER_CREATEHOOK(
+ hook, (char*)baseAddress + 0x1012C0, &CBaseClient__DisconnectHook, reinterpret_cast<LPVOID*>(&CBaseClient__Disconnect));
+ ENABLER_CREATEHOOK(
+ hook, (char*)baseAddress + 0x1022E0, &CGameClient__ExecuteStringCommandHook,
+ reinterpret_cast<LPVOID*>(&CGameClient__ExecuteStringCommand));
+ ENABLER_CREATEHOOK(
+ hook, (char*)baseAddress + 0x2140A0, &CNetChan___ProcessMessagesHook, reinterpret_cast<LPVOID*>(&CNetChan___ProcessMessages));
+ ENABLER_CREATEHOOK(
+ hook, (char*)baseAddress + 0x104FB0, &CBaseClient__SendServerInfoHook, reinterpret_cast<LPVOID*>(&CBaseClient__SendServerInfo));
+ ENABLER_CREATEHOOK(
+ hook, (char*)baseAddress + 0x117800, &ProcessConnectionlessPacketHook, reinterpret_cast<LPVOID*>(&ProcessConnectionlessPacket));
CCommand__Tokenize = (CCommand__TokenizeType)((char*)baseAddress + 0x418380);
@@ -597,5 +645,7 @@ void InitialiseServerAuthentication(HMODULE baseAddress)
void InitialiseServerAuthenticationServerDLL(HMODULE baseAddress)
{
HookEnabler hook;
- ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x1595C0, &CServerGameDLL__OnRecievedSayTextMessageHook, reinterpret_cast<LPVOID*>(&CServerGameDLL__OnRecievedSayTextMessage));
+ ENABLER_CREATEHOOK(
+ hook, (char*)baseAddress + 0x1595C0, &CServerGameDLL__OnRecievedSayTextMessageHook,
+ reinterpret_cast<LPVOID*>(&CServerGameDLL__OnRecievedSayTextMessage));
} \ No newline at end of file