Introduce sub-protocols
This commit is contained in:
parent
ff70b3e1c5
commit
6fecdeb68d
@ -110,6 +110,7 @@ namespace getinfo
|
||||
info.set("bots", std::to_string(get_bot_count()));
|
||||
info.set("sv_maxclients", std::to_string(get_max_client_count()));
|
||||
info.set("protocol", std::to_string(PROTOCOL));
|
||||
info.set("sub_protocol", std::to_string(SUB_PROTOCOL));
|
||||
info.set("playmode", std::to_string(game::Com_SessionMode_GetMode()));
|
||||
info.set("gamemode", std::to_string(Com_SessionMode_GetGameMode()));
|
||||
info.set("sv_running", std::to_string(game::is_server_running()));
|
||||
|
@ -157,6 +157,14 @@ namespace party
|
||||
return;
|
||||
}
|
||||
|
||||
const auto sub_protocol = atoi(info.get("sub_protocol").data());
|
||||
if (sub_protocol != SUB_PROTOCOL && sub_protocol != (SUB_PROTOCOL - 1))
|
||||
{
|
||||
const auto str = "Invalid sub-protocol.";
|
||||
printf("%s\n", str);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto gamename = info.get("gamename");
|
||||
if (gamename != "T7"s)
|
||||
{
|
||||
|
@ -1,164 +1,164 @@
|
||||
#include <std_include.hpp>
|
||||
#include "loader/component_loader.hpp"
|
||||
#include "server_list.hpp"
|
||||
|
||||
#include "game/game.hpp"
|
||||
|
||||
#include <utils/string.hpp>
|
||||
#include <utils/concurrency.hpp>
|
||||
#include <utils/hook.hpp>
|
||||
|
||||
#include "network.hpp"
|
||||
#include "scheduler.hpp"
|
||||
|
||||
namespace server_list
|
||||
{
|
||||
namespace
|
||||
{
|
||||
#include <std_include.hpp>
|
||||
#include "loader/component_loader.hpp"
|
||||
#include "server_list.hpp"
|
||||
|
||||
#include "game/game.hpp"
|
||||
|
||||
#include <utils/string.hpp>
|
||||
#include <utils/concurrency.hpp>
|
||||
#include <utils/hook.hpp>
|
||||
|
||||
#include "network.hpp"
|
||||
#include "scheduler.hpp"
|
||||
|
||||
namespace server_list
|
||||
{
|
||||
namespace
|
||||
{
|
||||
utils::hook::detour lua_serverinfo_to_table_hook;
|
||||
|
||||
struct state
|
||||
{
|
||||
game::netadr_t address{};
|
||||
bool requesting{false};
|
||||
std::chrono::high_resolution_clock::time_point query_start{};
|
||||
callback callback{};
|
||||
};
|
||||
|
||||
utils::concurrency::container<state> master_state;
|
||||
|
||||
void handle_server_list_response(const game::netadr_t& target,
|
||||
const network::data_view& data, state& s)
|
||||
{
|
||||
if (!s.requesting || s.address != target)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
s.requesting = false;
|
||||
const auto callback = std::move(s.callback);
|
||||
|
||||
std::optional<size_t> start{};
|
||||
|
||||
for (size_t i = 0; i + 6 < data.size(); ++i)
|
||||
{
|
||||
if (data[i + 6] == '\\')
|
||||
{
|
||||
start.emplace(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!start.has_value())
|
||||
{
|
||||
callback(true, {});
|
||||
return;
|
||||
}
|
||||
|
||||
std::unordered_set<game::netadr_t> result{};
|
||||
|
||||
for (auto i = start.value(); i + 6 < data.size(); i += 7)
|
||||
{
|
||||
if (data[i + 6] != '\\')
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
game::netadr_t address{};
|
||||
address.type = game::NA_RAWIP;
|
||||
address.localNetID = game::NS_CLIENT1;
|
||||
memcpy(&address.ipv4.a, data.data() + i + 0, 4);
|
||||
memcpy(&address.port, data.data() + i + 4, 2);
|
||||
address.port = ntohs(address.port);
|
||||
|
||||
result.emplace(address);
|
||||
}
|
||||
|
||||
callback(true, result);
|
||||
|
||||
struct state
|
||||
{
|
||||
game::netadr_t address{};
|
||||
bool requesting{false};
|
||||
std::chrono::high_resolution_clock::time_point query_start{};
|
||||
callback callback{};
|
||||
};
|
||||
|
||||
utils::concurrency::container<state> master_state;
|
||||
|
||||
void handle_server_list_response(const game::netadr_t& target,
|
||||
const network::data_view& data, state& s)
|
||||
{
|
||||
if (!s.requesting || s.address != target)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
s.requesting = false;
|
||||
const auto callback = std::move(s.callback);
|
||||
|
||||
std::optional<size_t> start{};
|
||||
|
||||
for (size_t i = 0; i + 6 < data.size(); ++i)
|
||||
{
|
||||
if (data[i + 6] == '\\')
|
||||
{
|
||||
start.emplace(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!start.has_value())
|
||||
{
|
||||
callback(true, {});
|
||||
return;
|
||||
}
|
||||
|
||||
std::unordered_set<game::netadr_t> result{};
|
||||
|
||||
for (auto i = start.value(); i + 6 < data.size(); i += 7)
|
||||
{
|
||||
if (data[i + 6] != '\\')
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
game::netadr_t address{};
|
||||
address.type = game::NA_RAWIP;
|
||||
address.localNetID = game::NS_CLIENT1;
|
||||
memcpy(&address.ipv4.a, data.data() + i + 0, 4);
|
||||
memcpy(&address.port, data.data() + i + 4, 2);
|
||||
address.port = ntohs(address.port);
|
||||
|
||||
result.emplace(address);
|
||||
}
|
||||
|
||||
callback(true, result);
|
||||
}
|
||||
|
||||
void lua_serverinfo_to_table_stub(game::hks::lua_State* state, game::ServerInfo serverInfo, int index)
|
||||
{
|
||||
{
|
||||
lua_serverinfo_to_table_hook.invoke(state, serverInfo, index);
|
||||
|
||||
if (state)
|
||||
{
|
||||
auto botCount = atoi(game::Info_ValueForKey(serverInfo.tags, "bots"));
|
||||
game::Lua_SetTableInt("botCount", botCount, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool get_master_server(game::netadr_t& address)
|
||||
{
|
||||
address = network::address_from_string("server.boiii.re:20810");
|
||||
return address.type != game::NA_BAD;
|
||||
}
|
||||
|
||||
void request_servers(callback callback)
|
||||
{
|
||||
master_state.access([&callback](state& s)
|
||||
{
|
||||
game::netadr_t addr{};
|
||||
if (!get_master_server(addr))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
s.requesting = true;
|
||||
s.address = addr;
|
||||
s.callback = std::move(callback);
|
||||
s.query_start = std::chrono::high_resolution_clock::now();
|
||||
|
||||
network::send(s.address, "getservers", utils::string::va("T7 %i full empty", PROTOCOL));
|
||||
});
|
||||
}
|
||||
|
||||
struct component final : client_component
|
||||
{
|
||||
void post_unpack() override
|
||||
{
|
||||
network::on("getServersResponse", [](const game::netadr_t& target, const network::data_view& data)
|
||||
{
|
||||
master_state.access([&](state& s)
|
||||
{
|
||||
handle_server_list_response(target, data, s);
|
||||
});
|
||||
});
|
||||
|
||||
scheduler::loop([]
|
||||
{
|
||||
master_state.access([](state& s)
|
||||
{
|
||||
if (!s.requesting)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto now = std::chrono::high_resolution_clock::now();
|
||||
if ((now - s.query_start) < 2s)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
s.requesting = false;
|
||||
s.callback(false, {});
|
||||
s.callback = {};
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool get_master_server(game::netadr_t& address)
|
||||
{
|
||||
address = network::address_from_string("server.boiii.re:20810");
|
||||
return address.type != game::NA_BAD;
|
||||
}
|
||||
|
||||
void request_servers(callback callback)
|
||||
{
|
||||
master_state.access([&callback](state& s)
|
||||
{
|
||||
game::netadr_t addr{};
|
||||
if (!get_master_server(addr))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
s.requesting = true;
|
||||
s.address = addr;
|
||||
s.callback = std::move(callback);
|
||||
s.query_start = std::chrono::high_resolution_clock::now();
|
||||
|
||||
network::send(s.address, "getservers", utils::string::va("T7 %i full empty", PROTOCOL));
|
||||
});
|
||||
}
|
||||
|
||||
struct component final : client_component
|
||||
{
|
||||
void post_unpack() override
|
||||
{
|
||||
network::on("getServersResponse", [](const game::netadr_t& target, const network::data_view& data)
|
||||
{
|
||||
master_state.access([&](state& s)
|
||||
{
|
||||
handle_server_list_response(target, data, s);
|
||||
});
|
||||
});
|
||||
|
||||
scheduler::loop([]
|
||||
{
|
||||
master_state.access([](state& s)
|
||||
{
|
||||
if (!s.requesting)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto now = std::chrono::high_resolution_clock::now();
|
||||
if ((now - s.query_start) < 2s)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
s.requesting = false;
|
||||
s.callback(false, {});
|
||||
s.callback = {};
|
||||
});
|
||||
}, scheduler::async, 200ms);
|
||||
|
||||
lua_serverinfo_to_table_hook.create(0x141F1FD10_g, lua_serverinfo_to_table_stub);
|
||||
}
|
||||
|
||||
void pre_destroy() override
|
||||
{
|
||||
master_state.access([](state& s)
|
||||
{
|
||||
s.requesting = false;
|
||||
s.callback = {};
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
REGISTER_COMPONENT(server_list::component)
|
||||
lua_serverinfo_to_table_hook.create(0x141F1FD10_g, lua_serverinfo_to_table_stub);
|
||||
}
|
||||
|
||||
void pre_destroy() override
|
||||
{
|
||||
master_state.access([](state& s)
|
||||
{
|
||||
s.requesting = false;
|
||||
s.callback = {};
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
REGISTER_COMPONENT(server_list::component)
|
||||
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#define PROTOCOL 4
|
||||
#define SUB_PROTOCOL 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
namespace game
|
||||
|
@ -1,333 +1,334 @@
|
||||
#include <std_include.hpp>
|
||||
#include "../steam.hpp"
|
||||
|
||||
#include "game/game.hpp"
|
||||
|
||||
#include "component/party.hpp"
|
||||
#include "component/network.hpp"
|
||||
#include "component/server_list.hpp"
|
||||
|
||||
#include <utils/string.hpp>
|
||||
#include <utils/concurrency.hpp>
|
||||
|
||||
namespace steam
|
||||
{
|
||||
namespace
|
||||
{
|
||||
struct server
|
||||
{
|
||||
bool handled{false};
|
||||
game::netadr_t address{};
|
||||
gameserveritem_t server_item{};
|
||||
};
|
||||
|
||||
auto* const internet_request = reinterpret_cast<void*>(1);
|
||||
|
||||
using servers = std::vector<server>;
|
||||
|
||||
::utils::concurrency::container<servers> queried_servers{};
|
||||
std::atomic<matchmaking_server_list_response*> current_response{};
|
||||
|
||||
gameserveritem_t create_server_item(const game::netadr_t& address, const ::utils::info_string& info,
|
||||
const uint32_t ping, const bool success)
|
||||
{
|
||||
gameserveritem_t server{};
|
||||
server.m_NetAdr.m_usConnectionPort = address.port;
|
||||
server.m_NetAdr.m_usQueryPort = address.port;
|
||||
server.m_NetAdr.m_unIP = ntohl(address.addr);
|
||||
server.m_nPing = static_cast<int>(ping);
|
||||
server.m_bHadSuccessfulResponse = success;
|
||||
server.m_bDoNotRefresh = false;
|
||||
::utils::string::copy(server.m_szGameDir, "");
|
||||
::utils::string::copy(server.m_szMap, info.get("mapname").data());
|
||||
::utils::string::copy(server.m_szGameDescription, info.get("description").data());
|
||||
server.m_nAppID = 311210;
|
||||
server.m_nPlayers = atoi(info.get("clients").data());
|
||||
server.m_nMaxPlayers = atoi(info.get("sv_maxclients").data());
|
||||
server.m_nBotPlayers = atoi(info.get("bots").data());
|
||||
server.m_bPassword = info.get("isPrivate") == "1";
|
||||
server.m_bSecure = true;
|
||||
server.m_ulTimeLastPlayed = 0;
|
||||
server.m_nServerVersion = 1000;
|
||||
::utils::string::copy(server.m_szServerName, info.get("hostname").data());
|
||||
|
||||
const auto playmode = info.get("playmode");
|
||||
const auto mode = game::eModes(std::atoi(playmode.data()));
|
||||
|
||||
const auto* tags = ::utils::string::va(
|
||||
R"(\gametype\%s\dedicated\%s\ranked\false\hardcore\%s\zombies\%s\playerCount\%d\bots\%d\modName\%s\)",
|
||||
info.get("gametype").data(),
|
||||
#include <std_include.hpp>
|
||||
#include "../steam.hpp"
|
||||
|
||||
#include "game/game.hpp"
|
||||
|
||||
#include "component/party.hpp"
|
||||
#include "component/network.hpp"
|
||||
#include "component/server_list.hpp"
|
||||
|
||||
#include <utils/string.hpp>
|
||||
#include <utils/concurrency.hpp>
|
||||
|
||||
namespace steam
|
||||
{
|
||||
namespace
|
||||
{
|
||||
struct server
|
||||
{
|
||||
bool handled{false};
|
||||
game::netadr_t address{};
|
||||
gameserveritem_t server_item{};
|
||||
};
|
||||
|
||||
auto* const internet_request = reinterpret_cast<void*>(1);
|
||||
|
||||
using servers = std::vector<server>;
|
||||
|
||||
::utils::concurrency::container<servers> queried_servers{};
|
||||
std::atomic<matchmaking_server_list_response*> current_response{};
|
||||
|
||||
gameserveritem_t create_server_item(const game::netadr_t& address, const ::utils::info_string& info,
|
||||
const uint32_t ping, const bool success)
|
||||
{
|
||||
const auto sub_protocol = atoi(info.get("sub_protocol").data());
|
||||
|
||||
gameserveritem_t server{};
|
||||
server.m_NetAdr.m_usConnectionPort = address.port;
|
||||
server.m_NetAdr.m_usQueryPort = address.port;
|
||||
server.m_NetAdr.m_unIP = ntohl(address.addr);
|
||||
server.m_nPing = static_cast<int>(ping);
|
||||
server.m_bHadSuccessfulResponse = success;
|
||||
server.m_bDoNotRefresh = false;
|
||||
::utils::string::copy(server.m_szGameDir, "");
|
||||
::utils::string::copy(server.m_szMap, info.get("mapname").data());
|
||||
::utils::string::copy(server.m_szGameDescription, info.get("description").data());
|
||||
server.m_nAppID = (sub_protocol == SUB_PROTOCOL || sub_protocol == (SUB_PROTOCOL - 1)) ? 311210 : 0;
|
||||
server.m_nPlayers = atoi(info.get("clients").data());
|
||||
server.m_nMaxPlayers = atoi(info.get("sv_maxclients").data());
|
||||
server.m_nBotPlayers = atoi(info.get("bots").data());
|
||||
server.m_bPassword = info.get("isPrivate") == "1";
|
||||
server.m_bSecure = true;
|
||||
server.m_ulTimeLastPlayed = 0;
|
||||
server.m_nServerVersion = 1000;
|
||||
::utils::string::copy(server.m_szServerName, info.get("hostname").data());
|
||||
|
||||
const auto playmode = info.get("playmode");
|
||||
const auto mode = game::eModes(std::atoi(playmode.data()));
|
||||
|
||||
const auto* tags = ::utils::string::va(
|
||||
R"(\gametype\%s\dedicated\%s\ranked\false\hardcore\%s\zombies\%s\playerCount\%d\bots\%d\modName\%s\)",
|
||||
info.get("gametype").data(),
|
||||
info.get("dedicated") == "1" ? "true" : "false",
|
||||
info.get("hc") == "1" ? "true" : "false",
|
||||
info.get("hc") == "1" ? "true" : "false",
|
||||
mode == game::MODE_ZOMBIES ? "true" : "false",
|
||||
server.m_nPlayers,
|
||||
atoi(info.get("bots").data()),
|
||||
info.get("modname").data());
|
||||
|
||||
::utils::string::copy(server.m_szGameTags, tags);
|
||||
server.m_steamID.bits = strtoull(info.get("xuid").data(), nullptr, 16);
|
||||
|
||||
return server;
|
||||
}
|
||||
|
||||
void handle_server_respone(const bool success, const game::netadr_t& host, const ::utils::info_string& info,
|
||||
const uint32_t ping)
|
||||
{
|
||||
bool all_handled = false;
|
||||
std::optional<int> index{};
|
||||
queried_servers.access([&](servers& srvs)
|
||||
{
|
||||
size_t i = 0;
|
||||
for (; i < srvs.size(); ++i)
|
||||
{
|
||||
if (srvs[i].address == host)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i >= srvs.size())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
index = static_cast<int>(i);
|
||||
|
||||
auto& srv = srvs[i];
|
||||
srv.handled = true;
|
||||
srv.server_item = create_server_item(host, info, ping, success);
|
||||
|
||||
|
||||
for (const auto& entry : srvs)
|
||||
{
|
||||
if (!entry.handled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
all_handled = true;
|
||||
});
|
||||
|
||||
const auto res = current_response.load();
|
||||
if (!index || !res)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (success)
|
||||
{
|
||||
res->ServerResponded(internet_request, *index);
|
||||
}
|
||||
else
|
||||
{
|
||||
res->ServerFailedToRespond(internet_request, *index);
|
||||
}
|
||||
|
||||
if (all_handled)
|
||||
{
|
||||
res->RefreshComplete(internet_request, eServerResponded);
|
||||
}
|
||||
}
|
||||
|
||||
void ping_server(const game::netadr_t& server)
|
||||
{
|
||||
party::query_server(server, handle_server_respone);
|
||||
}
|
||||
}
|
||||
|
||||
void* matchmaking_servers::RequestInternetServerList(unsigned int iApp, void** ppchFilters, unsigned int nFilters,
|
||||
matchmaking_server_list_response* pRequestServersResponse)
|
||||
{
|
||||
current_response = pRequestServersResponse;
|
||||
|
||||
server_list::request_servers([](const bool success, const std::unordered_set<game::netadr_t>& s)
|
||||
{
|
||||
const auto res = current_response.load();
|
||||
if (!res)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!success)
|
||||
{
|
||||
res->RefreshComplete(internet_request, eServerFailedToRespond);
|
||||
return;
|
||||
}
|
||||
|
||||
if (s.empty())
|
||||
{
|
||||
res->RefreshComplete(internet_request, eNoServersListedOnMasterServer);
|
||||
return;
|
||||
}
|
||||
|
||||
queried_servers.access([&s](servers& srvs)
|
||||
{
|
||||
srvs = {};
|
||||
srvs.reserve(s.size());
|
||||
|
||||
for (auto& address : s)
|
||||
{
|
||||
server new_server{};
|
||||
new_server.address = address;
|
||||
new_server.server_item = create_server_item(address, {}, 0, false);
|
||||
|
||||
srvs.push_back(new_server);
|
||||
}
|
||||
});
|
||||
|
||||
for (auto& srv : s)
|
||||
{
|
||||
ping_server(srv);
|
||||
}
|
||||
});
|
||||
|
||||
return internet_request;
|
||||
}
|
||||
|
||||
void* matchmaking_servers::RequestLANServerList(unsigned int iApp,
|
||||
matchmaking_server_list_response* pRequestServersResponse)
|
||||
{
|
||||
return reinterpret_cast<void*>(2);
|
||||
}
|
||||
|
||||
void* matchmaking_servers::RequestFriendsServerList(unsigned int iApp, void** ppchFilters, unsigned int nFilters,
|
||||
matchmaking_server_list_response* pRequestServersResponse)
|
||||
{
|
||||
return reinterpret_cast<void*>(3);
|
||||
}
|
||||
|
||||
void* matchmaking_servers::RequestFavoritesServerList(unsigned int iApp, void** ppchFilters, unsigned int nFilters,
|
||||
matchmaking_server_list_response* pRequestServersResponse)
|
||||
{
|
||||
return reinterpret_cast<void*>(4);
|
||||
}
|
||||
|
||||
void* matchmaking_servers::RequestHistoryServerList(unsigned int iApp, void** ppchFilters, unsigned int nFilters,
|
||||
matchmaking_server_list_response* pRequestServersResponse)
|
||||
{
|
||||
return reinterpret_cast<void*>(5);
|
||||
}
|
||||
|
||||
void* matchmaking_servers::RequestSpectatorServerList(unsigned int iApp, void** ppchFilters, unsigned int nFilters,
|
||||
matchmaking_server_list_response* pRequestServersResponse)
|
||||
{
|
||||
return reinterpret_cast<void*>(6);
|
||||
}
|
||||
|
||||
void matchmaking_servers::ReleaseRequest(void* hServerListRequest)
|
||||
{
|
||||
if (internet_request == hServerListRequest)
|
||||
{
|
||||
current_response = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
gameserveritem_t* matchmaking_servers::GetServerDetails(void* hRequest, int iServer)
|
||||
{
|
||||
if (internet_request != hRequest)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static thread_local gameserveritem_t server_item{};
|
||||
return queried_servers.access<gameserveritem_t*>([iServer](const servers& s) -> gameserveritem_t*
|
||||
{
|
||||
if (iServer < 0 || static_cast<size_t>(iServer) >= s.size())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
server_item = s[iServer].server_item;
|
||||
return &server_item;
|
||||
});
|
||||
}
|
||||
|
||||
void matchmaking_servers::CancelQuery(void* hRequest)
|
||||
{
|
||||
}
|
||||
|
||||
void matchmaking_servers::RefreshQuery(void* hRequest)
|
||||
{
|
||||
}
|
||||
|
||||
bool matchmaking_servers::IsRefreshing(void* hRequest)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int matchmaking_servers::GetServerCount(void* hRequest)
|
||||
{
|
||||
if (internet_request != hRequest)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return queried_servers.access<int>([](const servers& s)
|
||||
{
|
||||
return static_cast<int>(s.size());
|
||||
});
|
||||
}
|
||||
|
||||
void matchmaking_servers::RefreshServer(void* hRequest, const int iServer)
|
||||
{
|
||||
if (internet_request != hRequest)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
std::optional<game::netadr_t> address{};
|
||||
queried_servers.access([&](const servers& s)
|
||||
{
|
||||
if (iServer < 0 || static_cast<size_t>(iServer) >= s.size())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
address = s[iServer].address;
|
||||
});
|
||||
|
||||
if (address)
|
||||
{
|
||||
ping_server(*address);
|
||||
}
|
||||
}
|
||||
|
||||
void* matchmaking_servers::PingServer(const unsigned int unIP, const unsigned short usPort,
|
||||
matchmaking_ping_response* pRequestServersResponse)
|
||||
{
|
||||
auto response = pRequestServersResponse;
|
||||
const auto addr = network::address_from_ip(htonl(unIP), usPort);
|
||||
|
||||
party::query_server(
|
||||
addr, [response](const bool success, const game::netadr_t& host, const ::utils::info_string& info,
|
||||
const uint32_t ping)
|
||||
{
|
||||
if (success)
|
||||
{
|
||||
auto server_item = create_server_item(host, info, ping, success);
|
||||
response->ServerResponded(server_item);
|
||||
}
|
||||
else
|
||||
{
|
||||
response->ServerFailedToRespond();
|
||||
}
|
||||
});
|
||||
|
||||
return reinterpret_cast<void*>(static_cast<uint64_t>(7 + rand()));
|
||||
}
|
||||
|
||||
int matchmaking_servers::PlayerDetails(unsigned int unIP, unsigned short usPort, void* pRequestServersResponse)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int matchmaking_servers::ServerRules(unsigned int unIP, unsigned short usPort, void* pRequestServersResponse)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void matchmaking_servers::CancelServerQuery(int hServerQuery)
|
||||
{
|
||||
}
|
||||
}
|
||||
info.get("modname").data());
|
||||
|
||||
::utils::string::copy(server.m_szGameTags, tags);
|
||||
server.m_steamID.bits = strtoull(info.get("xuid").data(), nullptr, 16);
|
||||
|
||||
return server;
|
||||
}
|
||||
|
||||
void handle_server_respone(const bool success, const game::netadr_t& host, const ::utils::info_string& info,
|
||||
const uint32_t ping)
|
||||
{
|
||||
bool all_handled = false;
|
||||
std::optional<int> index{};
|
||||
queried_servers.access([&](servers& srvs)
|
||||
{
|
||||
size_t i = 0;
|
||||
for (; i < srvs.size(); ++i)
|
||||
{
|
||||
if (srvs[i].address == host)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i >= srvs.size())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
index = static_cast<int>(i);
|
||||
|
||||
auto& srv = srvs[i];
|
||||
srv.handled = true;
|
||||
srv.server_item = create_server_item(host, info, ping, success);
|
||||
|
||||
|
||||
for (const auto& entry : srvs)
|
||||
{
|
||||
if (!entry.handled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
all_handled = true;
|
||||
});
|
||||
|
||||
const auto res = current_response.load();
|
||||
if (!index || !res)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (success)
|
||||
{
|
||||
res->ServerResponded(internet_request, *index);
|
||||
}
|
||||
else
|
||||
{
|
||||
res->ServerFailedToRespond(internet_request, *index);
|
||||
}
|
||||
|
||||
if (all_handled)
|
||||
{
|
||||
res->RefreshComplete(internet_request, eServerResponded);
|
||||
}
|
||||
}
|
||||
|
||||
void ping_server(const game::netadr_t& server)
|
||||
{
|
||||
party::query_server(server, handle_server_respone);
|
||||
}
|
||||
}
|
||||
|
||||
void* matchmaking_servers::RequestInternetServerList(unsigned int iApp, void** ppchFilters, unsigned int nFilters,
|
||||
matchmaking_server_list_response* pRequestServersResponse)
|
||||
{
|
||||
current_response = pRequestServersResponse;
|
||||
|
||||
server_list::request_servers([](const bool success, const std::unordered_set<game::netadr_t>& s)
|
||||
{
|
||||
const auto res = current_response.load();
|
||||
if (!res)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!success)
|
||||
{
|
||||
res->RefreshComplete(internet_request, eServerFailedToRespond);
|
||||
return;
|
||||
}
|
||||
|
||||
if (s.empty())
|
||||
{
|
||||
res->RefreshComplete(internet_request, eNoServersListedOnMasterServer);
|
||||
return;
|
||||
}
|
||||
|
||||
queried_servers.access([&s](servers& srvs)
|
||||
{
|
||||
srvs = {};
|
||||
srvs.reserve(s.size());
|
||||
|
||||
for (auto& address : s)
|
||||
{
|
||||
server new_server{};
|
||||
new_server.address = address;
|
||||
new_server.server_item = create_server_item(address, {}, 0, false);
|
||||
|
||||
srvs.push_back(new_server);
|
||||
}
|
||||
});
|
||||
|
||||
for (auto& srv : s)
|
||||
{
|
||||
ping_server(srv);
|
||||
}
|
||||
});
|
||||
|
||||
return internet_request;
|
||||
}
|
||||
|
||||
void* matchmaking_servers::RequestLANServerList(unsigned int iApp,
|
||||
matchmaking_server_list_response* pRequestServersResponse)
|
||||
{
|
||||
return reinterpret_cast<void*>(2);
|
||||
}
|
||||
|
||||
void* matchmaking_servers::RequestFriendsServerList(unsigned int iApp, void** ppchFilters, unsigned int nFilters,
|
||||
matchmaking_server_list_response* pRequestServersResponse)
|
||||
{
|
||||
return reinterpret_cast<void*>(3);
|
||||
}
|
||||
|
||||
void* matchmaking_servers::RequestFavoritesServerList(unsigned int iApp, void** ppchFilters, unsigned int nFilters,
|
||||
matchmaking_server_list_response* pRequestServersResponse)
|
||||
{
|
||||
return reinterpret_cast<void*>(4);
|
||||
}
|
||||
|
||||
void* matchmaking_servers::RequestHistoryServerList(unsigned int iApp, void** ppchFilters, unsigned int nFilters,
|
||||
matchmaking_server_list_response* pRequestServersResponse)
|
||||
{
|
||||
return reinterpret_cast<void*>(5);
|
||||
}
|
||||
|
||||
void* matchmaking_servers::RequestSpectatorServerList(unsigned int iApp, void** ppchFilters, unsigned int nFilters,
|
||||
matchmaking_server_list_response* pRequestServersResponse)
|
||||
{
|
||||
return reinterpret_cast<void*>(6);
|
||||
}
|
||||
|
||||
void matchmaking_servers::ReleaseRequest(void* hServerListRequest)
|
||||
{
|
||||
if (internet_request == hServerListRequest)
|
||||
{
|
||||
current_response = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
gameserveritem_t* matchmaking_servers::GetServerDetails(void* hRequest, int iServer)
|
||||
{
|
||||
if (internet_request != hRequest)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static thread_local gameserveritem_t server_item{};
|
||||
return queried_servers.access<gameserveritem_t*>([iServer](const servers& s) -> gameserveritem_t* {
|
||||
if (iServer < 0 || static_cast<size_t>(iServer) >= s.size())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
server_item = s[iServer].server_item;
|
||||
return &server_item;
|
||||
});
|
||||
}
|
||||
|
||||
void matchmaking_servers::CancelQuery(void* hRequest)
|
||||
{
|
||||
}
|
||||
|
||||
void matchmaking_servers::RefreshQuery(void* hRequest)
|
||||
{
|
||||
}
|
||||
|
||||
bool matchmaking_servers::IsRefreshing(void* hRequest)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int matchmaking_servers::GetServerCount(void* hRequest)
|
||||
{
|
||||
if (internet_request != hRequest)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return queried_servers.access<int>([](const servers& s)
|
||||
{
|
||||
return static_cast<int>(s.size());
|
||||
});
|
||||
}
|
||||
|
||||
void matchmaking_servers::RefreshServer(void* hRequest, const int iServer)
|
||||
{
|
||||
if (internet_request != hRequest)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
std::optional<game::netadr_t> address{};
|
||||
queried_servers.access([&](const servers& s)
|
||||
{
|
||||
if (iServer < 0 || static_cast<size_t>(iServer) >= s.size())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
address = s[iServer].address;
|
||||
});
|
||||
|
||||
if (address)
|
||||
{
|
||||
ping_server(*address);
|
||||
}
|
||||
}
|
||||
|
||||
void* matchmaking_servers::PingServer(const unsigned int unIP, const unsigned short usPort,
|
||||
matchmaking_ping_response* pRequestServersResponse)
|
||||
{
|
||||
auto response = pRequestServersResponse;
|
||||
const auto addr = network::address_from_ip(htonl(unIP), usPort);
|
||||
|
||||
party::query_server(
|
||||
addr, [response](const bool success, const game::netadr_t& host, const ::utils::info_string& info,
|
||||
const uint32_t ping)
|
||||
{
|
||||
if (success)
|
||||
{
|
||||
auto server_item = create_server_item(host, info, ping, success);
|
||||
response->ServerResponded(server_item);
|
||||
}
|
||||
else
|
||||
{
|
||||
response->ServerFailedToRespond();
|
||||
}
|
||||
});
|
||||
|
||||
return reinterpret_cast<void*>(static_cast<uint64_t>(7 + rand()));
|
||||
}
|
||||
|
||||
int matchmaking_servers::PlayerDetails(unsigned int unIP, unsigned short usPort, void* pRequestServersResponse)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int matchmaking_servers::ServerRules(unsigned int unIP, unsigned short usPort, void* pRequestServersResponse)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void matchmaking_servers::CancelServerQuery(int hServerQuery)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user