Merge pull request #22 from XLabsProject/feature/demonware

Merge current demonware refactoring progress
This commit is contained in:
Maurice Heumann 2021-03-01 21:20:43 +01:00 committed by GitHub
commit ac709d54af
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 372 additions and 23270 deletions

View File

@ -3,6 +3,7 @@
#include "loader/component_loader.hpp"
#include "game/game.hpp"
#include "scheduler.hpp"
#include "command.hpp"
#include <utils/thread.hpp>
#include <utils/flags.hpp>
@ -32,9 +33,9 @@ namespace console
{
hide_console();
_pipe(this->handles_, 1024, _O_TEXT);
_dup2(this->handles_[1], 1);
_dup2(this->handles_[1], 2);
(void)_pipe(this->handles_, 1024, _O_TEXT);
(void)_dup2(this->handles_[1], 1);
(void)_dup2(this->handles_[1], 2);
//setvbuf(stdout, nullptr, _IONBF, 0);
//setvbuf(stderr, nullptr, _IONBF, 0);
@ -45,6 +46,7 @@ namespace console
scheduler::loop([this]()
{
this->log_messages();
this->event_frame();
}, scheduler::pipeline::main);
this->console_runner_ = utils::thread::create_named_thread("Console IO", [this]
@ -71,7 +73,19 @@ namespace console
void post_unpack() override
{
this->initialize();
game::Sys_ShowConsole();
if (!game::environment::is_dedi())
{
// Hide that shit
ShowWindow(console::get_window(), SW_MINIMIZE);
}
// Async console is not ready yet :/
//this->initialize();
std::lock_guard<std::mutex> _(this->mutex_);
this->console_initialized_ = true;
}
private:
@ -84,15 +98,27 @@ namespace console
int handles_[2]{};
void event_frame()
{
MSG msg;
while (PeekMessageA(&msg, nullptr, NULL, NULL, PM_REMOVE))
{
if (msg.message == WM_QUIT)
{
command::execute("quit", false);
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
void initialize()
{
utils::thread::create_named_thread("Console", [this]()
{
if (game::environment::is_dedi())
{
game::Sys_ShowConsole();
}
else if (!utils::flags::has_flag("noconsole"))
if (game::environment::is_dedi() || !utils::flags::has_flag("noconsole"))
{
game::Sys_ShowConsole();
}
@ -195,7 +221,7 @@ namespace console
SetWindowPos(get_window(), nullptr, rect.left, rect.top, width, height, 0);
const auto logo_window = *reinterpret_cast<HWND*>(SELECT_VALUE(0x14A9F6080, 0x14B5B94D0));
auto* const logo_window = *reinterpret_cast<HWND*>(SELECT_VALUE(0x14A9F6080, 0x14B5B94D0));
SetWindowPos(logo_window, nullptr, 5, 5, width - 25, 60, 0);
}
}

View File

@ -48,7 +48,7 @@ namespace demonware
{
std::lock_guard<std::recursive_mutex> $(server_mutex);
servers[server->address()] = server;
servers[server->get_address()] = server;
}
auto find_server_by_address(const std::uint32_t address) -> server_ptr
@ -176,7 +176,7 @@ namespace demonware
if (server)
{
static thread_local in_addr address;
address.s_addr = server->address();
address.s_addr = server->get_address();
static thread_local in_addr* addr_list[2];
addr_list[0] = &address;
@ -223,7 +223,8 @@ namespace demonware
if (server)
{
return server->recv(buf, len);
server->handle_input(buf, len);
return len;
}
return send(s, buf, len, flags);
@ -237,7 +238,7 @@ namespace demonware
{
if (server->pending_data())
{
return server->send(buf, len);
return static_cast<int>(server->handle_output(buf, len));
}
else
{
@ -251,21 +252,21 @@ namespace demonware
int sendto_stub(SOCKET s, const char* buf, int len, int flags, const struct sockaddr* to, int tolen)
{
const auto* in_addr = reinterpret_cast<const sockaddr_in*>(to);
/*const auto* in_addr = reinterpret_cast<const sockaddr_in*>(to);
auto server = find_server_by_address(in_addr->sin_addr.s_addr);
if (server)
{
socket_link(s, in_addr->sin_addr.s_addr);
return server->recv(buf, len);
}
}*/
return sendto(s, buf, len, flags, to, tolen);
}
int recvfrom_stub(SOCKET s, char* buf, int len, int flags, struct sockaddr* from, int* fromlen)
{
auto server = find_server_by_socket(s);
/*auto server = find_server_by_socket(s);
if (server)
{
@ -283,7 +284,7 @@ namespace demonware
WSASetLastError(WSAEWOULDBLOCK);
return -1;
}
}
}*/
return recvfrom(s, buf, len, flags, from, fromlen);
}

View File

@ -2,10 +2,16 @@
namespace demonware
{
class reply
{
public:
reply() = default;
reply(reply&&) = delete;
reply(const reply&) = delete;
reply& operator=(reply&&) = delete;
reply& operator=(const reply&) = delete;
virtual ~reply() = default;
virtual std::string data() = 0;
};
@ -22,7 +28,7 @@ namespace demonware
{
}
virtual std::string data() override
std::string data() override
{
return this->buffer_;
}
@ -30,16 +36,16 @@ namespace demonware
class typed_reply : public raw_reply
{
private:
uint8_t type_;
protected:
uint8_t type() const { return this->type_; }
public:
typed_reply(uint8_t _type) : type_(_type)
{
}
protected:
uint8_t type() const { return this->type_; }
private:
uint8_t type_;
};
class encrypted_reply final : public typed_reply
@ -55,7 +61,7 @@ namespace demonware
this->buffer_.append(bbuffer->get_buffer());
}
virtual std::string data() override;
std::string data() override;
};
class unencrypted_reply final : public typed_reply
@ -71,17 +77,13 @@ namespace demonware
this->buffer_.append(bbuffer->get_buffer());
}
virtual std::string data() override;
std::string data() override;
};
class service_server;
class remote_reply final
{
private:
uint8_t type_;
service_server* server_;
public:
remote_reply(service_server* server, uint8_t _type) : type_(_type), server_(server)
{
@ -91,16 +93,14 @@ namespace demonware
void send(byte_buffer* buffer, const bool encrypted);
uint8_t type() const { return this->type_; }
private:
uint8_t type_;
service_server* server_;
};
class service_reply final
{
private:
uint8_t type_;
uint32_t error_;
remote_reply reply_;
std::vector<std::shared_ptr<bdTaskResult>> objects_;
public:
service_reply(service_server* _server, uint8_t _type, uint32_t _error)
: type_(_type), error_(_error), reply_(_server, 1)
@ -150,6 +150,11 @@ namespace demonware
{
this->add(std::shared_ptr<bdTaskResult>(object));
}
};
private:
uint8_t type_;
uint32_t error_;
remote_reply reply_;
std::vector<std::shared_ptr<bdTaskResult>> objects_;
};
}

View File

@ -4,6 +4,9 @@
class base_server
{
public:
using stream_queue = std::queue<char>;
using data_queue = std::queue<std::string>;
base_server(std::string name)
: name_(std::move(name))
{
@ -27,14 +30,8 @@ public:
return this->address_;
}
virtual void frame()
{
}
virtual bool pending_data()
{
return false;
}
virtual void frame() = 0;
virtual bool pending_data() = 0;
private:
std::string name_;

View File

@ -10,32 +10,89 @@ class tcp_server : public base_server
public:
using base_server::base_server;
int handle_input(const char* buf, int size)
void handle_input(const char* buf, size_t size)
{
in_queue_.access([&](data_queue& queue)
{
queue.emplace(buf, size);
});
}
size_t handle_output(char* buf, size_t size)
{
if (out_queue_.get_raw().empty())
{
return 0;
}
int handle_output(char* buf, int size)
return out_queue_.access<size_t>([&](stream_queue& queue)
{
return 0;
for (size_t i = 0; i < size; ++i)
{
if (queue.empty())
{
return i;
}
buf[i] = queue.front();
queue.pop();
}
return size;
});
}
bool pending_data() override
{
return !this->out_queue_.get_raw().empty();
}
void frame() override
{
if (this->in_queue_.get_raw().empty())
{
return;
}
while (true)
{
std::string packet{};
const auto result = this->in_queue_.access<bool>([&](data_queue& queue)
{
if (queue.empty())
{
return false;
}
packet = std::move(queue.front());
queue.pop();
return true;
});
if (!result)
{
break;
}
this->handle(packet);
}
}
protected:
virtual void handle(const std::string& data) = 0;
void send(const std::string&)
{
void send(const std::string& data)
{
out_queue_.access([&](stream_queue& queue)
{
for (const auto& val : data)
{
queue.push(val);
}
});
}
private:
using stream_queue = std::queue<char>;
using data_queue = std::queue<std::string>;
utils::concurrency::container<data_queue> in_queue_;
utils::concurrency::container<stream_queue> out_queue_;
void frame() override
{
}
};

View File

@ -0,0 +1,95 @@
#pragma once
#include "base_server.hpp"
#include <queue>
#include <utils/concurrency.hpp>
class udp_server : public base_server
{
public:
using base_server::base_server;
void handle_input(const char* buf, size_t size)
{
in_queue_.access([&](data_queue& queue)
{
queue.emplace(buf, size);
});
}
size_t handle_output(char* buf, size_t size)
{
if (out_queue_.get_raw().empty())
{
return 0;
}
return out_queue_.access<size_t>([&](data_queue& queue) -> size_t
{
if (queue.empty())
{
return 0;
}
auto data = std::move(queue.front());
queue.pop();
const auto copy_size = std::min(size, data.size());
std::memcpy(buf, data.data(), copy_size);
return copy_size;
});
}
bool pending_data() override
{
return !this->out_queue_.get_raw().empty();
}
protected:
virtual void handle(const std::string& data) = 0;
void send(const std::string& data)
{
out_queue_.access([&](data_queue& queue)
{
queue.push(data);
});
}
private:
utils::concurrency::container<data_queue> in_queue_;
utils::concurrency::container<data_queue> out_queue_;
void frame() override
{
if (this->in_queue_.get_raw().empty())
{
return;
}
while (true)
{
std::string packet{};
const auto result = this->in_queue_.access<bool>([&](data_queue& queue)
{
if (queue.empty())
{
return false;
}
packet = std::move(queue.front());
queue.pop();
return true;
});
if (!result)
{
break;
}
this->handle(packet);
}
}
};

View File

@ -1,70 +1,15 @@
#include <std_include.hpp>
#include "../demonware.hpp"
#include <utils/json.hpp>
using json = nlohmann::json;
namespace demonware
{
int server_auth3::recv(const char* buf, const int len)
{
if (len <= 0) return -1;
std::lock_guard<std::recursive_mutex> _(this->mutex_);
this->incoming_queue_.push(std::string(buf, len));
return len;
}
int server_auth3::send(char* buf, int len)
{
if (len > 0 && !this->outgoing_queue_.empty())
{
std::lock_guard<std::recursive_mutex> _(this->mutex_);
len = std::min(len, static_cast<int>(this->outgoing_queue_.size()));
for (auto i = 0; i < len; ++i)
{
buf[i] = this->outgoing_queue_.front();
this->outgoing_queue_.pop();
}
return len;
}
return SOCKET_ERROR;
}
void server_auth3::send_reply(reply* data)
{
if (!data) return;
std::lock_guard _(this->mutex_);
const auto buffer = data->data();
for (auto& byte : buffer)
{
this->outgoing_queue_.push(byte);
}
this->send(data->data());
}
void server_auth3::frame()
{
if (!this->incoming_queue_.empty())
{
std::lock_guard _(this->mutex_);
const auto packet = this->incoming_queue_.front();
this->incoming_queue_.pop();
this->dispatch(packet);
}
}
bool server_auth3::pending_data()
{
std::lock_guard _(this->mutex_);
return !this->outgoing_queue_.empty();
}
void server_auth3::dispatch(const std::string& packet)
void server_auth3::handle(const std::string& packet)
{
if (packet.starts_with("POST /auth/"))
{
@ -73,38 +18,42 @@ namespace demonware
#endif
return;
}
else
{
unsigned int title_id = 0;
unsigned int iv_seed = 0;
std::string identity = "";
std::string token = "";
std::string identity{};
std::string token{};
json j = json::parse(packet);
rapidjson::Document j;
j.Parse(packet.data(), packet.size());
if (j.contains("title_id") && j["title_id"].is_string())
title_id = std::stoul(j["title_id"].get<std::string>());
if (j.HasMember("title_id") && j["title_id"].IsString())
title_id = std::stoul(j["title_id"].GetString());
if (j.contains("iv_seed") && j["iv_seed"].is_string())
iv_seed = std::stoul(j["iv_seed"].get<std::string>());
if (j.HasMember("iv_seed") && j["iv_seed"].IsString())
iv_seed = std::stoul(j["iv_seed"].GetString());
if (j.contains("extra_data") && j["extra_data"].is_string())
if (j.HasMember("extra_data") && j["extra_data"].IsString())
{
json extra_data = json::parse(j["extra_data"].get<std::string>());
rapidjson::Document extra_data;
auto& ed = j["extra_data"];
extra_data.Parse(ed.GetString(), ed.GetStringLength());
if (extra_data.contains("token") && extra_data["token"].is_string())
if (extra_data.HasMember("token") && extra_data["token"].IsString())
{
std::string token_b64 = extra_data["token"].get<std::string>();
auto& token_field = extra_data["token"];
std::string token_b64(token_field.GetString(), token_field.GetStringLength());
token = utils::cryptography::base64::decode(token_b64);
}
}
#ifdef DEBUG
printf("[demonware]: [auth]: authenticating user %s\n", std::string(&token.data()[64]).data());
printf("[demonware]: [auth]: authenticating user %s\n", token.data() + 64);
#endif
std::string auth_key(reinterpret_cast<char*>(&token.data()[32]), 24);
std::string session_key("\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37", 24);
std::string auth_key(reinterpret_cast<char*>(token.data() + 32), 24);
std::string session_key(
"\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37\x13\x37", 24);
// client_ticket
auth_ticket_t ticket{};
@ -115,14 +64,14 @@ namespace demonware
ticket.m_timeIssued = static_cast<uint32_t>(time(nullptr));
ticket.m_timeExpires = ticket.m_timeIssued + 30000;
ticket.m_licenseID = 0;
ticket.m_userID = reinterpret_cast<uint64_t>(&token.data()[56]);
strncpy_s(ticket.m_username, sizeof(ticket.m_username), reinterpret_cast<char*>(&token.data()[64]), 64);
ticket.m_userID = reinterpret_cast<uint64_t>(token.data() +56);
strncpy_s(ticket.m_username, sizeof(ticket.m_username), reinterpret_cast<char*>(token.data() + 64), 64);
std::memcpy(ticket.m_sessionKey, session_key.data(), 24);
const auto iv = utils::cryptography::tiger::compute(std::string(reinterpret_cast<char*>(&iv_seed), 4));
std::string ticket_enc = utils::cryptography::des3::encrypt(
std::string(reinterpret_cast<char*>(&ticket), sizeof(ticket)), iv, auth_key);
std::string ticket_b64 = utils::cryptography::base64::encode((const unsigned char*)ticket_enc.c_str(), 128);
std::string ticket_b64 = utils::cryptography::base64::encode(reinterpret_cast<const unsigned char*>(ticket_enc.data()), 128);
// server_ticket
uint8_t auth_data[128];
@ -134,24 +83,33 @@ namespace demonware
// header time
char date[64];
time_t now = time(0);
tm gmtm;
time_t now = time(nullptr);
tm gmtm{};
gmtime_s(&gmtm, &now);
strftime(date, 64, "%a, %d %b %G %T", &gmtm);
// json content
std::string content;
content.append("{\"auth_task\": \"29\",");
content.append("\"code\": \"700\",");
content.append(utils::string::va("\"iv_seed\": \"%u\",", iv_seed));
content.append(utils::string::va("\"client_ticket\": \"%s\",", ticket_b64.c_str()));
content.append(utils::string::va("\"server_ticket\": \"%s\",", auth_data_b64.c_str()));
content.append("\"client_id\": \"\",");
content.append("\"account_type\": \"steam\",");
content.append("\"crossplay_enabled\": false,");
content.append("\"loginqueue_eanbled\": false,");
content.append("\"lsg_endpoint\": null,");
content.append("}");
rapidjson::Document doc;
doc.SetObject();
doc.AddMember("auth_task", "29", doc.GetAllocator());
doc.AddMember("code", "700", doc.GetAllocator());
auto seed = std::to_string(iv_seed);
doc.AddMember("iv_seed", rapidjson::StringRef(seed.data(), seed.size()), doc.GetAllocator());
doc.AddMember("client_ticket", rapidjson::StringRef(ticket_b64.data(), ticket_b64.size()), doc.GetAllocator());
doc.AddMember("server_ticket", rapidjson::StringRef(auth_data_b64.data(), auth_data_b64.size()), doc.GetAllocator());
doc.AddMember("client_id", "", doc.GetAllocator());
doc.AddMember("account_type", "steam", doc.GetAllocator());
doc.AddMember("crossplay_enabled", false, doc.GetAllocator());
doc.AddMember("loginqueue_eanbled", false, doc.GetAllocator());
rapidjson::Value value{};
doc.AddMember("lsg_endpoint", value, doc.GetAllocator());
rapidjson::StringBuffer buffer{};
rapidjson::Writer<rapidjson::StringBuffer, rapidjson::Document::EncodingType, rapidjson::ASCII<>> writer(buffer);
doc.Accept(writer);
// http stuff
std::string result;
@ -159,8 +117,8 @@ namespace demonware
result.append("Server: TornadoServer/4.5.3\r\n");
result.append("Content-Type: application/json\r\n");
result.append(utils::string::va("Date: %s GMT\r\n", date));
result.append(utils::string::va("Content-Length: %d\r\n\r\n", content.size()));
result.append(content);
result.append(utils::string::va("Content-Length: %d\r\n\r\n", buffer.GetLength()));
result.append(buffer.GetString(), buffer.GetLength());
raw_reply reply(result);
this->send_reply(&reply);
@ -169,5 +127,4 @@ namespace demonware
printf("[demonware]: [auth]: user successfully authenticated.\n");
#endif
}
}
}

View File

@ -1,47 +1,8 @@
#pragma once
#include <utils/cryptography.hpp>
#include "new/tcp_server.hpp"
class server_base
{
std::string name_;
std::uint32_t address_ = 0;
public:
server_base(std::string name) : name_(std::move(name))
{
this->address_ = utils::cryptography::jenkins_one_at_a_time::compute(this->name_);
}
virtual ~server_base() = default;
std::uint32_t address() const
{
return this->address_;
}
virtual void frame()
{
return;
}
virtual int recv(const char* buf, int size)
{
printf("PACKET\n%s\n", std::string(buf, size).data());
return 0;
}
virtual int send(char* buf, int size)
{
return SOCKET_ERROR;
}
virtual bool pending_data()
{
return false;
}
};
using server_ptr = std::shared_ptr<server_base>;
using server_ptr = std::shared_ptr<tcp_server>;
namespace demonware
{
@ -62,24 +23,13 @@ namespace demonware
};
#pragma pack(pop)
class server_auth3 : public server_base
class server_auth3 : public tcp_server
{
public:
explicit server_auth3(std::string name) : server_base(name)
{
};
void frame() override;
int recv(const char* buf, int len) override;
int send(char* buf, int len) override;
bool pending_data() override;
using tcp_server::tcp_server;
private:
std::recursive_mutex mutex_;
std::queue<char> outgoing_queue_;
std::queue<std::string> incoming_queue_;
void send_reply(reply* data);
void dispatch(const std::string& packet);
void handle(const std::string& packet) override;
};
}

View File

@ -1,10 +1,10 @@
#include <std_include.hpp>
#include "../demonware.hpp"
#include "new/tcp_server.hpp"
namespace demonware
{
server_lobby::server_lobby(std::string name) : server_base(std::move(name))
server_lobby::server_lobby(std::string name) : tcp_server(std::move(name))
{
this->register_service<bdAnticheat>();
this->register_service<bdBandwidthTest>();
@ -26,67 +26,13 @@ namespace demonware
this->register_service<bdMarketing>();
};
void server_lobby::frame()
{
if (!this->incoming_queue_.empty())
{
std::lock_guard _(this->mutex_);
const auto packet = this->incoming_queue_.front();
this->incoming_queue_.pop();
this->dispatch(packet);
}
}
int server_lobby::recv(const char* buf, int len)
{
if (len <= 3) return -1;
std::lock_guard<std::recursive_mutex> _(this->mutex_);
this->incoming_queue_.push(std::string(buf, len));
return len;
}
int server_lobby::send(char* buf, int len)
{
if (len > 0 && !this->outgoing_queue_.empty())
{
std::lock_guard<std::recursive_mutex> _(this->mutex_);
len = std::min(len, static_cast<int>(this->outgoing_queue_.size()));
for (auto i = 0; i < len; ++i)
{
buf[i] = this->outgoing_queue_.front();
this->outgoing_queue_.pop();
}
return len;
}
return SOCKET_ERROR;
}
bool server_lobby::pending_data()
{
std::lock_guard _(this->mutex_);
return !this->outgoing_queue_.empty();
}
void server_lobby::send_reply(reply* data)
{
if (!data) return;
std::lock_guard _(this->mutex_);
const auto buffer = data->data();
for (auto& byte : buffer)
{
this->outgoing_queue_.push(byte);
}
this->send(data->data());
}
void server_lobby::dispatch(const std::string& packet)
void server_lobby::handle(const std::string& packet)
{
byte_buffer buffer(packet);
buffer.set_use_data_types(false);
@ -200,7 +146,7 @@ namespace demonware
}
}
void server_lobby::call_service(std::uint8_t id, const std::string& data)
void server_lobby::call_service(const std::uint8_t id, const std::string& data)
{
const auto& it = this->services_.find(id);

View File

@ -2,15 +2,10 @@
namespace demonware
{
class server_lobby : public server_base, service_server
class server_lobby : public tcp_server, service_server
{
public:
explicit server_lobby(std::string name);
void frame() override;
int recv(const char* buf, int len) override;
int send(char* buf, int len) override;
bool pending_data() override;
server_lobby(std::string name);
template <typename T>
void register_service()
@ -26,12 +21,9 @@ namespace demonware
void send_reply(reply* data) override;
private:
std::recursive_mutex mutex_;
std::queue<char> outgoing_queue_;
std::queue<std::string> incoming_queue_;
std::map<std::uint8_t, std::unique_ptr<service>> services_;
std::unordered_map<std::uint8_t, std::unique_ptr<service>> services_;
void dispatch(const std::string& packet);
void call_service(std::uint8_t type, const std::string& data);
void handle(const std::string& packet) override;
void call_service(const std::uint8_t id, const std::string& data);
};
}

View File

@ -1,65 +1,16 @@
#pragma once
#include "new/udp_server.hpp"
namespace demonware
{
class server_stun : public server_base
class server_stun : public udp_server
{
public:
using server_base::server_base;
int recv(const char* buf, int len) override
{
if (len <= 0) return -1;
std::lock_guard<std::recursive_mutex> _(this->mutex_);
this->incoming_queue_.push(std::string(buf, len));
return len;
}
int send(char* buf, int len) override
{
if (len > 0 && !this->outgoing_queue_.empty())
{
std::lock_guard<std::recursive_mutex> _(this->mutex_);
auto& data = this->outgoing_queue_.front();
len = std::min(len, static_cast<int>(data.size()));
for (auto i = 0; i < len; ++i)
{
buf[i] = data[i];
}
this->outgoing_queue_.pop();
return len;
}
return SOCKET_ERROR;
}
bool pending_data() override
{
return !outgoing_queue_.empty();
}
void frame() override
{
if (!this->incoming_queue_.empty())
{
std::lock_guard _(this->mutex_);
const auto packet = this->incoming_queue_.front();
this->incoming_queue_.pop();
this->dispatch(packet);
}
}
using udp_server::udp_server;
private:
std::recursive_mutex mutex_;
std::queue<std::string> outgoing_queue_;
std::queue<std::string> incoming_queue_;
void dispatch(const std::string& packet)
void handle(const std::string& packet) override
{
uint8_t type, version, padding;
@ -94,7 +45,7 @@ namespace demonware
buffer.write_uint32(ip); // external ip
buffer.write_uint16(3074); // port
send(buffer.get_buffer().data(), static_cast<int>(buffer.get_buffer().size()));
this->send(buffer.get_buffer());
}
void nat_discovery()
@ -108,10 +59,10 @@ namespace demonware
buffer.write_byte(0); // version
buffer.write_uint32(ip); // external ip
buffer.write_uint16(3074); // port
buffer.write_uint32(this->address()); // server ip
buffer.write_uint32(this->get_address()); // server ip
buffer.write_uint16(3074); // server port
send(buffer.get_buffer().data(), static_cast<int>(buffer.get_buffer().size()));
this->send(buffer.get_buffer());
}
};
}

View File

@ -11,7 +11,7 @@
DECLSPEC_NORETURN void WINAPI exit_hook(const int code)
{
component_loader::pre_destroy();
_exit(code); // Temporarily
exit(code);
}

File diff suppressed because it is too large Load Diff