#include #include "loader/component_loader.hpp" #include #include #include "component/console.hpp" #include "network.hpp" namespace network { namespace { std::unordered_map& get_callbacks() { static std::unordered_map network_callbacks{}; return network_callbacks; } bool handle_command(game::netadr_s* address, const char* command, game::msg_t* msg) { const auto cmd_string = utils::string::to_lower(command); auto& callbacks = get_callbacks(); const auto handler = callbacks.find(cmd_string); const auto offset = cmd_string.size() + 5; if (static_cast(msg->cursize) < offset || handler == callbacks.end()) { return false; } const std::string data(reinterpret_cast(msg->data) + offset, msg->cursize - offset); handler->second(*address, data); return true; } int packet_interception_handler(game::netadr_s* from, const char* command, game::msg_t* message) { if (!handle_command(from, command, message)) { return utils::hook::invoke(0x525730, from, command, message); } return TRUE; } } // namespace void send(const game::netadr_s& address, const std::string& command, const std::string& data, const char separator) { std::string packet = "\xFF\xFF\xFF\xFF"; packet.append(command); packet.push_back(separator); packet.append(data); send_data(address, packet); } void send_data(const game::netadr_s& address, const std::string& data) { auto size = static_cast(data.size()); if (address.type == game::NA_LOOPBACK) { // TODO: Fix this for loopback if (size > 1280) { console::info("Packet was too long. Truncated!\n"); size = 1280; } game::NET_SendLoopPacket(game::NS_CLIENT1, size, data.data(), address); } else { game::Sys_SendPacket(size, data.data(), address); } } void on_packet(const std::string& command, const callback& callback) { get_callbacks()[utils::string::to_lower(command)] = callback; } const char* net_adr_to_string(const game::netadr_s& a) { if (a.type == game::netadrtype_t::NA_LOOPBACK) { return "loopback"; } if (a.type == game::netadrtype_t::NA_BOT) { return "bot"; } if (a.type == game::netadrtype_t::NA_IP || a.type == game::netadrtype_t::NA_BROADCAST) { if (a.port) { return utils::string::va("%u.%u.%u.%u:%u", a.ip[0], a.ip[1], a.ip[2], a.ip[3], htons(a.port)); } return utils::string::va("%u.%u.%u.%u", a.ip[0], a.ip[1], a.ip[2], a.ip[3]); } return "bad"; } class network final : public component_interface { public: void post_unpack() override { add_network_commands(); utils::hook(0x5B27E1, HOOK_CAST(packet_interception_handler), HOOK_CALL) .install() // hook* ->quick(); } private: static void add_network_commands() {} }; } // namespace network REGISTER_COMPONENT(network::network)