116 lines
3.0 KiB
C++

#include <std_include.hpp>
#include "loader/component_loader.hpp"
#include <utils/hook.hpp>
#include <utils/string.hpp>
#include "component/console.hpp"
#include "network.hpp"
namespace network {
namespace {
std::unordered_map<std::string, callback>& get_callbacks() {
static std::unordered_map<std::string, callback> 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<unsigned int>(msg->cursize) < offset ||
handler == callbacks.end()) {
return false;
}
const std::string data(reinterpret_cast<char*>(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<int>(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<int>(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)