Server-side moddownload implemented

This commit is contained in:
momo5502 2016-06-04 21:24:03 +02:00
parent fea894cd5e
commit 0c205f0353
16 changed files with 267 additions and 62 deletions

View File

@ -261,7 +261,7 @@ workspace "iw4x"
kind "StaticLib"
-- json11
-- mongoose
project "mongoose"
language "C"

View File

@ -46,12 +46,12 @@ namespace Components
}
else
{
Logger::Print("Sending XUID authentication request to %s\n", Network::Address(client->adr).GetString());
Logger::Print("Sending XUID authentication request to %s\n", Network::Address(client->addr).GetCString());
info->state = Auth::STATE_NEGOTIATING;
info->time = Game::Com_Milliseconds();
info->challenge = Utils::VA("%X", Utils::Cryptography::Rand::GenerateInt());
Network::SendCommand(client->adr, "xuidAuthReq", info->challenge);
Network::SendCommand(client->addr, "xuidAuthReq", info->challenge);
}
}
else if (info->state == Auth::STATE_UNKNOWN && !info->time)
@ -109,7 +109,7 @@ namespace Components
{
if (clientNum >= 18) return;
Network::Address address(Game::svs_clients[clientNum].adr);
Network::Address address(Game::svs_clients[clientNum].addr);
if (address.GetType() == Game::netadrtype_t::NA_BOT)
{
@ -117,7 +117,7 @@ namespace Components
}
else
{
Logger::Print("Registering client %s\n", address.GetString());
Logger::Print("Registering client %s\n", address.GetCString());
Auth::ClientAuthInfo[clientNum].time = 0;
Auth::ClientAuthInfo[clientNum].state = Auth::STATE_UNKNOWN;
}
@ -297,7 +297,7 @@ namespace Components
{
Network::Handle("xuidAuthReq", [] (Network::Address address, std::string data)
{
Logger::Print("Received XUID authentication request from %s\n", address.GetString());
Logger::Print("Received XUID authentication request from %s\n", address.GetCString());
// Only accept requests from the server we're connected to
if (address != *Game::connectedHost) return;
@ -317,14 +317,14 @@ namespace Components
Network::Handle("xuidAuthResp", [] (Network::Address address, std::string data)
{
Logger::Print("Received XUID authentication response from %s\n", address.GetString());
Logger::Print("Received XUID authentication response from %s\n", address.GetCString());
for (int i = 0; i < *Game::svs_numclients; i++)
{
Game::client_t* client = &Game::svs_clients[i];
Auth::AuthInfo* info = &Auth::ClientAuthInfo[i];
if (client->state >= 3 && address == client->adr && info->state == Auth::STATE_NEGOTIATING)
if (client->state >= 3 && address == client->addr && info->state == Auth::STATE_NEGOTIATING)
{
Proto::Auth::Response response;
unsigned int id = static_cast<unsigned int>(~0x110000100000000 & client->steamid);
@ -356,7 +356,7 @@ namespace Components
if (userLevel >= ourLevel)
{
info->state = Auth::STATE_VALID;
Logger::Print("Verified XUID %llX (%d) from %s\n", client->steamid, userLevel, address.GetString());
Logger::Print("Verified XUID %llX (%d) from %s\n", client->steamid, userLevel, address.GetCString());
}
else
{

View File

@ -47,11 +47,11 @@ namespace Components
if (!address.IsLocal())
{
Logger::Print("Received discovery request from non-local address: %s\n", address.GetString());
Logger::Print("Received discovery request from non-local address: %s\n", address.GetCString());
return;
}
Logger::Print("Received discovery request from %s\n", address.GetString());
Logger::Print("Received discovery request from %s\n", address.GetCString());
Network::SendCommand(address, "discoveryResponse", data);
});
@ -61,17 +61,17 @@ namespace Components
if (!address.IsLocal())
{
Logger::Print("Received discovery response from non-local address: %s\n", address.GetString());
Logger::Print("Received discovery response from non-local address: %s\n", address.GetCString());
return;
}
if (Utils::ParseChallenge(data) != Discovery::DiscoveryContainer.Challenge)
{
Logger::Print("Received discovery with invalid challenge from: %s\n", address.GetString());
Logger::Print("Received discovery with invalid challenge from: %s\n", address.GetCString());
return;
}
Logger::Print("Received discovery response from: %s\n", address.GetString());
Logger::Print("Received discovery response from: %s\n", address.GetCString());
if (ServerList::IsOfflineList())
{

View File

@ -4,6 +4,152 @@ namespace Components
{
mg_mgr Download::Mgr;
bool Download::IsClient(mg_connection *nc)
{
return (Download::GetClient(nc) != nullptr);
}
Game::client_t* Download::GetClient(mg_connection *nc)
{
Network::Address address(nc->sa.sa);
for (int i = 0; i < *Game::svs_numclients; ++i)
{
Game::client_t* client = &Game::svs_clients[i];
if (client->state >= 3)
{
if (address.GetIP().full == Network::Address(client->addr).GetIP().full)
{
return client;
}
}
}
return nullptr;
}
void Download::Forbid(mg_connection *nc)
{
mg_printf(nc, "HTTP/1.1 403 Forbidden\r\n"
"Content-Type: text/html\r\n"
"Connection: close\r\n"
"\r\n"
"403 - Forbidden");
nc->flags |= MG_F_SEND_AND_CLOSE;
}
void Download::ListHandler(mg_connection *nc, int ev, void *ev_data)
{
// Only handle http requests
if (ev != MG_EV_HTTP_REQUEST) return;
// if (!Download::IsClient(nc))
// {
// Download::Forbid(nc);
// }
// else
{
static std::string fsGamePre;
static json11::Json jsonList;
std::string fsGame = Dvar::Var("fs_game").Get<std::string>();
if (!fsGame.empty() && fsGame != fsGamePre)
{
std::vector<json11::Json> fileList;
fsGamePre = fsGame;
std::string path = Dvar::Var("fs_basepath").Get<std::string>() + "\\" + fsGame;
auto list = FileSystem::GetSysFileList(path, "iwd", false);
list.push_back("mod.ff");
for (auto i = list.begin(); i != list.end(); ++i)
{
std::string filename = path + "\\" + *i;
if (strstr(i->data(), "_svr_") == NULL && Utils::FileExists(filename))
{
std::map<std::string, json11::Json> file;
std::string fileBuffer = Utils::ReadFile(path + "\\" + *i);
file["name"] = *i;
file["size"] = static_cast<int>(fileBuffer.size());
file["hash"] = Utils::Cryptography::SHA256::Compute(fileBuffer, true);
fileList.push_back(file);
}
}
jsonList = fileList;
}
mg_printf(nc,
"HTTP/1.1 200 OK\r\n"
"Content-Type: application/json\r\n"
"Connection: close\r\n"
"\r\n"
"%s", jsonList.dump().data());
nc->flags |= MG_F_SEND_AND_CLOSE;
}
}
void Download::FileHandler(mg_connection *nc, int ev, void *ev_data)
{
// Only handle http requests
if (ev != MG_EV_HTTP_REQUEST) return;
http_message* message = reinterpret_cast<http_message*>(ev_data);
// if (!Download::IsClient(nc))
// {
// Download::Forbid(nc);
// }
// else
{
std::string url(message->uri.p, message->uri.len);
Utils::Replace(url, "\\", "/");
url = url.substr(6);
if (url.find_first_of("/") != std::string::npos || (!Utils::EndsWith(url, ".iwd") && url != "mod.ff") || strstr(url.data(), "_svr_") != NULL)
{
Download::Forbid(nc);
return;
}
std::string fsGame = Dvar::Var("fs_game").Get<std::string>();
std::string path = Dvar::Var("fs_basepath").Get<std::string>() + "\\" + fsGame + "\\" + url;
if (fsGame.empty() || !Utils::FileExists(path))
{
mg_printf(nc,
"HTTP/1.1 404 Not Found\r\n"
"Content-Type: text/html\r\n"
"Connection: close\r\n"
"\r\n"
"404 - Not Found %s", path.data());
}
else
{
std::string file = Utils::ReadFile(path);
mg_printf(nc,
"HTTP/1.1 200 OK\r\n"
"Content-Type: application/octet-stream\r\n"
"Content-Length: %d\r\n"
"Connection: close\r\n"
"\r\n", file.size());
mg_send(nc, file.data(), static_cast<int>(file.size()));
}
nc->flags |= MG_F_SEND_AND_CLOSE;
}
}
void Download::EventHandler(mg_connection *nc, int ev, void *ev_data)
{
// Only handle http requests
@ -13,12 +159,19 @@ namespace Components
if (std::string(message->uri.p, message->uri.len) == "/")
{
mg_printf(nc, "%s",
mg_printf(nc,
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/html\r\n"
"Connection: close\r\n"
"\r\n"
"Hi fella!");
"Hi fella!<br>You are%s connected to this server!", (Download::IsClient(nc) ? " " : " not"));
Game::client_t* client = Download::GetClient(nc);
if (client)
{
mg_printf(nc, "<br>Hello %s!", client->name);
}
}
else
{
@ -27,7 +180,7 @@ namespace Components
"Content-Type: text/html\r\n"
"Connection: close\r\n"
"\r\n"
"<h1>404 - Not Found</h1>");
"404 - Not Found");
}
nc->flags |= MG_F_SEND_AND_CLOSE;
@ -42,6 +195,11 @@ namespace Components
Network::OnStart([] ()
{
mg_connection* nc = mg_bind(&Download::Mgr, Utils::VA("%hu", (Dvar::Var("net_port").Get<int>() & 0xFFFF)), Download::EventHandler);
// Handle list requests
mg_register_http_endpoint(nc, "/list", Download::ListHandler);
mg_register_http_endpoint(nc, "/file", Download::FileHandler);
mg_set_protocol_http_websocket(nc);
});

View File

@ -11,5 +11,11 @@ namespace Components
static mg_mgr Mgr;
static void EventHandler(mg_connection *nc, int ev, void *ev_data);
static void ListHandler(mg_connection *nc, int ev, void *ev_data);
static void FileHandler(mg_connection *nc, int ev, void *ev_data);
static bool IsClient(mg_connection *nc);
static Game::client_t* GetClient(mg_connection *nc);
static void Forbid(mg_connection *nc);
};
}

View File

@ -397,7 +397,7 @@ namespace Components
if(i != Menus::MenuList.end())
{
if (i->second) Menus::FreeMenu(i->second);
Menus::MenuList.erase(i);
i = Menus::MenuList.erase(i);
}
}
@ -408,7 +408,7 @@ namespace Components
if (i->second == menudef)
{
Menus::FreeMenu(menudef);
Menus::MenuList.erase(i);
i = Menus::MenuList.erase(i);
break;
}
}
@ -429,7 +429,7 @@ namespace Components
Menus::FreeMenuList(i->second);
}
Menus::MenuListList.erase(i);
i = Menus::MenuListList.erase(i);
}
}

View File

@ -10,6 +10,10 @@ namespace Components
{
Game::NET_StringToAdr(addrString.data(), &this->address);
}
Network::Address::Address(sockaddr* addr)
{
Game::SockadrToNetadr(addr, &this->address);
}
bool Network::Address::operator==(const Network::Address &obj)
{
return Game::NET_CompareAdr(this->address, obj.address);
@ -42,14 +46,35 @@ namespace Components
{
return this->address.type;
}
sockaddr Network::Address::GetSockAddr()
{
sockaddr addr;
this->ToSockAddr(&addr);
return addr;
}
void Network::Address::ToSockAddr(sockaddr* addr)
{
if (addr)
{
Game::NetadrToSockadr(&this->address, addr);
}
}
void Network::Address::ToSockAddr(sockaddr_in* addr)
{
this->ToSockAddr(reinterpret_cast<sockaddr*>(addr));
}
Game::netadr_t* Network::Address::Get()
{
return &this->address;
}
const char* Network::Address::GetString()
const char* Network::Address::GetCString()
{
return Game::NET_AdrToString(this->address);
}
std::string Network::Address::GetString()
{
return this->GetCString();
}
bool Network::Address::IsLocal()
{
// According to: https://en.wikipedia.org/wiki/Private_network

View File

@ -10,6 +10,10 @@ namespace Components
public:
Address() { this->SetType(Game::netadrtype_t::NA_BAD); };
Address(std::string addrString);
Address(sockaddr* addr);
Address(sockaddr addr) : Address(&addr) {}
Address(sockaddr_in addr) : Address(&addr) {}
Address(sockaddr_in* addr) : Address(reinterpret_cast<sockaddr*>(addr)) {}
Address(Game::netadr_t addr) : address(addr) {}
Address(Game::netadr_t* addr) : Address(*addr) {}
Address(const Address& obj) : address(obj.address) {};
@ -27,8 +31,12 @@ namespace Components
void SetType(Game::netadrtype_t type);
Game::netadrtype_t GetType();
sockaddr GetSockAddr();
void ToSockAddr(sockaddr* addr);
void ToSockAddr(sockaddr_in* addr);
Game::netadr_t* Get();
const char* GetString();
const char* GetCString();
std::string GetString();
bool IsLocal();
bool IsSelf();

View File

@ -131,7 +131,7 @@ namespace Components
Node::Nodes.push_back(entry);
#ifdef DEBUG
Logger::Print("Adding node %s...\n", address.GetString());
Logger::Print("Adding node %s...\n", address.GetCString());
#endif
}
}
@ -190,7 +190,7 @@ namespace Components
{
if (node.state == Node::STATE_INVALID && (Game::Com_Milliseconds() - node.lastHeard) > NODE_INVALID_DELETE)
{
Logger::Print("Removing invalid node %s\n", node.address.GetString());
Logger::Print("Removing invalid node %s\n", node.address.GetCString());
}
else
{
@ -233,14 +233,14 @@ namespace Components
packet.set_challenge(entry->challenge);
#ifdef DEBUG
Logger::Print("Sending registration request to %s\n", entry->address.GetString());
Logger::Print("Sending registration request to %s\n", entry->address.GetCString());
#endif
Network::SendCommand(entry->address, "nodeRegisterRequest", packet.SerializeAsString());
}
else
{
#ifdef DEBUG
Logger::Print("Sending session request to %s\n", entry->address.GetString());
Logger::Print("Sending session request to %s\n", entry->address.GetCString());
#endif
Network::SendCommand(entry->address, "sessionRequest");
}
@ -268,7 +268,7 @@ namespace Components
node.lastHeard = Game::Com_Milliseconds();
node.lastTime = Game::Com_Milliseconds();
Logger::Print("Node negotiation timed out. Invalidating %s\n", node.address.GetString());
Logger::Print("Node negotiation timed out. Invalidating %s\n", node.address.GetCString());
}
if (registerCount < NODE_FRAME_QUERY_LIMIT)
@ -399,7 +399,7 @@ namespace Components
}
#ifdef DEBUG
Logger::Print("Received registration request from %s\n", address.GetString());
Logger::Print("Received registration request from %s\n", address.GetCString());
#endif
Proto::Node::Packet packet;
@ -440,7 +440,7 @@ namespace Components
if (!entry || entry->state != Node::STATE_NEGOTIATING) return;
#ifdef DEBUG
Logger::Print("Received synchronization data for registration from %s!\n", address.GetString());
Logger::Print("Received synchronization data for registration from %s!\n", address.GetCString());
#endif
Proto::Node::Packet packet;
@ -457,7 +457,7 @@ namespace Components
entry->publicKey.Set(publicKey);
if (!Utils::Cryptography::ECC::VerifyMessage(entry->publicKey, entry->challenge, signature))
{
Logger::Print("Signature from %s for challenge '%s' is invalid!\n", address.GetString(), entry->challenge.data());
Logger::Print("Signature from %s for challenge '%s' is invalid!\n", address.GetCString(), entry->challenge.data());
return;
}
@ -467,8 +467,8 @@ namespace Components
entry->registered = true;
#ifdef DEBUG
Logger::Print("Signature from %s for challenge '%s' is valid!\n", address.GetString(), entry->challenge.data());
Logger::Print("Node %s registered\n", address.GetString());
Logger::Print("Signature from %s for challenge '%s' is valid!\n", address.GetCString(), entry->challenge.data());
Logger::Print("Node %s registered\n", address.GetCString());
#endif
// Build response
@ -491,7 +491,7 @@ namespace Components
if (!entry || entry->state != Node::STATE_NEGOTIATING) return;
#ifdef DEBUG
Logger::Print("Received acknowledgment from %s\n", address.GetString());
Logger::Print("Received acknowledgment from %s\n", address.GetCString());
#endif
Proto::Node::Packet packet;
@ -511,13 +511,13 @@ namespace Components
entry->registered = true;
#ifdef DEBUG
Logger::Print("Signature from %s for challenge '%s' is valid!\n", address.GetString(), entry->challenge.data());
Logger::Print("Node %s registered\n", address.GetString());
Logger::Print("Signature from %s for challenge '%s' is valid!\n", address.GetCString(), entry->challenge.data());
Logger::Print("Node %s registered\n", address.GetCString());
#endif
}
else
{
Logger::Print("Signature from %s for challenge '%s' is invalid!\n", address.GetString(), entry->challenge.data());
Logger::Print("Signature from %s for challenge '%s' is invalid!\n", address.GetCString(), entry->challenge.data());
}
});
@ -552,7 +552,7 @@ namespace Components
else
{
// Unallowed connection
Logger::Print("Node list requested by %s, but no valid session was present!\n", address.GetString());
Logger::Print("Node list requested by %s, but no valid session was present!\n", address.GetCString());
Network::SendCommand(address, "nodeListError");
}
});
@ -580,12 +580,12 @@ namespace Components
entry->state = Node::STATE_INVALID;
#ifdef DEBUG
Logger::Print("Node %s unregistered\n", address.GetString());
Logger::Print("Node %s unregistered\n", address.GetCString());
#endif
}
else
{
Logger::Print("Node %s tried to unregister using an invalid signature!\n", address.GetString());
Logger::Print("Node %s tried to unregister using an invalid signature!\n", address.GetCString());
}
});
@ -606,7 +606,7 @@ namespace Components
if (!session) return; // Registering template session failed, odd...
#ifdef DEBUG
Logger::Print("Client %s is requesting a new session\n", address.GetString());
Logger::Print("Client %s is requesting a new session\n", address.GetCString());
#endif
// Initialize session data
@ -628,7 +628,7 @@ namespace Components
if (session->challenge == data)
{
#ifdef DEBUG
Logger::Print("Session for %s validated.\n", address.GetString());
Logger::Print("Session for %s validated.\n", address.GetCString());
#endif
session->valid = true;
Network::SendCommand(address, "sessionAcknowledge");
@ -636,7 +636,7 @@ namespace Components
else
{
session->lastTime = -1;
Logger::Print("Challenge mismatch. Validating session for %s failed.\n", address.GetString());
Logger::Print("Challenge mismatch. Validating session for %s failed.\n", address.GetCString());
}
});
}
@ -648,7 +648,7 @@ namespace Components
if (!entry) return;
#ifdef DEBUG
Logger::Print("Session initialization received from %s. Synchronizing...\n", address.GetString());
Logger::Print("Session initialization received from %s. Synchronizing...\n", address.GetCString());
#endif
entry->lastTime = Game::Com_Milliseconds();
@ -665,7 +665,7 @@ namespace Components
entry->lastTime = Game::Com_Milliseconds();
#ifdef DEBUG
Logger::Print("Session acknowledged by %s, synchronizing node list...\n", address.GetString());
Logger::Print("Session acknowledged by %s, synchronizing node list...\n", address.GetCString());
#endif
Network::SendCommand(address, "nodeListRequest");
Node::SendNodeList(address);
@ -678,7 +678,7 @@ namespace Components
if (data.empty() || !list.ParseFromString(data))
{
Logger::Print("Received invalid node list from %s!\n", address.GetString());
Logger::Print("Received invalid node list from %s!\n", address.GetCString());
return;
}
@ -687,7 +687,7 @@ namespace Components
{
if (entry->registered)
{
Logger::Print("Received valid node list with %i entries from %s\n", list.address_size(), address.GetString());
Logger::Print("Received valid node list with %i entries from %s\n", list.address_size(), address.GetCString());
entry->isDedi = list.is_dedi();
entry->state = Node::STATE_VALID;
@ -763,7 +763,7 @@ namespace Components
for (auto node : Node::Nodes)
{
Logger::Print("%s\t(%s)\n", node.address.GetString(), Node::GetStateName(node.state));
Logger::Print("%s\t(%s)\n", node.address.GetCString(), Node::GetStateName(node.state));
}
});

