146 lines
4.1 KiB
C++
146 lines
4.1 KiB
C++
/*
|
|
* =====================================================================================
|
|
*
|
|
* OpenMiner
|
|
*
|
|
* Copyright (C) 2018-2020 Unarelith, Quentin Bazin <openminer@unarelith.net>
|
|
* Copyright (C) 2019-2020 the OpenMiner contributors (see CONTRIBUTORS.md)
|
|
*
|
|
* This file is part of OpenMiner.
|
|
*
|
|
* OpenMiner is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* OpenMiner 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
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* along with OpenMiner; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*
|
|
* =====================================================================================
|
|
*/
|
|
#include "Server.hpp"
|
|
#include "ServerConfig.hpp"
|
|
|
|
void Server::init(u16 port) {
|
|
if (m_tcpListener.listen(port) != sf::Socket::Done)
|
|
throw EXCEPTION("Network error: Listen failed");
|
|
|
|
m_port = m_tcpListener.getLocalPort();
|
|
|
|
m_tcpListener.setBlocking(false);
|
|
|
|
m_selector.add(m_tcpListener);
|
|
}
|
|
|
|
void Server::disconnectAllClients() {
|
|
for (auto &it : m_info.clients())
|
|
disconnectClient(it);
|
|
}
|
|
|
|
void Server::handleGameEvents() {
|
|
if (m_selector.wait(sf::milliseconds(10))) {
|
|
if (m_selector.isReady(m_tcpListener)) {
|
|
handleNewConnections();
|
|
}
|
|
else {
|
|
handleClientMessages();
|
|
}
|
|
}
|
|
}
|
|
|
|
void Server::handleNewConnections() {
|
|
std::shared_ptr<sf::TcpSocket> clientSocket = std::make_shared<sf::TcpSocket>();
|
|
if (m_tcpListener.accept(*clientSocket) == sf::Socket::Done) {
|
|
Network::Packet packet;
|
|
clientSocket->receive(packet);
|
|
|
|
Network::Command command;
|
|
packet >> command;
|
|
if (command != Network::Command::ClientConnect)
|
|
gkError() << "Network error: Expected 'ClientConnect' packet for new clients.";
|
|
else if (m_info.clients().size() < ServerConfig::maxPlayers) {
|
|
ClientInfo &client = m_info.addClient(clientSocket);
|
|
m_selector.add(*client.tcpSocket);
|
|
|
|
Network::Packet outPacket;
|
|
outPacket << Network::Command::ClientOk << client.id << m_isSingleplayer;
|
|
client.tcpSocket->send(outPacket);
|
|
// client.tcpSocket->setBlocking(false);
|
|
|
|
if (m_connectionCallback)
|
|
m_connectionCallback(client, packet);
|
|
}
|
|
else {
|
|
Network::Packet outPacket;
|
|
outPacket << Network::Command::ClientRefused;
|
|
clientSocket->send(outPacket);
|
|
}
|
|
}
|
|
else {
|
|
gkWarning() << "Warning: Connection accept failed.";
|
|
}
|
|
}
|
|
|
|
void Server::handleClientMessages() {
|
|
for (size_t i = 0 ; i < m_info.clients().size() ; ++i) {
|
|
ClientInfo &client = m_info.clients()[i];
|
|
if (m_selector.isReady(*client.tcpSocket)) {
|
|
Network::Packet packet;
|
|
sf::Socket::Status status = client.tcpSocket->receive(packet);
|
|
if (status == sf::Socket::Done) {
|
|
Network::Command command;
|
|
packet >> command;
|
|
|
|
// gkDebug() << "TCP message received:" << Network::commandToString(command);
|
|
|
|
if (m_isRunning) {
|
|
for (auto &it : m_commands) {
|
|
if (command == it.first)
|
|
it.second(client, packet);
|
|
|
|
if (command == Network::Command::ClientDisconnect) {
|
|
disconnectClient(client);
|
|
--i;
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (status == sf::Socket::Disconnected) {
|
|
disconnectClient(client);
|
|
--i;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Server::disconnectClient(ClientInfo &client) {
|
|
Network::Packet packet;
|
|
packet << Network::Command::ClientDisconnect << client.id;
|
|
sendToAllClients(packet);
|
|
|
|
m_commands[Network::Command::ClientDisconnect](client, packet);
|
|
|
|
m_selector.remove(*client.tcpSocket);
|
|
m_info.removeClient(client.id);
|
|
|
|
if (m_isSingleplayer && m_info.clients().size() == 0) {
|
|
m_tcpListener.close();
|
|
m_isRunning = false;
|
|
}
|
|
}
|
|
|
|
void Server::sendToAllClients(Network::Packet &packet) const {
|
|
for (const ClientInfo &client : m_info.clients()) {
|
|
client.tcpSocket->send(packet);
|
|
}
|
|
}
|
|
|