Profileinfo v2 (#114)
* profile info (todo) * fix path & server running check * temp progress * more progress idek i need xuids * profile info v2 * fix bdProfiles reading bad data * custom emblem storage + cleanup * tiny bit of progress but stalling in buffer read * stuff * small stuff * Update profile_infos.cpp * update * player xuid packet, stuff... kinda works? * works * cleanup * fix * cleanup * cleanup on aisle 2 --------- Co-authored-by: m <mjkzyalt@gmail.com>
This commit is contained in:
parent
c8a99d23c1
commit
08b4eec837
@ -4,9 +4,11 @@
|
||||
#include "network.hpp"
|
||||
|
||||
#include "game/game.hpp"
|
||||
#include "game/utils/fragment_handler.hpp"
|
||||
|
||||
#include "console/console.hpp"
|
||||
#include "dvars.hpp"
|
||||
#include "scheduler.hpp"
|
||||
|
||||
#include <utils/hook.hpp>
|
||||
#include <utils/string.hpp>
|
||||
@ -30,16 +32,27 @@ namespace network
|
||||
auto& callbacks = get_callbacks();
|
||||
const auto handler = callbacks.find(cmd_string);
|
||||
const auto offset = cmd_string.size() + 5;
|
||||
if (message->cursize < offset || handler == callbacks.end())
|
||||
if (message->cursize < 0 || static_cast<size_t>(message->cursize) < offset || handler == callbacks.end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::string_view data(message->data + offset, message->cursize - offset);
|
||||
const std::basic_string_view data(message->data + offset, message->cursize - offset);
|
||||
|
||||
//console::debug("[Network] Handling command %s\n", cmd_string.data());
|
||||
console::debug("[network] handling command \"%s\"\n", cmd_string.data());
|
||||
|
||||
try
|
||||
{
|
||||
handler->second(*address, data);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
printf("Error: %s\n", e.what());
|
||||
}
|
||||
//catch (...)
|
||||
//{
|
||||
//}
|
||||
|
||||
handler->second(*address, data);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -232,15 +245,14 @@ namespace network
|
||||
void send_data(const game::netadr_s& address, const std::string& data)
|
||||
{
|
||||
auto size = static_cast<int>(data.size());
|
||||
if (size > 1280)
|
||||
{
|
||||
console::error("Packet was too long. Truncated!\n");
|
||||
size = 1280;
|
||||
}
|
||||
|
||||
if (address.type == game::NA_LOOPBACK)
|
||||
{
|
||||
// TODO: Fix this for loopback
|
||||
if (size > 1280)
|
||||
{
|
||||
console::error("Packet was too long. Truncated!\n");
|
||||
size = 1280;
|
||||
}
|
||||
|
||||
game::NET_SendLoopPacket(game::NS_CLIENT1, size, data.data(), &address);
|
||||
}
|
||||
else
|
||||
@ -284,6 +296,8 @@ namespace network
|
||||
public:
|
||||
void post_unpack() override
|
||||
{
|
||||
scheduler::loop(game::fragment_handler::clean, scheduler::async, 5s);
|
||||
|
||||
// redirect dw packet sends to our stub
|
||||
utils::hook::jump(0xD942C0_b, dw_send_to_stub);
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "command.hpp"
|
||||
#include "console/console.hpp"
|
||||
#include "network.hpp"
|
||||
#include "profile_infos.hpp"
|
||||
#include "scheduler.hpp"
|
||||
|
||||
#include <utils/string.hpp>
|
||||
@ -21,12 +22,7 @@ namespace party
|
||||
{
|
||||
namespace
|
||||
{
|
||||
struct
|
||||
{
|
||||
game::netadr_s host{};
|
||||
std::string challenge{};
|
||||
bool hostDefined{ false };
|
||||
} connect_state;
|
||||
connection_state server_connection_state{};
|
||||
|
||||
bool preloaded_map = false;
|
||||
|
||||
@ -165,6 +161,8 @@ namespace party
|
||||
void sv_start_map_for_party_stub(const char* map, const char* game_type, int client_count, int agent_count, bool hardcore,
|
||||
bool map_is_preloaded, bool migrate)
|
||||
{
|
||||
profile_infos::xuid::clear_xuids();
|
||||
|
||||
preloaded_map = map_is_preloaded;
|
||||
sv_start_map_for_party_hook.invoke<void>(map, game_type, client_count, agent_count, hardcore, map_is_preloaded, migrate);
|
||||
}
|
||||
@ -196,7 +194,7 @@ namespace party
|
||||
a.popad64();
|
||||
|
||||
a.jmp(0xC563E2_b);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
void start_map(const std::string& mapname, bool dev)
|
||||
@ -313,26 +311,30 @@ namespace party
|
||||
|
||||
void connect(const game::netadr_s& target)
|
||||
{
|
||||
//command::execute("lui_open_popup popup_acceptinginvite", false);
|
||||
command::execute("luiOpenPopup AcceptingInvite", false);
|
||||
|
||||
connect_state.host = target;
|
||||
connect_state.challenge = utils::cryptography::random::get_challenge();
|
||||
connect_state.hostDefined = true;
|
||||
profile_infos::xuid::clear_xuids();
|
||||
profile_infos::clear_profile_infos();
|
||||
|
||||
network::send(target, "getInfo", connect_state.challenge);
|
||||
server_connection_state.host = target;
|
||||
server_connection_state.challenge = utils::cryptography::random::get_challenge();
|
||||
server_connection_state.hostDefined = true;
|
||||
|
||||
network::send(target, "getInfo", server_connection_state.challenge);
|
||||
}
|
||||
|
||||
void info_response_error(const std::string& error)
|
||||
{
|
||||
console::error("%s\n", error.data());
|
||||
//if (game::Menu_IsMenuOpenAndVisible(0, "popup_acceptinginvite"))
|
||||
//{
|
||||
// command::execute("lui_close popup_acceptinginvite", false);
|
||||
//}
|
||||
|
||||
command::execute("luiLeaveMenu AcceptingInvite", false);
|
||||
game::Com_SetLocalizedErrorMessage(error.data(), "MENU_NOTICE");
|
||||
}
|
||||
|
||||
connection_state get_server_connection_state()
|
||||
{
|
||||
return server_connection_state;
|
||||
}
|
||||
|
||||
class component final : public component_interface
|
||||
{
|
||||
public:
|
||||
@ -483,45 +485,45 @@ namespace party
|
||||
|
||||
network::on("infoResponse", [](const game::netadr_s& target, const std::string_view& data)
|
||||
{
|
||||
const utils::info_string info{ data };
|
||||
const utils::info_string info = data;
|
||||
//server_list::handle_info_response(target, info);
|
||||
|
||||
if (connect_state.host != target)
|
||||
if (server_connection_state.host != target)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (info.get("challenge") != connect_state.challenge)
|
||||
if (info.get("challenge") != server_connection_state.challenge)
|
||||
{
|
||||
info_response_error("Invalid challenge.");
|
||||
info_response_error("Connection failed: Invalid challenge.");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto gamename = info.get("gamename");
|
||||
if (gamename != "IW7"s)
|
||||
{
|
||||
info_response_error("Invalid gamename.");
|
||||
info_response_error("Connection failed: Invalid gamename.");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto playmode = info.get("playmode");
|
||||
if (game::GameModeType(std::atoi(playmode.data())) != game::Com_GameMode_GetActiveGameMode())
|
||||
{
|
||||
info_response_error("Invalid playmode.");
|
||||
info_response_error("Connection failed: Invalid playmode.");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto sv_running = info.get("sv_running");
|
||||
if (!std::atoi(sv_running.data()))
|
||||
{
|
||||
info_response_error("Server not running.");
|
||||
info_response_error("Connection failed: Server not running.");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto mapname = info.get("mapname");
|
||||
if (mapname.empty())
|
||||
{
|
||||
info_response_error("Invalid map.");
|
||||
info_response_error("Connection failed: Invalid map.");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -536,12 +538,21 @@ namespace party
|
||||
const auto sv_maxclients = std::atoi(sv_maxclients_str.data());
|
||||
if (!sv_maxclients)
|
||||
{
|
||||
info_response_error("Invalid sv_maxclients.");
|
||||
info_response_error("Connection failed: Invalid sv_maxclients.");
|
||||
return;
|
||||
}
|
||||
|
||||
//party::sv_motd = info.get("sv_motd");
|
||||
//party::sv_maxclients = std::stoi(info.get("sv_maxclients"));
|
||||
server_connection_state.motd = info.get("sv_motd");
|
||||
server_connection_state.max_clients = std::stoi(sv_maxclients_str);
|
||||
|
||||
const auto profile_info = profile_infos::get_profile_info();
|
||||
if (!profile_info.has_value())
|
||||
{
|
||||
console::error("profile_info has no value to send, possible undefined behavior ahead\n");
|
||||
}
|
||||
|
||||
const auto profile_info_value = profile_info.value_or(profile_infos::profile_info{});
|
||||
profile_infos::send_profile_info(target, steam::SteamUser()->GetSteamID().bits, profile_info_value);
|
||||
|
||||
connect_to_party(target, mapname, gametype, sv_maxclients);
|
||||
});
|
||||
|
@ -3,17 +3,21 @@
|
||||
|
||||
namespace party
|
||||
{
|
||||
void info_response_error(const std::string& error);
|
||||
struct connection_state
|
||||
{
|
||||
game::netadr_s host;
|
||||
std::string challenge;
|
||||
bool hostDefined;
|
||||
std::string motd;
|
||||
int max_clients;
|
||||
};
|
||||
|
||||
void reset_connect_state();
|
||||
void info_response_error(const std::string& error);
|
||||
|
||||
void connect(const game::netadr_s& target);
|
||||
void start_map(const std::string& mapname, bool dev = false);
|
||||
|
||||
void clear_sv_motd();
|
||||
game::netadr_s get_state_host();
|
||||
std::string get_state_challenge();
|
||||
int server_client_count();
|
||||
connection_state get_server_connection_state();
|
||||
|
||||
int get_client_num_by_name(const std::string& name);
|
||||
|
||||
|
426
src/client/component/profile_infos.cpp
Normal file
426
src/client/component/profile_infos.cpp
Normal file
@ -0,0 +1,426 @@
|
||||
#include <std_include.hpp>
|
||||
#include "loader/component_loader.hpp"
|
||||
|
||||
#include "../steam/steam.hpp"
|
||||
|
||||
#include "dvars.hpp"
|
||||
#include "console/console.hpp"
|
||||
#include "network.hpp"
|
||||
#include "party.hpp"
|
||||
#include "profile_infos.hpp"
|
||||
|
||||
#include <utils/concurrency.hpp>
|
||||
#include <utils/io.hpp>
|
||||
#include <utils/hook.hpp>
|
||||
|
||||
#include "game/utils/fragment_handler.hpp"
|
||||
|
||||
namespace profile_infos
|
||||
{
|
||||
namespace
|
||||
{
|
||||
using profile_map = std::unordered_map<std::uint64_t, profile_info>;
|
||||
utils::concurrency::container<profile_map, std::recursive_mutex> profile_mapping{};
|
||||
|
||||
std::optional<profile_info> load_profile_info()
|
||||
{
|
||||
std::string data{};
|
||||
if (!utils::io::read_file("players2/user/profile_info", &data))
|
||||
{
|
||||
console::error("[load_profile_info] failed to load profile_info for self!\n");
|
||||
return {};
|
||||
}
|
||||
|
||||
profile_info info{};
|
||||
info.m_memberplayer_card.assign(data);
|
||||
|
||||
return {std::move(info)};
|
||||
}
|
||||
|
||||
std::unordered_set<std::uint64_t> get_connected_client_xuids()
|
||||
{
|
||||
if (!game::Com_IsAnyLocalServerRunning()) // is_host()
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
std::unordered_set<std::uint64_t> xuids{};
|
||||
|
||||
const auto* svs_clients = *game::svs_clients;
|
||||
for (unsigned int i = 0; i < *game::svs_numclients; ++i)
|
||||
{
|
||||
if (svs_clients[i].header.state >= 1)
|
||||
{
|
||||
xuids.emplace(xuid::get_client_xuid(i));
|
||||
}
|
||||
}
|
||||
|
||||
return xuids;
|
||||
}
|
||||
|
||||
void set_playercardcache_to_download(const std::uint64_t user_id)
|
||||
{
|
||||
game::XUID xuid{ user_id };
|
||||
game::PlayercardCache_AddToDownload(0, xuid);
|
||||
*game::g_DWPlayercardCacheDownloadTaskStage = game::PLAYERCARD_CACHE_TASK_STAGE_WAITING;
|
||||
}
|
||||
|
||||
void set_client_xuid_to_session(game::SessionData* session, const std::uint32_t client_index)
|
||||
{
|
||||
session->dyn.users[client_index].xuid = xuid::get_client_xuid(client_index);
|
||||
}
|
||||
}
|
||||
|
||||
profile_info::profile_info(utils::byte_buffer& buffer)
|
||||
{
|
||||
this->m_memberplayer_card = buffer.read_string();
|
||||
}
|
||||
|
||||
void profile_info::serialize(utils::byte_buffer& buffer) const
|
||||
{
|
||||
buffer.write_string(this->m_memberplayer_card);
|
||||
}
|
||||
|
||||
void clear_profile_infos()
|
||||
{
|
||||
profile_mapping.access([](profile_map& profiles)
|
||||
{
|
||||
profiles.clear();
|
||||
});
|
||||
}
|
||||
|
||||
void remove_profile_info(const std::uint64_t user_id)
|
||||
{
|
||||
profile_mapping.access([user_id](profile_map& profiles)
|
||||
{
|
||||
for (auto i = profiles.begin(); i != profiles.end();)
|
||||
{
|
||||
if (i->first == user_id)
|
||||
{
|
||||
i = profiles.erase(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
i++;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void remove_profile_info_by_client_index(const std::uint32_t client_index)
|
||||
{
|
||||
const auto user_id = xuid::get_client_xuid(client_index);
|
||||
if (!user_id)
|
||||
{
|
||||
return;
|
||||
}
|
||||
remove_profile_info(user_id);
|
||||
}
|
||||
|
||||
void send_profile_info(const game::netadr_s& address, const std::string& data)
|
||||
{
|
||||
game::fragment_handler::fragment_data(data.data(), data.size(), [&address](const utils::byte_buffer& buffer)
|
||||
{
|
||||
network::send(address, "profileInfo", buffer.get_buffer());
|
||||
});
|
||||
}
|
||||
|
||||
void send_profile_info(const game::netadr_s& address, const std::uint64_t user_id, const profile_info& info)
|
||||
{
|
||||
utils::byte_buffer buffer{};
|
||||
buffer.write(user_id);
|
||||
info.serialize(buffer);
|
||||
|
||||
const std::string data = buffer.move_buffer();
|
||||
|
||||
send_profile_info(address, data);
|
||||
}
|
||||
|
||||
std::optional<profile_info> get_profile_info()
|
||||
{
|
||||
return load_profile_info();
|
||||
}
|
||||
|
||||
std::optional<profile_info> get_profile_info(const uint64_t user_id)
|
||||
{
|
||||
const auto my_xuid = steam::SteamUser()->GetSteamID().bits;
|
||||
if (user_id == my_xuid)
|
||||
{
|
||||
return get_profile_info();
|
||||
}
|
||||
|
||||
return profile_mapping.access<std::optional<profile_info>>([user_id](profile_map& profiles)
|
||||
{
|
||||
std::optional<profile_info> result{};
|
||||
|
||||
const auto profile_entry = profiles.find(user_id);
|
||||
if (profile_entry != profiles.end())
|
||||
{
|
||||
result = profile_entry->second;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
else
|
||||
{
|
||||
console::error("[get_profile_info] requesting profile info for %llX (bad)\n", user_id);
|
||||
}
|
||||
#endif
|
||||
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
void update_profile_info(const profile_info& info)
|
||||
{
|
||||
std::string data{};
|
||||
data.reserve(info.m_memberplayer_card.size());
|
||||
data.append(info.m_memberplayer_card);
|
||||
utils::io::write_file("players2/user/profile_info", data);
|
||||
}
|
||||
|
||||
void send_all_profile_infos(const game::netadr_s& sender_addr)
|
||||
{
|
||||
profile_mapping.access([&](const profile_map& profiles)
|
||||
{
|
||||
for (const auto& entry : profiles)
|
||||
{
|
||||
send_profile_info(sender_addr, entry.first, entry.second);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void send_profile_info_to_all_clients(const std::uint64_t user_id, const profile_info& info)
|
||||
{
|
||||
const auto* svs_clients = *game::svs_clients;
|
||||
for (unsigned int i = 0; i < *game::svs_numclients; ++i)
|
||||
{
|
||||
if (svs_clients[i].header.state >= 1 && !game::SV_BotIsBot(i) && !game::Session_IsHost(game::SV_MainMP_GetServerLobby(), i))
|
||||
{
|
||||
send_profile_info(svs_clients[i].remoteAddress, user_id, info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void send_self_profile(const game::netadr_s& addr)
|
||||
{
|
||||
const auto* svs_clients = *game::svs_clients;
|
||||
for (unsigned int i = 0; i < *game::svs_numclients; ++i)
|
||||
{
|
||||
if (svs_clients[i].header.state >= 1 && !game::SV_BotIsBot(i) && game::Session_IsHost(game::SV_MainMP_GetServerLobby(), i))
|
||||
{
|
||||
assert(i == 0);
|
||||
|
||||
auto self = load_profile_info();
|
||||
if (self.has_value())
|
||||
{
|
||||
send_profile_info(addr, xuid::get_client_xuid(i), self.value());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void add_profile_info(const game::netadr_s& sender_addr, const std::uint64_t user_id, const profile_info& info)
|
||||
{
|
||||
if (user_id == steam::SteamUser()->GetSteamID().bits)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (game::Com_IsAnyLocalServerRunning()) // is_host()
|
||||
{
|
||||
send_all_profile_infos(sender_addr); // send all stored profile infos to the new player
|
||||
|
||||
if (!game::environment::is_dedi())
|
||||
{
|
||||
send_self_profile(sender_addr); // send self profile info to the new player too
|
||||
}
|
||||
|
||||
// send new player info to all clients
|
||||
send_profile_info_to_all_clients(user_id, info);
|
||||
}
|
||||
|
||||
profile_mapping.access([&](profile_map& profiles)
|
||||
{
|
||||
profiles[user_id] = info;
|
||||
});
|
||||
}
|
||||
|
||||
namespace xuid
|
||||
{
|
||||
client_xuid_array client_xuids{};
|
||||
|
||||
void add_client_xuid(const std::uint32_t& client_index, const std::uint64_t& xuid)
|
||||
{
|
||||
if (client_xuids[client_index] && client_xuids[client_index] != xuid)
|
||||
{
|
||||
remove_profile_info(client_xuids[client_index]); // remove profile if it exists
|
||||
}
|
||||
|
||||
client_xuids[client_index] = xuid;
|
||||
|
||||
set_client_xuid_to_session(game::SV_MainMP_GetServerLobby(), client_index);
|
||||
}
|
||||
|
||||
std::uint64_t get_client_xuid(const std::uint32_t& client_index)
|
||||
{
|
||||
if (client_xuids[client_index])
|
||||
{
|
||||
// returns xuid for player. this must be on both the client & server
|
||||
// client recieves data for this via playerXuid packet
|
||||
return client_xuids[client_index];
|
||||
}
|
||||
|
||||
return static_cast<std::uint64_t>(0);
|
||||
}
|
||||
|
||||
void remove_client_xuid(const std::uint32_t& client_index)
|
||||
{
|
||||
client_xuids[client_index] = 0;
|
||||
}
|
||||
|
||||
void clear_xuids()
|
||||
{
|
||||
for (auto& xuid : client_xuids)
|
||||
{
|
||||
xuid = 0;
|
||||
}
|
||||
}
|
||||
|
||||
client_xuid_array get_xuids()
|
||||
{
|
||||
return client_xuids;
|
||||
}
|
||||
|
||||
void send_xuid(const game::netadr_s& addr, const std::uint64_t xuid, const std::uint32_t client_index)
|
||||
{
|
||||
utils::byte_buffer buffer{};
|
||||
buffer.write(client_index);
|
||||
buffer.write(xuid);
|
||||
|
||||
const std::string data = buffer.move_buffer();
|
||||
|
||||
game::fragment_handler::fragment_data(data.data(), data.size(), [&](const utils::byte_buffer& buffer)
|
||||
{
|
||||
network::send(addr, "playerXuid", buffer.get_buffer());
|
||||
});
|
||||
}
|
||||
|
||||
void send_xuid_to_all_clients(const std::uint64_t xuid, const std::uint32_t& client_index)
|
||||
{
|
||||
const auto* svs_clients = *game::svs_clients;
|
||||
for (unsigned int i = 0; i < *game::svs_numclients; ++i)
|
||||
{
|
||||
if (svs_clients[i].header.state >= 1 && !game::SV_BotIsBot(i) && !game::Session_IsHost(game::SV_MainMP_GetServerLobby(), i))
|
||||
{
|
||||
send_xuid(svs_clients[i].remoteAddress, xuid, client_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void send_all_xuids(const game::netadr_s& addr)
|
||||
{
|
||||
int i = 0;
|
||||
for (const auto xuid : xuid::get_xuids())
|
||||
{
|
||||
if (xuid == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
send_xuid(addr, xuid, i++);
|
||||
}
|
||||
|
||||
if (!game::environment::is_dedi())
|
||||
{
|
||||
// send self xuid here too
|
||||
send_xuid(addr, steam::SteamUser()->GetSteamID().bits, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
utils::hook::detour client_connect_hook;
|
||||
const char* client_connect_stub(int client_num, unsigned __int16 script_pers_id)
|
||||
{
|
||||
auto result = client_connect_hook.invoke<const char*>(client_num, script_pers_id);
|
||||
|
||||
const auto client = game::svs_clients[client_num];
|
||||
std::uint64_t xuid{};
|
||||
game::StringToXUID(client->playerGuid, &xuid);
|
||||
|
||||
xuid::add_client_xuid(client_num, xuid); // add to self
|
||||
|
||||
// don't send if client is self
|
||||
if (client_num == 0 && !game::environment::is_dedi() && game::Com_IsAnyLocalServerRunning())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
xuid::send_xuid_to_all_clients(xuid, client_num); // add to all connected
|
||||
xuid::send_all_xuids(client->remoteAddress);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
utils::hook::detour session_unregister_remote_player_hook;
|
||||
void session_unregister_remote_player_stub(game::SessionData* session, const int slot)
|
||||
{
|
||||
session_unregister_remote_player_hook.invoke<void>(session, slot);
|
||||
|
||||
set_client_xuid_to_session(game::SV_MainMP_GetServerLobby(), slot);
|
||||
}
|
||||
}
|
||||
|
||||
class component final : public component_interface
|
||||
{
|
||||
public:
|
||||
void post_unpack() override
|
||||
{
|
||||
client_connect_hook.create(0xAFFF10_b, client_connect_stub);
|
||||
session_unregister_remote_player_hook.create(0xC73970_b, session_unregister_remote_player_stub);
|
||||
|
||||
dvars::override::register_int("playercard_cache_validity_life", 5000, 0, 3600000, 0x0); // 5sec
|
||||
|
||||
network::on("profileInfo", [](const game::netadr_s& client_addr, const std::string_view& data)
|
||||
{
|
||||
utils::byte_buffer buffer(data);
|
||||
std::string final_packet{};
|
||||
if (game::fragment_handler::handle(client_addr, buffer, final_packet))
|
||||
{
|
||||
buffer = utils::byte_buffer(final_packet);
|
||||
|
||||
const auto user_id = buffer.read<uint64_t>();
|
||||
|
||||
const profile_info info(buffer);
|
||||
add_profile_info(client_addr, user_id, info);
|
||||
set_playercardcache_to_download(user_id);
|
||||
}
|
||||
});
|
||||
|
||||
network::on("playerXuid", [](const game::netadr_s& server_addr, const std::string_view& data)
|
||||
{
|
||||
utils::byte_buffer buffer(data);
|
||||
std::string final_packet{};
|
||||
if (!game::fragment_handler::handle(server_addr, buffer, final_packet))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
buffer = utils::byte_buffer(final_packet);
|
||||
|
||||
const auto client_index = buffer.read<std::uint32_t>();
|
||||
const auto xuid = buffer.read<std::uint64_t>();
|
||||
|
||||
if (!game::Com_IsAnyLocalServerRunning() && server_addr.addr != party::get_server_connection_state().host.addr)
|
||||
{
|
||||
console::debug("playerXuid call from an unknown address\n");
|
||||
return;
|
||||
}
|
||||
|
||||
xuid::add_client_xuid(client_index, xuid);
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
REGISTER_COMPONENT(profile_infos::component)
|
33
src/client/component/profile_infos.hpp
Normal file
33
src/client/component/profile_infos.hpp
Normal file
@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#include <game/game.hpp>
|
||||
#include <utils/byte_buffer.hpp>
|
||||
|
||||
namespace profile_infos
|
||||
{
|
||||
namespace xuid
|
||||
{
|
||||
using client_xuid_array = std::array<std::uint64_t, 18>;
|
||||
std::uint64_t get_client_xuid(const std::uint32_t& client_index);
|
||||
void clear_xuids();
|
||||
client_xuid_array get_xuids();
|
||||
}
|
||||
|
||||
struct profile_info
|
||||
{
|
||||
std::string m_memberplayer_card{};
|
||||
|
||||
profile_info() = default;
|
||||
profile_info(utils::byte_buffer& buffer);
|
||||
void serialize(utils::byte_buffer& buffer) const;
|
||||
};
|
||||
|
||||
void clear_profile_infos();
|
||||
|
||||
void send_profile_info(const game::netadr_s& address, const std::uint64_t user_id, const profile_info& info);
|
||||
|
||||
std::optional<profile_info> get_profile_info();
|
||||
std::optional<profile_info> get_profile_info(const uint64_t user_id);
|
||||
|
||||
void update_profile_info(const profile_info& info);
|
||||
}
|
@ -1,5 +1,4 @@
|
||||
#pragma once
|
||||
#include "dw_include.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
@ -243,4 +242,122 @@ namespace demonware
|
||||
buffer->read_blob(&this->data);
|
||||
}
|
||||
};
|
||||
|
||||
class bdContextUserStorageFileInfo final : public bdTaskResult
|
||||
{
|
||||
public:
|
||||
std::uint32_t create_time;
|
||||
std::uint32_t modifed_time;
|
||||
bool priv;
|
||||
std::uint64_t owner_id;
|
||||
std::string account_type;
|
||||
std::string filename;
|
||||
|
||||
void serialize(byte_buffer* buffer) override
|
||||
{
|
||||
buffer->write_uint32(this->create_time);
|
||||
buffer->write_uint32(this->modifed_time);
|
||||
buffer->write_bool(this->priv);
|
||||
buffer->write_uint64(this->owner_id);
|
||||
buffer->write_string(this->account_type);
|
||||
buffer->write_string(this->filename);
|
||||
}
|
||||
|
||||
void deserialize(byte_buffer* buffer) override
|
||||
{
|
||||
buffer->read_uint32(&this->create_time);
|
||||
buffer->read_uint32(&this->modifed_time);
|
||||
buffer->read_bool(&this->priv);
|
||||
buffer->read_uint64(&this->owner_id);
|
||||
buffer->read_string(&this->account_type);
|
||||
buffer->read_string(&this->filename);
|
||||
}
|
||||
};
|
||||
|
||||
class bdPublicProfileInfo final : public bdTaskResult
|
||||
{
|
||||
public:
|
||||
std::uint64_t m_entityID;
|
||||
std::string m_memberplayer_card;
|
||||
|
||||
void serialize(byte_buffer* buffer) override
|
||||
{
|
||||
buffer->write_uint64(this->m_entityID);
|
||||
buffer->write_blob(this->m_memberplayer_card);
|
||||
}
|
||||
|
||||
void deserialize(byte_buffer* buffer) override
|
||||
{
|
||||
buffer->read_uint64(&this->m_entityID);
|
||||
buffer->read_blob(&this->m_memberplayer_card);
|
||||
}
|
||||
};
|
||||
|
||||
class bdSessionID final : public bdTaskResult
|
||||
{
|
||||
public:
|
||||
uint64_t session_id;
|
||||
|
||||
void serialize(byte_buffer* buffer) override
|
||||
{
|
||||
buffer->write_blob(LPSTR(&this->session_id), sizeof this->session_id);
|
||||
}
|
||||
|
||||
void deserialize(byte_buffer* buffer) override
|
||||
{
|
||||
int size{};
|
||||
char* data{};
|
||||
buffer->read_blob(&data, &size);
|
||||
|
||||
if (data && uint32_t(size) >= sizeof(this->session_id))
|
||||
{
|
||||
this->session_id = *reinterpret_cast<uint64_t*>(data);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class bdMatchMakingInfo final : bdTaskResult
|
||||
{
|
||||
bdSessionID m_sessionID;
|
||||
std::string m_hostAddr;
|
||||
uint32_t m_hostAddrSize;
|
||||
uint32_t m_gameType;
|
||||
uint32_t m_maxPlayers;
|
||||
uint32_t m_numPlayers;
|
||||
|
||||
void serialize(byte_buffer* buffer) override
|
||||
{
|
||||
buffer->write_blob(this->m_hostAddr);
|
||||
this->m_sessionID.serialize(buffer);
|
||||
buffer->write_uint32(this->m_gameType);
|
||||
buffer->write_uint32(this->m_maxPlayers);
|
||||
buffer->write_uint32(this->m_numPlayers);
|
||||
}
|
||||
|
||||
void deserialize(byte_buffer* buffer) override
|
||||
{
|
||||
buffer->read_blob(&this->m_hostAddr);
|
||||
buffer->read_uint32(&this->m_gameType);
|
||||
buffer->read_uint32(&this->m_maxPlayers);
|
||||
}
|
||||
};
|
||||
|
||||
class bdPerformanceValue final : public bdTaskResult
|
||||
{
|
||||
public:
|
||||
uint64_t user_id;
|
||||
int64_t performance;
|
||||
|
||||
void serialize(byte_buffer* buffer) override
|
||||
{
|
||||
buffer->write_uint64(this->user_id);
|
||||
buffer->write_int64(this->performance);
|
||||
}
|
||||
|
||||
void deserialize(byte_buffer* buffer) override
|
||||
{
|
||||
buffer->read_uint64(&this->user_id);
|
||||
buffer->read_int64(&this->performance);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include <utils/string.hpp>
|
||||
|
||||
#include "servers/service_server.hpp"
|
||||
|
||||
namespace demonware
|
||||
|
@ -1,6 +1,8 @@
|
||||
#include <std_include.hpp>
|
||||
#include "../dw_include.hpp"
|
||||
|
||||
#include "steam/steam.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
bdMatchMaking::bdMatchMaking() : service(138, "bdMatchMaking")
|
||||
@ -24,8 +26,11 @@ namespace demonware
|
||||
|
||||
void bdMatchMaking::createSession(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto id = std::make_unique<bdSessionID>();
|
||||
id->session_id = steam::SteamUser()->GetSteamID().bits;
|
||||
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply.add(id);
|
||||
reply.send();
|
||||
}
|
||||
|
||||
@ -36,9 +41,14 @@ namespace demonware
|
||||
reply.send();
|
||||
}
|
||||
|
||||
void bdMatchMaking::deleteSession(service_server* server, byte_buffer* /*buffer*/) const
|
||||
void bdMatchMaking::deleteSession(service_server* server, byte_buffer* buffer) const
|
||||
{
|
||||
// TODO:
|
||||
bdSessionID id;
|
||||
id.deserialize(buffer);
|
||||
|
||||
byte_buffer out_data;
|
||||
id.serialize(&out_data);
|
||||
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply.send();
|
||||
}
|
||||
@ -59,8 +69,12 @@ namespace demonware
|
||||
|
||||
void bdMatchMaking::getPerformanceValues(service_server* server, byte_buffer* /*buffer*/) const
|
||||
{
|
||||
// TODO:
|
||||
auto result = std::make_unique<bdPerformanceValue>();
|
||||
result->user_id = steam::SteamUser()->GetSteamID().bits;
|
||||
result->performance = 10;
|
||||
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply.add(result);
|
||||
reply.send();
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
#include <std_include.hpp>
|
||||
#include "../dw_include.hpp"
|
||||
|
||||
#include "../../../component/profile_infos.hpp"
|
||||
|
||||
namespace demonware
|
||||
{
|
||||
bdProfiles::bdProfiles() : service(8, "bdProfiles")
|
||||
@ -15,16 +17,40 @@ namespace demonware
|
||||
this->register_task(8, &bdProfiles::setPublicInfoByUserID);
|
||||
}
|
||||
|
||||
void bdProfiles::getPublicInfos(service_server* server, byte_buffer* /*buffer*/) const
|
||||
void bdProfiles::getPublicInfos(service_server* server, byte_buffer* buffer) const
|
||||
{
|
||||
// TODO:
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
std::vector<std::pair<std::uint64_t, profile_infos::profile_info>> profile_infos{};
|
||||
|
||||
std::uint64_t entity_id;
|
||||
while (buffer->read_uint64(&entity_id))
|
||||
{
|
||||
auto profile = profile_infos::get_profile_info(entity_id);
|
||||
if (profile)
|
||||
{
|
||||
profile_infos.emplace_back(entity_id, std::move(*profile));
|
||||
}
|
||||
}
|
||||
|
||||
auto reply = server->create_reply(this->task_id(), profile_infos.empty() ? game::BD_NO_PROFILE_INFO_EXISTS : game::BD_NO_ERROR);
|
||||
|
||||
for (auto& info : profile_infos)
|
||||
{
|
||||
auto result = std::make_unique<bdPublicProfileInfo>();
|
||||
result->m_entityID = info.first;
|
||||
result->m_memberplayer_card = std::move(info.second.m_memberplayer_card);
|
||||
|
||||
reply.add(result);
|
||||
}
|
||||
|
||||
reply.send();
|
||||
}
|
||||
|
||||
void bdProfiles::setPublicInfo(service_server* server, byte_buffer* /*buffer*/) const
|
||||
void bdProfiles::setPublicInfo(service_server* server, byte_buffer* buffer) const
|
||||
{
|
||||
// TODO:
|
||||
profile_infos::profile_info info{};
|
||||
buffer->read_blob(&info.m_memberplayer_card);
|
||||
profile_infos::update_profile_info(info);
|
||||
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
reply.send();
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ namespace demonware
|
||||
this->register_task(20, &bdStorage::listAllPublisherFiles);
|
||||
this->register_task(21, &bdStorage::getPublisherFile);
|
||||
this->register_task(24, &bdStorage::uploadAndValidateFiles);
|
||||
this->register_task(18, &bdStorage::uploadFiles);
|
||||
this->register_task(16, &bdStorage::getFiles);
|
||||
this->register_task(12, &bdStorage::getFile);
|
||||
|
||||
@ -173,6 +174,51 @@ namespace demonware
|
||||
info->filename = filename;
|
||||
info->data = data;
|
||||
|
||||
#ifdef DW_DEBUG
|
||||
printf("[DW]: [bdStorage]: set user file: %s\n", filename.data());
|
||||
#endif
|
||||
|
||||
reply.add(info);
|
||||
}
|
||||
|
||||
reply.send();
|
||||
}
|
||||
|
||||
void bdStorage::uploadFiles(service_server* server, byte_buffer* buffer) const
|
||||
{
|
||||
std::string game, platform;
|
||||
std::uint64_t owner;
|
||||
std::uint32_t numfiles;
|
||||
|
||||
buffer->read_string(&game);
|
||||
buffer->read_uint64(&owner);
|
||||
buffer->read_string(&platform);
|
||||
buffer->read_uint32(&numfiles);
|
||||
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
|
||||
for (uint32_t i = 0; i < numfiles; i++)
|
||||
{
|
||||
std::string filename, data;
|
||||
std::uint32_t version;
|
||||
bool priv;
|
||||
|
||||
buffer->read_string(&filename);
|
||||
buffer->read_blob(&data);
|
||||
buffer->read_uint32(&version);
|
||||
buffer->read_bool(&priv);
|
||||
|
||||
const auto path = get_user_file_path(filename);
|
||||
utils::io::write_file(path, data);
|
||||
|
||||
auto info = std::make_unique<bdContextUserStorageFileInfo>();
|
||||
info->modifed_time = static_cast<uint32_t>(time(nullptr));
|
||||
info->create_time = info->modifed_time;
|
||||
info->priv = priv;
|
||||
info->owner_id = owner;
|
||||
info->account_type = platform;
|
||||
info->filename = filename;
|
||||
|
||||
#ifdef DW_DEBUG
|
||||
printf("[DW]: [bdStorage]: set user file: %s\n", filename.data());
|
||||
#endif
|
||||
@ -186,26 +232,26 @@ namespace demonware
|
||||
void bdStorage::getFiles(service_server* server, byte_buffer* buffer) const
|
||||
{
|
||||
std::string platform;
|
||||
uint32_t numunk;
|
||||
uint32_t numfiles;
|
||||
uint32_t num_users;
|
||||
uint32_t num_files;
|
||||
uint64_t user_id = 0;
|
||||
std::string game;
|
||||
|
||||
buffer->read_string(&platform);
|
||||
buffer->read_uint32(&numunk);
|
||||
buffer->read_uint32(&num_users);
|
||||
|
||||
for (uint32_t i = 0; i < numunk; i++)
|
||||
for (uint32_t i = 0; i < num_users; i++)
|
||||
{
|
||||
buffer->read_uint64(&user_id);
|
||||
buffer->read_string(&game);
|
||||
}
|
||||
|
||||
buffer->read_uint32(&numfiles);
|
||||
buffer->read_uint32(&num_files);
|
||||
|
||||
auto reply = server->create_reply(this->task_id());
|
||||
|
||||
uint32_t count = 0;
|
||||
for (uint32_t i = 0; i < numfiles; i++)
|
||||
for (uint32_t i = 0; i < num_files; i++)
|
||||
{
|
||||
std::string filename, data;
|
||||
buffer->read_string(&filename);
|
||||
|
@ -7,6 +7,8 @@ namespace demonware
|
||||
public:
|
||||
bdStorage();
|
||||
|
||||
static std::string get_user_file_path(const std::string& name);
|
||||
|
||||
private:
|
||||
using callback = std::function<std::string()>;
|
||||
using resource_variant = std::variant<std::string, callback>;
|
||||
@ -19,9 +21,8 @@ namespace demonware
|
||||
void listAllPublisherFiles(service_server* server, byte_buffer* buffer);
|
||||
void getPublisherFile(service_server* server, byte_buffer* buffer);
|
||||
void uploadAndValidateFiles(service_server* server, byte_buffer* buffer) const;
|
||||
void uploadFiles(service_server* server, byte_buffer* buffer) const;
|
||||
void getFiles(service_server* server, byte_buffer* buffer) const;
|
||||
void getFile(service_server* server, byte_buffer* buffer) const;
|
||||
|
||||
static std::string get_user_file_path(const std::string& name);
|
||||
};
|
||||
}
|
||||
|
@ -1,19 +1,16 @@
|
||||
#pragma once
|
||||
#include "types/database.hpp"
|
||||
#include "types/ddl.hpp"
|
||||
#include "types/demonware.hpp"
|
||||
#include "types/party.hpp"
|
||||
#include "types/pmem.hpp"
|
||||
#include "types/sv.hpp"
|
||||
|
||||
namespace game
|
||||
{
|
||||
using namespace database;
|
||||
using namespace ddl;
|
||||
using namespace demonware;
|
||||
using namespace party;
|
||||
using namespace pmem;
|
||||
using namespace sv;
|
||||
|
||||
struct XUID
|
||||
{
|
||||
std::uint64_t m_id;
|
||||
};
|
||||
|
||||
enum GameModeType : std::uint32_t
|
||||
{
|
||||
@ -27,6 +24,7 @@ namespace game
|
||||
{
|
||||
FEATURE_GRAVITY = 33,
|
||||
FEATURE_TIMESCALE = 69,
|
||||
FEATURE_RANDOM_PLAYERCARD_WHEN_MISSING = 163,
|
||||
};
|
||||
|
||||
enum Sys_Folder
|
||||
@ -392,7 +390,11 @@ namespace game
|
||||
struct netadr_s
|
||||
{
|
||||
netadrtype_t type;
|
||||
unsigned char ip[4];
|
||||
union
|
||||
{
|
||||
unsigned char ip[4];
|
||||
uint32_t addr;
|
||||
};
|
||||
unsigned __int16 port;
|
||||
netsrc_t localNetID;
|
||||
unsigned int addrHandleIndex;
|
||||
@ -500,8 +502,13 @@ namespace game
|
||||
struct entityState_t
|
||||
{
|
||||
__int16 number; // 0
|
||||
char __pad0[150];
|
||||
int surfType;
|
||||
int clientNum;
|
||||
}; // sizeof = ?
|
||||
|
||||
assert_offsetof(entityState_t, clientNum, 156);
|
||||
|
||||
struct gclient_s
|
||||
{
|
||||
char __pad0[19376];
|
||||
@ -547,14 +554,16 @@ namespace game
|
||||
struct client_t
|
||||
{
|
||||
clientHeader_t header; // 0
|
||||
char __pad0[120];
|
||||
char __pad0[120]; // 16
|
||||
gentity_s* gentity; // 136
|
||||
char __pad1[20];
|
||||
char userinfo[1024];
|
||||
char name[32]; // 1188
|
||||
char __pad2[648396];
|
||||
char __pad2[648396]; // 1220
|
||||
netadr_s remoteAddress; // 649616
|
||||
char __pad3[65780];
|
||||
char __pad5[2460]; // 649636
|
||||
char playerGuid[21]; // 652096
|
||||
char __pad6[63299]; // 652117
|
||||
}; static_assert(sizeof(client_t) == 715416);
|
||||
|
||||
static_assert(offsetof(client_t, header.state) == 8);
|
||||
@ -562,6 +571,7 @@ namespace game
|
||||
static_assert(offsetof(client_t, userinfo) == 164);
|
||||
static_assert(offsetof(client_t, name) == 1188);
|
||||
static_assert(offsetof(client_t, remoteAddress) == 649616);
|
||||
static_assert(offsetof(client_t, playerGuid) == 652096);
|
||||
}
|
||||
using namespace entity;
|
||||
|
||||
@ -788,4 +798,254 @@ namespace game
|
||||
unsigned __int16 childVariableBucket[65536];
|
||||
ChildVariableValue childVariableValue[384000];
|
||||
};
|
||||
|
||||
enum PLAYERCARD_CACHE_TASK_STAGE
|
||||
{
|
||||
PLAYERCARD_CACHE_TASK_STAGE_WAITING = 0x0,
|
||||
PLAYERCARD_CACHE_TASK_STAGE_WORKING = 0x1,
|
||||
PLAYERCARD_CACHE_TASK_STAGE_ALL_DONE = 0x2,
|
||||
};
|
||||
|
||||
struct CachedPlayerProfile
|
||||
{
|
||||
bool has_data;
|
||||
XUID userID;
|
||||
char profile[2201];
|
||||
int time;
|
||||
};
|
||||
|
||||
namespace ddl
|
||||
{
|
||||
enum DDLType
|
||||
{
|
||||
DDL_INVALID_TYPE = 0xFFFFFFFF,
|
||||
DDL_BYTE_TYPE = 0x0,
|
||||
DDL_SHORT_TYPE = 0x1,
|
||||
DDL_UINT_TYPE = 0x2,
|
||||
DDL_INT_TYPE = 0x3,
|
||||
DDL_UINT64_TYPE = 0x4,
|
||||
DDL_FLOAT_TYPE = 0x5,
|
||||
DDL_FIXEDPOINT_TYPE = 0x6,
|
||||
DDL_STRING_TYPE = 0x7,
|
||||
DDL_STRUCT_TYPE = 0x8,
|
||||
DDL_ENUM_TYPE = 0x9,
|
||||
};
|
||||
|
||||
union DDLValue
|
||||
{
|
||||
int intValue;
|
||||
unsigned int uintValue;
|
||||
unsigned __int64 uint64Value;
|
||||
float floatValue;
|
||||
float fixedPointValue;
|
||||
const char* stringPtr;
|
||||
};
|
||||
|
||||
struct DDLMember
|
||||
{
|
||||
const char* name;
|
||||
int index;
|
||||
int bitSize;
|
||||
int limitSize;
|
||||
int offset;
|
||||
int type;
|
||||
int externalIndex;
|
||||
unsigned int rangeLimit;
|
||||
bool isArray;
|
||||
int arraySize;
|
||||
int enumIndex;
|
||||
};
|
||||
|
||||
struct DDLState
|
||||
{
|
||||
bool isValid;
|
||||
int offset;
|
||||
int arrayIndex;
|
||||
DDLMember* member;
|
||||
//const DDLDef* ddlDef;
|
||||
};
|
||||
|
||||
struct DDLContext
|
||||
{
|
||||
|
||||
};
|
||||
}
|
||||
using namespace ddl;
|
||||
|
||||
namespace session
|
||||
{
|
||||
struct SessionStaticData
|
||||
{
|
||||
const char* sessionName;
|
||||
bool registerUsersWithVoice;
|
||||
};
|
||||
|
||||
struct ClientInfo
|
||||
{
|
||||
bool registered;
|
||||
bool voiceRegistered;
|
||||
unsigned __int64 xuid;
|
||||
int natType;
|
||||
netadr_s addr;
|
||||
int usrVoiceConnectivityBits;
|
||||
int nextConnectivityTestTime[1];
|
||||
bool muted;
|
||||
bool privateSlot;
|
||||
};
|
||||
|
||||
struct RegisteredUser
|
||||
{
|
||||
bool active;
|
||||
unsigned __int64 xuid;
|
||||
bool privateSlot;
|
||||
};
|
||||
|
||||
struct SessionDynamicData
|
||||
{
|
||||
bool sessionHandle;
|
||||
char __pad0[47];
|
||||
bool keysGenerated;
|
||||
bool sessionStartCalled;
|
||||
unsigned __int64 sessionNonce;
|
||||
int privateSlots;
|
||||
int publicSlots;
|
||||
int flags;
|
||||
bool qosListenEnabled;
|
||||
ClientInfo users[18];
|
||||
int localVoiceConnectivityBits;
|
||||
int sessionCreateController;
|
||||
int sessionDeleteTime;
|
||||
bool allowJoining;
|
||||
RegisteredUser internalRegisteredUsers[18];
|
||||
};
|
||||
|
||||
struct SessionData
|
||||
{
|
||||
SessionStaticData staticData;
|
||||
SessionDynamicData dyn;
|
||||
};
|
||||
|
||||
assert_sizeof(SessionData, 1552);
|
||||
assert_offsetof(SessionData, dyn.users, 96);
|
||||
assert_offsetof(SessionData, dyn.internalRegisteredUsers, 1120);
|
||||
}
|
||||
using namespace session;
|
||||
|
||||
namespace party
|
||||
{
|
||||
enum PartyPreloadMapStage : std::uint32_t
|
||||
{
|
||||
PRELOAD_MAP_IDLE = 0x0,
|
||||
PRELOAD_MAP_INITIATED = 0x1,
|
||||
PRELOAD_MAP_STARTED = 0x2,
|
||||
PRELOAD_MAP_COUNT = 0x3,
|
||||
};
|
||||
|
||||
struct PartyData
|
||||
{
|
||||
SessionData* session;
|
||||
char __pad0[11436];
|
||||
PartyPreloadMapStage preloadingMapStage;
|
||||
char __pad1[101];
|
||||
bool m_gameStartSkipCountdown;
|
||||
char __pad2[110];
|
||||
int lobbyFlags;
|
||||
bool gameStartRequested;
|
||||
};
|
||||
static_assert(offsetof(PartyData, preloadingMapStage) == 11444);
|
||||
static_assert(offsetof(PartyData, m_gameStartSkipCountdown) == 11549);
|
||||
static_assert(offsetof(PartyData, lobbyFlags) == 11660);
|
||||
static_assert(offsetof(PartyData, gameStartRequested) == 11664);
|
||||
}
|
||||
using namespace party;
|
||||
|
||||
namespace sv
|
||||
{
|
||||
struct SvServerInitSettings
|
||||
{
|
||||
char mapName[64];
|
||||
char gameType[64];
|
||||
char serverHostName[64];
|
||||
bool hardcoreMode;
|
||||
unsigned int maxClientCount;
|
||||
unsigned int maxAgentCount;
|
||||
bool isMapPreloaded;
|
||||
bool isSaveGame;
|
||||
bool isRestart;
|
||||
bool isFrontEnd;
|
||||
char __pad0[2];
|
||||
bool serverThreadStartup;
|
||||
}; //static_assert(sizeof(SvServerInitSettings) == 212);
|
||||
static_assert(offsetof(SvServerInitSettings, maxClientCount) == 196);
|
||||
static_assert(offsetof(SvServerInitSettings, isMapPreloaded) == 204);
|
||||
static_assert(offsetof(SvServerInitSettings, isFrontEnd) == 207);
|
||||
static_assert(offsetof(SvServerInitSettings, serverThreadStartup) == 210);
|
||||
}
|
||||
using namespace sv;
|
||||
|
||||
namespace pmem
|
||||
{
|
||||
enum PMem_Stack : __int32
|
||||
{
|
||||
PMEM_STACK_GAME = 0x0,
|
||||
PMEM_STACK_RENDER_TARGETS = 0x1,
|
||||
PMEM_STACK_MEM_VIRTUAL = 0x2,
|
||||
PMEM_STACK_MEMCARD_LARGE_BUFFER = 0x3,
|
||||
PMEM_STACK_SOUND = 0x4,
|
||||
PMEM_STACK_STASHED_MEMORY = 0x5,
|
||||
PMEM_STACK_CINEMATIC = 0x6,
|
||||
PMEM_STACK_COUNT = 0x7,
|
||||
};
|
||||
|
||||
enum PMem_Source
|
||||
{
|
||||
PMEM_SOURCE_EXTERNAL = 0x0,
|
||||
PMEM_SOURCE_SCRIPT = 0x1,
|
||||
};
|
||||
|
||||
enum PMem_Direction : __int32
|
||||
{
|
||||
PHYS_ALLOC_LOW = 0x0,
|
||||
PHYS_ALLOC_HIGH = 0x1,
|
||||
PHYS_ALLOC_COUNT = 0x2,
|
||||
};
|
||||
|
||||
enum Mem_PageID
|
||||
{
|
||||
};
|
||||
|
||||
struct Mem_PageRange
|
||||
{
|
||||
Mem_PageID firstPageID;
|
||||
Mem_PageID lastPageID;
|
||||
};
|
||||
|
||||
struct PhysicalMemoryAllocation
|
||||
{
|
||||
const char* name;
|
||||
char* prev_buffer;
|
||||
char* next_buffer;
|
||||
unsigned __int64 pos;
|
||||
Mem_PageRange pageRange;
|
||||
};
|
||||
|
||||
struct PhysicalMemoryPrim
|
||||
{
|
||||
const char* name;
|
||||
unsigned int allocListCount;
|
||||
char __pad0[4];
|
||||
unsigned __int8* buf;
|
||||
unsigned __int64 unk_pos;
|
||||
int unk1;
|
||||
char __pad2[4];
|
||||
unsigned __int64 pos;
|
||||
PhysicalMemoryAllocation allocList[32];
|
||||
};
|
||||
|
||||
struct PhysicalMemory
|
||||
{
|
||||
PhysicalMemoryPrim prim[2];
|
||||
};
|
||||
}
|
||||
using namespace pmem;
|
||||
}
|
||||
|
@ -149,6 +149,7 @@ namespace game
|
||||
WEAK symbol<void(int localClientNum)> LUI_CoD_CLoseAll{ 0x6135C0 };
|
||||
|
||||
WEAK symbol<unsigned int(int controllerIndex)> Live_SyncOnlineDataFlags{ 0xDC5CE0 };
|
||||
WEAK symbol<std::uint64_t(int controllerIndex)> Live_GetXuid{ 0xD32A20 };
|
||||
|
||||
WEAK symbol<PartyData* ()> Lobby_GetPartyData{ 0x9C3E20 };
|
||||
|
||||
@ -163,6 +164,8 @@ namespace game
|
||||
|
||||
WEAK symbol<PartyData* ()> Party_GetActiveParty{ 0x9CC010 };
|
||||
|
||||
WEAK symbol<void(const unsigned int controllerIndex, XUID xuid)> PlayercardCache_AddToDownload{ 0xDB72E0 };
|
||||
|
||||
WEAK symbol<GfxFont* (const char* font, int size)> R_RegisterFont{ 0xDFC670 };
|
||||
WEAK symbol<int(const char* text, int maxChars, GfxFont* font)> R_TextWidth{ 0xDFC770 };
|
||||
WEAK symbol<int(void* font)> R_GetFontHeight{ 0x12727B0 };
|
||||
@ -178,6 +181,11 @@ namespace game
|
||||
#define R_AddCmdDrawTextWithCursor(TXT, MC, F, UNK, X, Y, XS, YS, R, C, S, CP, CC) \
|
||||
IW7_AddBaseDrawTextCmd(TXT, MC, F, game::R_GetFontHeight(F), X, Y, XS, YS, R, C, CP, CC, game::R_DrawSomething(S), 0, 0, 0, 0)
|
||||
|
||||
WEAK symbol<std::uint64_t(const void* session, const int clientNum)> Session_GetXuid{ 0xC72AB0 };
|
||||
WEAK symbol<bool(const SessionData* session, const int memberIndex)> Session_IsHost{ 0xD9B470 };
|
||||
|
||||
WEAK symbol<int(const char* str, std::uint64_t* xuid)> StringToXUID{ 0xCE6C40 };
|
||||
|
||||
WEAK symbol<char* ()> Sys_Cwd{ 0xCFE5A0 };
|
||||
|
||||
WEAK symbol<int()> Sys_Milliseconds{ 0xD58110 };
|
||||
@ -229,8 +237,9 @@ namespace game
|
||||
WEAK symbol<void()> SV_CmdsSP_MapRestart_f{ 0xC12B30 };
|
||||
WEAK symbol<void()> SV_CmdsSP_FastRestart_f{ 0xC12AF0 };
|
||||
WEAK symbol<int (int clientNum)> SV_ClientMP_GetClientPing{ 0xC507D0 };
|
||||
WEAK symbol<char* (int entNum)> SV_GameMP_GetGuid{ 0XC12410 };
|
||||
WEAK symbol<char* (int entNum)> SV_GameMP_GetGuid{ 0xC12410 };
|
||||
WEAK symbol<void()> SV_MainMP_KillLocalServer{ 0xC58DF0 };
|
||||
WEAK symbol<SessionData* ()> SV_MainMP_GetServerLobby{ 0xC58DA0 };
|
||||
WEAK symbol<void(int clientNum, svscmd_type type, const char* text)> SV_GameSendServerCommand{ 0xC54780 };
|
||||
WEAK symbol<void(client_t* drop, const char* reason, bool tellThem)> SV_DropClient{ 0xC4FBA0 };
|
||||
WEAK symbol<bool()> SV_Loaded{ 0xC114C0 };
|
||||
@ -258,6 +267,9 @@ namespace game
|
||||
WEAK symbol<cmd_function_s*> cmd_functions{ 0x5D65CC8 };
|
||||
WEAK symbol<const char*> command_whitelist{ 0x14D1B70 };
|
||||
|
||||
WEAK symbol<PLAYERCARD_CACHE_TASK_STAGE> g_DWPlayercardCacheDownloadTaskStage{ 0x80AE414 };
|
||||
WEAK symbol<CachedPlayerProfile> cached_playercards{ 0x80AE420 };
|
||||
|
||||
WEAK symbol<GfxDrawMethod> gfxDrawMethod{ 0x83E86A8 };
|
||||
|
||||
WEAK symbol<int> keyCatchers{ 0x2246C34 };
|
||||
@ -273,6 +285,8 @@ namespace game
|
||||
WEAK symbol<unsigned int> svs_numclients{ 0x6B229E0 };
|
||||
WEAK symbol<client_t*> svs_clients{ 0x6B22950 };
|
||||
|
||||
WEAK symbol<SessionData> g_serverSession{ 0x6B4E080 };
|
||||
|
||||
WEAK symbol<clientUIActive_t> clientUIActives{ 0x2246C30 };
|
||||
|
||||
WEAK symbol<connection_data*> cl_con_data{ 0x1FE58B8 };
|
||||
|
@ -1,9 +1,6 @@
|
||||
#pragma once
|
||||
#include <d3d11.h>
|
||||
|
||||
#define assert_sizeof(__ASSET__, __SIZE__) static_assert(sizeof(__ASSET__) == __SIZE__)
|
||||
#define assert_offsetof(__ASSET__, __VARIABLE__, __OFFSET__) static_assert(offsetof(__ASSET__, __VARIABLE__) == __OFFSET__)
|
||||
|
||||
namespace game::database
|
||||
{
|
||||
typedef float vec_t;
|
||||
|
@ -1,58 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
namespace game::ddl
|
||||
{
|
||||
enum DDLType
|
||||
{
|
||||
DDL_INVALID_TYPE = 0xFFFFFFFF,
|
||||
DDL_BYTE_TYPE = 0x0,
|
||||
DDL_SHORT_TYPE = 0x1,
|
||||
DDL_UINT_TYPE = 0x2,
|
||||
DDL_INT_TYPE = 0x3,
|
||||
DDL_UINT64_TYPE = 0x4,
|
||||
DDL_FLOAT_TYPE = 0x5,
|
||||
DDL_FIXEDPOINT_TYPE = 0x6,
|
||||
DDL_STRING_TYPE = 0x7,
|
||||
DDL_STRUCT_TYPE = 0x8,
|
||||
DDL_ENUM_TYPE = 0x9,
|
||||
};
|
||||
|
||||
union DDLValue
|
||||
{
|
||||
int intValue;
|
||||
unsigned int uintValue;
|
||||
unsigned __int64 uint64Value;
|
||||
float floatValue;
|
||||
float fixedPointValue;
|
||||
const char* stringPtr;
|
||||
};
|
||||
|
||||
struct DDLMember
|
||||
{
|
||||
const char* name;
|
||||
int index;
|
||||
int bitSize;
|
||||
int limitSize;
|
||||
int offset;
|
||||
int type;
|
||||
int externalIndex;
|
||||
unsigned int rangeLimit;
|
||||
bool isArray;
|
||||
int arraySize;
|
||||
int enumIndex;
|
||||
};
|
||||
|
||||
struct DDLState
|
||||
{
|
||||
bool isValid;
|
||||
int offset;
|
||||
int arrayIndex;
|
||||
DDLMember* member;
|
||||
//const DDLDef* ddlDef;
|
||||
};
|
||||
|
||||
struct DDLContext
|
||||
{
|
||||
|
||||
};
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
namespace game::party
|
||||
{
|
||||
enum PartyPreloadMapStage : std::uint32_t
|
||||
{
|
||||
PRELOAD_MAP_IDLE = 0x0,
|
||||
PRELOAD_MAP_INITIATED = 0x1,
|
||||
PRELOAD_MAP_STARTED = 0x2,
|
||||
PRELOAD_MAP_COUNT = 0x3,
|
||||
};
|
||||
|
||||
struct PartyData
|
||||
{
|
||||
char __pad0[11444];
|
||||
PartyPreloadMapStage preloadingMapStage;
|
||||
char __pad1[101];
|
||||
bool m_gameStartSkipCountdown;
|
||||
char __pad2[110];
|
||||
int lobbyFlags;
|
||||
bool gameStartRequested;
|
||||
};
|
||||
static_assert(offsetof(PartyData, preloadingMapStage) == 11444);
|
||||
static_assert(offsetof(PartyData, m_gameStartSkipCountdown) == 11549);
|
||||
static_assert(offsetof(PartyData, lobbyFlags) == 11660);
|
||||
static_assert(offsetof(PartyData, gameStartRequested) == 11664);
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
namespace game::pmem
|
||||
{
|
||||
enum PMem_Stack : __int32
|
||||
{
|
||||
PMEM_STACK_GAME = 0x0,
|
||||
PMEM_STACK_RENDER_TARGETS = 0x1,
|
||||
PMEM_STACK_MEM_VIRTUAL = 0x2,
|
||||
PMEM_STACK_MEMCARD_LARGE_BUFFER = 0x3,
|
||||
PMEM_STACK_SOUND = 0x4,
|
||||
PMEM_STACK_STASHED_MEMORY = 0x5,
|
||||
PMEM_STACK_CINEMATIC = 0x6,
|
||||
PMEM_STACK_COUNT = 0x7,
|
||||
};
|
||||
|
||||
enum PMem_Source
|
||||
{
|
||||
PMEM_SOURCE_EXTERNAL = 0x0,
|
||||
PMEM_SOURCE_SCRIPT = 0x1,
|
||||
};
|
||||
|
||||
enum PMem_Direction : __int32
|
||||
{
|
||||
PHYS_ALLOC_LOW = 0x0,
|
||||
PHYS_ALLOC_HIGH = 0x1,
|
||||
PHYS_ALLOC_COUNT = 0x2,
|
||||
};
|
||||
|
||||
enum Mem_PageID
|
||||
{
|
||||
};
|
||||
|
||||
struct Mem_PageRange
|
||||
{
|
||||
Mem_PageID firstPageID;
|
||||
Mem_PageID lastPageID;
|
||||
};
|
||||
|
||||
struct PhysicalMemoryAllocation
|
||||
{
|
||||
const char* name;
|
||||
char* prev_buffer;
|
||||
char* next_buffer;
|
||||
unsigned __int64 pos;
|
||||
Mem_PageRange pageRange;
|
||||
};
|
||||
|
||||
struct PhysicalMemoryPrim
|
||||
{
|
||||
const char* name;
|
||||
unsigned int allocListCount;
|
||||
char __pad0[4];
|
||||
unsigned __int8* buf;
|
||||
unsigned __int64 unk_pos;
|
||||
int unk1;
|
||||
char __pad2[4];
|
||||
unsigned __int64 pos;
|
||||
PhysicalMemoryAllocation allocList[32];
|
||||
};
|
||||
|
||||
struct PhysicalMemory
|
||||
{
|
||||
PhysicalMemoryPrim prim[2];
|
||||
};
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
namespace game::sv
|
||||
{
|
||||
struct SvServerInitSettings
|
||||
{
|
||||
char mapName[64];
|
||||
char gameType[64];
|
||||
char serverHostName[64];
|
||||
bool hardcoreMode;
|
||||
unsigned int maxClientCount;
|
||||
unsigned int maxAgentCount;
|
||||
bool isMapPreloaded;
|
||||
bool isSaveGame;
|
||||
bool isRestart;
|
||||
bool isFrontEnd;
|
||||
char __pad0[2];
|
||||
bool serverThreadStartup;
|
||||
}; //static_assert(sizeof(SvServerInitSettings) == 212);
|
||||
static_assert(offsetof(SvServerInitSettings, maxClientCount) == 196);
|
||||
static_assert(offsetof(SvServerInitSettings, isMapPreloaded) == 204);
|
||||
static_assert(offsetof(SvServerInitSettings, isFrontEnd) == 207);
|
||||
static_assert(offsetof(SvServerInitSettings, serverThreadStartup) == 210);
|
||||
}
|
162
src/client/game/utils/fragment_handler.cpp
Normal file
162
src/client/game/utils/fragment_handler.cpp
Normal file
@ -0,0 +1,162 @@
|
||||
#include <std_include.hpp>
|
||||
#include "fragment_handler.hpp"
|
||||
|
||||
namespace game::fragment_handler
|
||||
{
|
||||
namespace
|
||||
{
|
||||
constexpr size_t MAX_FRAGMENTS = 100;
|
||||
|
||||
using fragments = std::unordered_map<size_t, std::string>;
|
||||
|
||||
struct fragmented_packet
|
||||
{
|
||||
size_t fragment_count{0};
|
||||
fragments fragments{};
|
||||
std::chrono::high_resolution_clock::time_point insertion_time = std::chrono::high_resolution_clock::now();
|
||||
};
|
||||
|
||||
using id_fragment_map = std::unordered_map<uint64_t, fragmented_packet>;
|
||||
using address_fragment_map = std::unordered_map<netadr_s, id_fragment_map>;
|
||||
|
||||
utils::concurrency::container<address_fragment_map> global_map{};
|
||||
|
||||
std::vector<std::string> construct_fragments(const void* data, const size_t length)
|
||||
{
|
||||
std::vector<std::string> fragments{};
|
||||
|
||||
constexpr size_t max_fragment_size = 0x400;
|
||||
|
||||
for (size_t i = 0; i < length; i += max_fragment_size)
|
||||
{
|
||||
const auto current_fragment_size = std::min(length - i, max_fragment_size);
|
||||
|
||||
std::string fragment(static_cast<const char*>(data) + i, current_fragment_size);
|
||||
fragments.push_back(std::move(fragment));
|
||||
}
|
||||
|
||||
return fragments;
|
||||
}
|
||||
}
|
||||
|
||||
bool handle(const netadr_s& target, utils::byte_buffer& buffer, std::string& final_packet)
|
||||
{
|
||||
const auto fragment_id = buffer.read<uint64_t>();
|
||||
const size_t fragment_count = buffer.read<uint32_t>();
|
||||
const size_t fragment_index = buffer.read<uint32_t>();
|
||||
|
||||
auto fragment_data = buffer.get_remaining_data();
|
||||
|
||||
// Check for valid fragment_count and fragment_index
|
||||
if (fragment_count == 0 || fragment_count > MAX_FRAGMENTS || fragment_index >= fragment_count)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return global_map.access<bool>([&](address_fragment_map& map)
|
||||
{
|
||||
auto& user_map = map[target];
|
||||
|
||||
// Check if the user_map is full
|
||||
if (!user_map.contains(fragment_id) && user_map.size() > MAX_FRAGMENTS)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
auto& packet_queue = user_map[fragment_id];
|
||||
|
||||
// Set fragment_count if not set
|
||||
if (packet_queue.fragment_count == 0)
|
||||
{
|
||||
packet_queue.fragment_count = fragment_count;
|
||||
}
|
||||
|
||||
// Check if fragment_count matches
|
||||
if (packet_queue.fragment_count != fragment_count)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ensure fragment_index is within bounds
|
||||
if (packet_queue.fragments.size() + 1 < fragment_count)
|
||||
{
|
||||
packet_queue.fragments[fragment_index] = std::move(fragment_data);
|
||||
return false;
|
||||
}
|
||||
|
||||
final_packet.clear();
|
||||
|
||||
// Reconstruct final_packet
|
||||
for (size_t i = 0; i < fragment_count; ++i)
|
||||
{
|
||||
if (i == fragment_index)
|
||||
{
|
||||
final_packet.append(fragment_data.data(), fragment_data.size());
|
||||
}
|
||||
else
|
||||
{
|
||||
final_packet.append(packet_queue.fragments[i].data(), packet_queue.fragments[i].size());
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void clean()
|
||||
{
|
||||
global_map.access([](address_fragment_map& map)
|
||||
{
|
||||
for (auto i = map.begin(); i != map.end();)
|
||||
{
|
||||
auto& user_map = i->second;
|
||||
|
||||
for (auto j = user_map.begin(); j != user_map.end();)
|
||||
{
|
||||
const auto now = std::chrono::high_resolution_clock::now();
|
||||
const auto diff = now - j->second.insertion_time;
|
||||
|
||||
if (diff > 5s)
|
||||
{
|
||||
j = user_map.erase(j);
|
||||
}
|
||||
else
|
||||
{
|
||||
++j;
|
||||
}
|
||||
}
|
||||
|
||||
if (user_map.empty())
|
||||
{
|
||||
i = map.erase(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
++i;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void fragment_handler::fragment_data(const void* data, const size_t size,
|
||||
const std::function<void(const utils::byte_buffer& buffer)>& callback)
|
||||
{
|
||||
static std::atomic_uint64_t current_id{0};
|
||||
const auto id = current_id++;
|
||||
|
||||
const auto fragments = construct_fragments(data, size);
|
||||
|
||||
for (size_t i = 0; i < fragments.size(); ++i)
|
||||
{
|
||||
utils::byte_buffer buffer{};
|
||||
buffer.write(id);
|
||||
buffer.write(static_cast<uint32_t>(fragments.size()));
|
||||
buffer.write(static_cast<uint32_t>(i));
|
||||
|
||||
auto& fragment = fragments.at(i);
|
||||
buffer.write(fragment.data(), fragment.size());
|
||||
|
||||
callback(buffer);
|
||||
}
|
||||
}
|
||||
}
|
17
src/client/game/utils/fragment_handler.hpp
Normal file
17
src/client/game/utils/fragment_handler.hpp
Normal file
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <utils/byte_buffer.hpp>
|
||||
#include <utils/concurrency.hpp>
|
||||
|
||||
#include "../../component/network.hpp"
|
||||
|
||||
namespace game::fragment_handler
|
||||
{
|
||||
bool handle(const netadr_s& target, utils::byte_buffer& buffer,
|
||||
std::string& final_packet);
|
||||
|
||||
void clean();
|
||||
|
||||
void fragment_data(const void* data, const size_t size,
|
||||
const std::function<void(const utils::byte_buffer& buffer)>& callback);
|
||||
}
|
@ -102,4 +102,7 @@
|
||||
|
||||
using namespace std::literals;
|
||||
|
||||
#define assert_sizeof(__ASSET__, __SIZE__) static_assert(sizeof(__ASSET__) == __SIZE__)
|
||||
#define assert_offsetof(__ASSET__, __VARIABLE__, __OFFSET__) static_assert(offsetof(__ASSET__, __VARIABLE__) == __OFFSET__)
|
||||
|
||||
#define __FILENAME__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
|
||||
|
53
src/common/utils/byte_buffer.cpp
Normal file
53
src/common/utils/byte_buffer.cpp
Normal file
@ -0,0 +1,53 @@
|
||||
#include "byte_buffer.hpp"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace utils
|
||||
{
|
||||
byte_buffer::byte_buffer()
|
||||
: writing_(true)
|
||||
{
|
||||
}
|
||||
|
||||
byte_buffer::byte_buffer(std::string buffer)
|
||||
: writing_(false)
|
||||
, buffer_(std::move(buffer))
|
||||
{
|
||||
}
|
||||
|
||||
void byte_buffer::write(const void* buffer, const size_t length)
|
||||
{
|
||||
if (!this->writing_)
|
||||
{
|
||||
throw std::runtime_error("Writing to readable byte buffer");
|
||||
}
|
||||
|
||||
this->buffer_.append(static_cast<const char*>(buffer), length);
|
||||
}
|
||||
|
||||
void byte_buffer::read(void* data, const size_t length)
|
||||
{
|
||||
if (this->writing_)
|
||||
{
|
||||
throw std::runtime_error("Reading from writable byte buffer");
|
||||
}
|
||||
|
||||
if (this->offset_ + length > this->buffer_.size())
|
||||
{
|
||||
throw std::runtime_error("Out of bounds read from byte buffer");
|
||||
}
|
||||
|
||||
memcpy(data, this->buffer_.data() + this->offset_, length);
|
||||
this->offset_ += length;
|
||||
}
|
||||
|
||||
std::string byte_buffer::read_data(const size_t length)
|
||||
{
|
||||
std::string result{};
|
||||
result.resize(length);
|
||||
|
||||
this->read(result.data(), result.size());
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
141
src/common/utils/byte_buffer.hpp
Normal file
141
src/common/utils/byte_buffer.hpp
Normal file
@ -0,0 +1,141 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace utils
|
||||
{
|
||||
class byte_buffer
|
||||
{
|
||||
public:
|
||||
byte_buffer();
|
||||
byte_buffer(std::string buffer);
|
||||
|
||||
template <typename T>
|
||||
byte_buffer(const std::basic_string_view<T>& buffer)
|
||||
: byte_buffer(std::string(reinterpret_cast<const char*>(buffer.data()), buffer.size() * sizeof(T)))
|
||||
{
|
||||
}
|
||||
|
||||
void write(const void* buffer, size_t length);
|
||||
|
||||
void write(const char* text)
|
||||
{
|
||||
this->write(text, strlen(text));
|
||||
}
|
||||
|
||||
void write_string(const char* str, const size_t length)
|
||||
{
|
||||
this->write<uint32_t>(static_cast<uint32_t>(length));
|
||||
this->write(str, length);
|
||||
}
|
||||
|
||||
void write_string(const std::string& str)
|
||||
{
|
||||
this->write_string(str.data(), str.size());
|
||||
}
|
||||
|
||||
void write_string(const char* str)
|
||||
{
|
||||
this->write_string(str, strlen(str));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void write(const T& object)
|
||||
{
|
||||
this->write(&object, sizeof(object));
|
||||
}
|
||||
|
||||
template<>
|
||||
void write<byte_buffer>(const byte_buffer& object)
|
||||
{
|
||||
const auto& buffer = object.get_buffer();
|
||||
this->write(buffer.data(), buffer.size());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void write(const std::vector<T>& vec)
|
||||
{
|
||||
this->write(vec.data(), vec.size() * sizeof(T));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void write_vector(const std::vector<T>& vec)
|
||||
{
|
||||
this->write(static_cast<uint32_t>(vec.size()));
|
||||
this->write(vec);
|
||||
}
|
||||
|
||||
const std::string& get_buffer() const
|
||||
{
|
||||
return this->buffer_;
|
||||
}
|
||||
|
||||
std::string move_buffer()
|
||||
{
|
||||
return std::move(this->buffer_);
|
||||
}
|
||||
|
||||
void read(void* data, size_t length);
|
||||
|
||||
template <typename T>
|
||||
T read()
|
||||
{
|
||||
T object{};
|
||||
this->read(&object, sizeof(object));
|
||||
return object;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::vector<T> read_vector()
|
||||
{
|
||||
std::vector<T> result{};
|
||||
const auto size = this->read<uint32_t>();
|
||||
const auto totalSize = size * sizeof(T);
|
||||
|
||||
if (this->offset_ + totalSize > this->buffer_.size())
|
||||
{
|
||||
throw std::runtime_error("Out of bounds read from byte buffer");
|
||||
}
|
||||
|
||||
result.resize(size);
|
||||
this->read(result.data(), totalSize);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string read_string()
|
||||
{
|
||||
std::string result{};
|
||||
const auto size = this->read<uint32_t>();
|
||||
|
||||
if (this->offset_ + size > this->buffer_.size())
|
||||
{
|
||||
throw std::runtime_error("Out of bounds read from byte buffer");
|
||||
}
|
||||
|
||||
result.resize(size);
|
||||
this->read(result.data(), size);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
size_t get_remaining_size() const
|
||||
{
|
||||
return this->buffer_.size() - offset_;
|
||||
}
|
||||
|
||||
std::string get_remaining_data()
|
||||
{
|
||||
return this->read_data(this->get_remaining_size());
|
||||
}
|
||||
|
||||
std::string read_data(size_t length);
|
||||
|
||||
private:
|
||||
bool writing_{false};
|
||||
size_t offset_{0};
|
||||
std::string buffer_{};
|
||||
};
|
||||
}
|
@ -39,6 +39,11 @@ namespace utils::concurrency
|
||||
T& get_raw() { return object_; }
|
||||
const T& get_raw() const { return object_; }
|
||||
|
||||
std::unique_lock<MutexType> accquire_lock()
|
||||
{
|
||||
return std::unique_lock<MutexType>{mutex_};
|
||||
}
|
||||
|
||||
private:
|
||||
mutable MutexType mutex_{};
|
||||
T object_{};
|
||||
|
Loading…
Reference in New Issue
Block a user