View File

@ -64,7 +64,7 @@ namespace Components
if (!list.ParseFromString(data))
{
Party::PlaylistError(Utils::VA("Received playlist response from %s, but it is invalid.", address.GetString()));
Party::PlaylistError(Utils::VA("Received playlist response from %s, but it is invalid.", address.GetCString()));
Playlist::ReceivedPlaylistBuffer.clear();
return;
}
@ -77,7 +77,7 @@ namespace Components
//Validate hashes
if (hash != list.hash())
{
Party::PlaylistError(Utils::VA("Received playlist response from %s, but the checksum did not match (%X != %X).", address.GetString(), list.hash(), hash));
Party::PlaylistError(Utils::VA("Received playlist response from %s, but the checksum did not match (%X != %X).", address.GetCString(), list.hash(), hash));
Playlist::ReceivedPlaylistBuffer.clear();
return;
}

View File

@ -80,7 +80,7 @@ namespace Components
auto pos = data.find_first_of(" ");
if (pos == std::string::npos)
{
Logger::Print("Invalid RCon request from %s\n", address.GetString());
Logger::Print("Invalid RCon request from %s\n", address.GetCString());
return;
}
@ -98,7 +98,7 @@ namespace Components
if (svPassword.empty())
{
Logger::Print("RCon request from %s dropped. No password set!\n", address.GetString());
Logger::Print("RCon request from %s dropped. No password set!\n", address.GetCString());
return;
}
@ -107,7 +107,7 @@ namespace Components
static std::string outputBuffer;
outputBuffer.clear();
Logger::Print("Executing RCon request from %s: %s\n", address.GetString(), command.data());
Logger::Print("Executing RCon request from %s: %s\n", address.GetCString(), command.data());
Logger::PipeOutput([] (std::string output)
{
@ -123,7 +123,7 @@ namespace Components
}
else
{
Logger::Print("Invalid RCon password sent from %s\n", address.GetString());
Logger::Print("Invalid RCon password sent from %s\n", address.GetCString());
}
});

