tibia-rme/source/live_server.cpp
Eduardo Dantas 2057c5203b
improve: improve: replacing boosts with std functions (#415)
Removed boosts (replaced with equivalent on std 14/17/20)

With this modification, there are only 16 libs for the project to add, simplifying a lot.

So two additional libraries will be needed to compile: asio,
nlohmann-json

I also removed OTGZ support by default and disabled it, making it optional (needs to be enabled). Anyone who wants to use it will need to activate this, I think it's ideal since few should use it, so a majority don't use it, which is fairer that those who need to activate it to use it than those who don't need to have this in their program.
2023-03-25 21:42:38 -03:00

305 lines
6.5 KiB
C++

//////////////////////////////////////////////////////////////////////
// This file is part of Remere's Map Editor
//////////////////////////////////////////////////////////////////////
// Remere's Map Editor is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Remere's Map Editor is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//////////////////////////////////////////////////////////////////////
#include "main.h"
#include "live_server.h"
#include "live_peer.h"
#include "live_tab.h"
#include "live_action.h"
#include "editor.h"
LiveServer::LiveServer(Editor& editor) : LiveSocket(),
clients(), acceptor(nullptr), socket(nullptr), editor(&editor),
clientIds(0), port(0), stopped(false)
{
//
}
LiveServer::~LiveServer()
{
//
}
bool LiveServer::bind()
{
NetworkConnection& connection = NetworkConnection::getInstance();
if(!connection.start()) {
setLastError("The previous connection has not been terminated yet.");
return false;
}
auto& service = connection.get_service();
acceptor = std::make_shared<asio::ip::tcp::acceptor>(service);
asio::ip::tcp::endpoint endpoint(asio::ip::tcp::v4(), port);
acceptor->open(endpoint.protocol());
std::error_code error;
acceptor->set_option(asio::ip::tcp::no_delay(true), error);
if(error) {
setLastError("Error: " + error.message());
return false;
}
acceptor->bind(endpoint);
acceptor->listen();
acceptClient();
return true;
}
void LiveServer::close()
{
for(auto& clientEntry : clients) {
delete clientEntry.second;
}
clients.clear();
if(log) {
log->Message("Server was shutdown.");
log->Disconnect();
log = nullptr;
}
stopped = true;
if(acceptor) {
acceptor->close();
}
if(socket) {
socket->close();
}
}
void LiveServer::acceptClient()
{
static uint32_t id = 0;
if(stopped) {
return;
}
if(!socket) {
socket = std::make_shared<asio::ip::tcp::socket>(
NetworkConnection::getInstance().get_service()
);
}
acceptor->async_accept(*socket, [this](const std::error_code& error) -> void
{
if(error) {
//
} else {
LivePeer* peer = new LivePeer(this, std::move(*socket));
peer->log = log;
peer->receiveHeader();
clients.insert(std::make_pair(id++, peer));
}
acceptClient();
});
}
void LiveServer::removeClient(uint32_t id)
{
auto it = clients.find(id);
if(it == clients.end()) {
return;
}
const uint32_t clientId = it->second->getClientId();
if(clientId != 0) {
clientIds &= ~clientId;
editor->getMap().clearVisible(clientIds);
}
clients.erase(it);
updateClientList();
}
void LiveServer::updateCursor(const Position& position)
{
LiveCursor cursor;
cursor.id = 0;
cursor.pos = position;
cursor.color = wxColor(
g_settings.getInteger(Config::CURSOR_RED),
g_settings.getInteger(Config::CURSOR_GREEN),
g_settings.getInteger(Config::CURSOR_BLUE),
g_settings.getInteger(Config::CURSOR_ALPHA)
);
broadcastCursor(cursor);
}
void LiveServer::updateClientList() const
{
log->UpdateClientList(clients);
}
uint16_t LiveServer::getPort() const
{
return port;
}
bool LiveServer::setPort(int32_t newPort)
{
if(newPort < 1 || newPort > 65535) {
setLastError("Port must be a number in the range 1-65535.");
return false;
}
port = newPort;
return true;
}
uint32_t LiveServer::getFreeClientId()
{
for(int32_t bit = 1; bit < (1 << 16); bit <<= 1) {
if(!testFlags(clientIds, bit)) {
clientIds |= bit;
return bit;
}
}
return 0;
}
std::string LiveServer::getHostName() const
{
if(acceptor) {
auto endpoint = acceptor->local_endpoint();
return endpoint.address().to_string() + ":" + std::to_string(endpoint.port());
}
return "localhost";
}
void LiveServer::broadcastNodes(DirtyList& dirtyList)
{
if(dirtyList.Empty()) {
return;
}
for(const auto& ind : dirtyList.GetPosList()) {
int32_t ndx = ind.pos >> 18;
int32_t ndy = (ind.pos >> 4) & 0x3FFF;
uint32_t floors = ind.floors;
QTreeNode* node = editor->getMap().getLeaf(ndx * 4, ndy * 4);
if(!node) {
continue;
}
for(auto& clientEntry : clients) {
LivePeer* peer = clientEntry.second;
const uint32_t clientId = peer->getClientId();
if(dirtyList.owner != 0 && dirtyList.owner == clientId) {
continue;
}
if(node->isVisible(clientId, true)) {
peer->sendNode(clientId, node, ndx, ndy, floors & 0xFF00);
}
if(node->isVisible(clientId, false)) {
peer->sendNode(clientId, node, ndx, ndy, floors & 0x00FF);
}
}
}
}
void LiveServer::broadcastCursor(const LiveCursor& cursor)
{
if(clients.empty()) {
return;
}
if(cursor.id != 0) {
cursors[cursor.id] = cursor;
}
NetworkMessage message;
message.write<uint8_t>(PACKET_CURSOR_UPDATE);
writeCursor(message, cursor);
for(auto& clientEntry : clients) {
LivePeer* peer = clientEntry.second;
if(peer->getClientId() != cursor.id) {
peer->send(message);
}
}
}
void LiveServer::broadcastChat(const wxString& speaker, const wxString& chatMessage)
{
if(clients.empty()) {
return;
}
NetworkMessage message;
message.write<uint8_t>(PACKET_SERVER_TALK);
message.write<std::string>(nstr(speaker));
message.write<std::string>(nstr(chatMessage));
for(auto& clientEntry : clients) {
clientEntry.second->send(message);
}
log->Chat(name, chatMessage);
}
void LiveServer::startOperation(const wxString& operationMessage)
{
if(clients.empty()) {
return;
}
NetworkMessage message;
message.write<uint8_t>(PACKET_START_OPERATION);
message.write<std::string>(nstr(operationMessage));
for(auto& clientEntry : clients) {
clientEntry.second->send(message);
}
}
void LiveServer::updateOperation(int32_t percent)
{
if(clients.empty()) {
return;
}
NetworkMessage message;
message.write<uint8_t>(PACKET_UPDATE_OPERATION);
message.write<uint32_t>(percent);
for(auto& clientEntry : clients) {
clientEntry.second->send(message);
}
}
LiveLogTab* LiveServer::createLogWindow(wxWindow* parent)
{
MapTabbook* mapTabBook = dynamic_cast<MapTabbook*>(parent);
ASSERT(mapTabBook);
log = newd LiveLogTab(mapTabBook, this);
log->Message("New Live mapping session started.");
log->Message("Hosted on server " + getHostName() + ".");
updateClientList();
return log;
}