View File

@ -73,8 +73,7 @@ namespace Components
Game::Font* font = Game::R_RegisterFont("fonts/bigfont");
void* cxt = Game::UI_GetContext(a1);
Network::Address address(reinterpret_cast<Game::netadr_t*>(0xA1E888));
std::string addressText = address.GetString();
std::string addressText = Network::Address(*Game::connectedHost).GetString();
if (addressText == "0.0.0.0:0") addressText = "Listen Server";
// get x positions

View File

@ -405,7 +405,7 @@ namespace Components
server.Addr = address;
// Remove server from queue
ServerList::RefreshContainer.Servers.erase(i);
i = ServerList::RefreshContainer.Servers.erase(i);
// Check if already inserted and remove
auto list = ServerList::GetList();
@ -416,7 +416,7 @@ namespace Components
{
if (j->Addr == address)
{
list->erase(j);
j = list->erase(j);
break;
}
}
@ -426,7 +426,7 @@ namespace Components
{
if (*j == k)
{
ServerList::VisibleList.erase(j);
j = ServerList::VisibleList.erase(j);
break;
}
}
@ -692,8 +692,7 @@ namespace Components
{
if (Dvar::Var("cl_ingame").Get<bool>())
{
Network::Address address(reinterpret_cast<Game::netadr_t*>(0xA1E888));
std::string addressText = address.GetString();
std::string addressText = Network::Address(*Game::connectedHost).GetString();
if (addressText != "0.0.0.0:0")
{
ServerList::StoreFavourite(addressText);

View File

@ -91,6 +91,8 @@ namespace Game
MSG_ReadByte_t MSG_ReadByte = (MSG_ReadByte_t)0x4C1C20;
MSG_ReadBitsCompress_t MSG_ReadBitsCompress = (MSG_ReadBitsCompress_t)0x4DCC30;
NetadrToSockadr_t NetadrToSockadr = (NetadrToSockadr_t)0x4B4B40;
NET_AdrToString_t NET_AdrToString = (NET_AdrToString_t)0x469880;
NET_CompareAdr_t NET_CompareAdr = (NET_CompareAdr_t)0x4D0AA0;
NET_IsLocalAddress_t NET_IsLocalAddress = (NET_IsLocalAddress_t)0x402BD0;
@ -145,6 +147,8 @@ namespace Game
SND_InitDriver_t SND_InitDriver = (SND_InitDriver_t)0x4F5090;
SockadrToNetadr_t SockadrToNetadr = (SockadrToNetadr_t)0x4F8460;
Steam_JoinLobby_t Steam_JoinLobby = (Steam_JoinLobby_t)0x49CF70;
SV_GameClientNum_Score_t SV_GameClientNum_Score = (SV_GameClientNum_Score_t)0x469AC0;
@ -368,7 +372,7 @@ namespace Game
{
if (client->state < 5)
{
Components::Network::Send(client->adr, Utils::VA("error\n%s", reason));
Components::Network::Send(client->addr, Utils::VA("error\n%s", reason));
}
SV_KickClient(client, reason);

View File

@ -218,6 +218,9 @@ namespace Game
typedef int(__cdecl * MSG_WriteBitsCompress_t)(bool trainHuffman, const char *from, char *to, int size);
extern MSG_WriteBitsCompress_t MSG_WriteBitsCompress;
typedef void(__cdecl * NetadrToSockadr_t)(netadr_t *a, sockaddr *s);
extern NetadrToSockadr_t NetadrToSockadr;
typedef const char* (__cdecl * NET_AdrToString_t)(netadr_t adr);
extern NET_AdrToString_t NET_AdrToString;
@ -332,6 +335,9 @@ namespace Game
typedef void(__cdecl * SND_InitDriver_t)();
extern SND_InitDriver_t SND_InitDriver;
typedef void(__cdecl * SockadrToNetadr_t)(sockaddr *s, netadr_t *a);
extern SockadrToNetadr_t SockadrToNetadr;
typedef void(__cdecl * Steam_JoinLobby_t)(SteamID, char);
extern Steam_JoinLobby_t Steam_JoinLobby;

View File

@ -880,7 +880,7 @@ namespace Game
// 4
char pad[36];
// 40
netadr_t adr;
netadr_t addr;
// 60
char pad1[1568];
// 1628