From 9232b24a7be77aec148c79309356af2da75bb214 Mon Sep 17 00:00:00 2001 From: Jocke Date: Thu, 4 Feb 2016 15:49:04 +0100 Subject: [PATCH] WIP Reliable message --- include/Engine/Network/Client.h | 13 +- include/Engine/Network/HybridClient.h | 10 ++ include/Engine/Network/HybridServer.h | 30 ++++ include/Engine/Network/PlayerDefinition.h | 3 + include/Engine/Network/Server.h | 35 ++-- include/Engine/Network/TCPClient.h | 16 ++ include/Engine/Network/TCPServer.h | 37 ++++ include/Game/Game.h | 4 +- src/Engine/Network/Client.cpp | 59 +----- src/Engine/Network/HybridClient.cpp | 56 +++++- src/Engine/Network/HybridServer.cpp | 203 +++++++++++++++++++++ src/Engine/Network/Server.cpp | 208 +--------------------- src/Engine/Network/TCPClient.cpp | 48 +++++ src/Engine/Network/TCPServer.cpp | 148 +++++++++++++++ src/Game/Game.cpp | 4 +- 15 files changed, 580 insertions(+), 294 deletions(-) create mode 100644 include/Engine/Network/HybridServer.h create mode 100644 include/Engine/Network/TCPServer.h create mode 100644 src/Engine/Network/HybridServer.cpp create mode 100644 src/Engine/Network/TCPServer.cpp diff --git a/include/Engine/Network/Client.h b/include/Engine/Network/Client.h index 4397dd41..1c445cac 100644 --- a/include/Engine/Network/Client.h +++ b/include/Engine/Network/Client.h @@ -30,11 +30,9 @@ public: void Start(World* world, EventBroker* eventBroker) override; void Update() override; protected: - // Assio UDP logic - boost::asio::ip::udp::endpoint m_ReceiverEndpoint; - boost::asio::io_service m_IOService; - boost::asio::ip::udp::socket m_Socket; - + // Save for children + std::string address; + int port = 0; // Sending message to server logic int bytesRead = -1; char readBuf[INPUTSIZE] = { 0 }; @@ -68,9 +66,8 @@ protected: std::vector m_InputCommandBuffer; // Private member functions - void readFromServer(); - int receive(char* data); - void send(Packet& packet); + virtual void send(Packet& packet) = 0; + virtual void readFromServer() = 0; void connect(); void disconnect(); void parseMessageType(Packet& packet); diff --git a/include/Engine/Network/HybridClient.h b/include/Engine/Network/HybridClient.h index 7573ad87..8c9d1a68 100644 --- a/include/Engine/Network/HybridClient.h +++ b/include/Engine/Network/HybridClient.h @@ -9,6 +9,16 @@ class HybridClient : public Client public: HybridClient(ConfigFile* config); ~HybridClient(); + void Start(World* world, EventBroker* eventBroker); +private: + // Assio UDP logic + boost::asio::ip::udp::endpoint m_ReceiverEndpoint; + boost::asio::io_service m_IOService; + boost::asio::ip::udp::socket m_Socket; + + void readFromServer(); + int receive(char * data); + void send(Packet & packet); }; #endif \ No newline at end of file diff --git a/include/Engine/Network/HybridServer.h b/include/Engine/Network/HybridServer.h new file mode 100644 index 00000000..95a9ffde --- /dev/null +++ b/include/Engine/Network/HybridServer.h @@ -0,0 +1,30 @@ +#ifndef HybridServer_h__ +#define HybridServer_h__ + +#include "Server.h" +#include + +class HybridServer : public Server +{ +public: + HybridServer(); + ~HybridServer(); +private: + // UDP logic + boost::asio::io_service m_IOService; + std::unique_ptr m_Socket; + + void readFromClients(); + void parseClientPing(); + void parsePing(); + void parseDisconnect(); + void parseConnect(Packet & packet); + void parseOnInputCommand(Packet & packet); + void parsePlayerTransform(Packet & packet); + void send(Packet & packet, PlayerDefinition & playerDefinition); + void send(Packet & packet); + int receive(char * data); + PlayerID GetPlayerIDFromEndpoint(boost::asio::ip::udp::endpoint endpoint); +}; + +#endif \ No newline at end of file diff --git a/include/Engine/Network/PlayerDefinition.h b/include/Engine/Network/PlayerDefinition.h index 863948b3..3a3dd122 100644 --- a/include/Engine/Network/PlayerDefinition.h +++ b/include/Engine/Network/PlayerDefinition.h @@ -2,6 +2,7 @@ #define PlayerDefinition_h__ #include #include "../Core/Entity.h" +#include struct PlayerDefinition { ::EntityID EntityID = EntityID_Invalid; @@ -9,6 +10,8 @@ struct PlayerDefinition { boost::asio::ip::udp::endpoint Endpoint; unsigned int PacketID; std::clock_t StopTime; + // use for tcp connections + boost::shared_ptr TCPSocket; }; #endif diff --git a/include/Engine/Network/Server.h b/include/Engine/Network/Server.h index 11f983a9..2926558f 100644 --- a/include/Engine/Network/Server.h +++ b/include/Engine/Network/Server.h @@ -5,7 +5,6 @@ #include #include -#include #include "Network/MessageType.h" #include "Network/PlayerDefinition.h" @@ -18,7 +17,6 @@ #include "Core/EPlayerSpawned.h" #include "Core/EEntityDeleted.h" #include "Core/EComponentDeleted.h" - class Server : public Network { public: @@ -26,12 +24,9 @@ public: ~Server(); void Start(World* m_world, EventBroker *eventBroker) override; void Update() override; -private: - // UDP logic - boost::asio::ip::udp::endpoint m_ReceiverEndpoint; - boost::asio::io_service m_IOService; - boost::asio::ip::udp::socket m_Socket; - +protected: + template + T m_ReceiverEndpoint; // Sending messages to client logic std::map m_ConnectedPlayers; // HACK: Fix INPUTSIZE @@ -41,12 +36,12 @@ private: std::clock_t previousePingMessage = std::clock(); std::clock_t previousSnapshotMessage = std::clock(); std::clock_t timOutTimer = std::clock(); + // How often we send messages (milliseconds) int pingIntervalMs; int snapshotInterval; int checkTimeOutInterval = 100; int m_NextPlayerID = 0; - //Timers std::clock_t m_StartPingTime; @@ -59,10 +54,7 @@ private: PacketID m_PreviousPacketID = 0; // Private member functions - int receive(char* data); - void readFromClients(); - void send(PlayerID player, Packet& packet); - void send(Packet& packet); + //int receive(char* data); void broadcast(Packet& packet); void sendSnapshot(); void addChildrenToPacket(Packet& packet, EntityID entityID); @@ -70,15 +62,18 @@ private: void checkForTimeOuts(); void disconnect(PlayerID playerID); void parseMessageType(Packet& packet); - void parseOnInputCommand(Packet& packet); void parseOnPlayerDamage(Packet& packet); - void parseConnect(Packet& packet); - void parseDisconnect(); - void parseClientPing(); - void parsePing(); void identifyPacketLoss(); void kick(PlayerID player); - PlayerID GetPlayerIDFromEndpoint(boost::asio::ip::udp::endpoint endpoint); + // Pure virtual functions + virtual void parseOnInputCommand(Packet& packet) = 0; + virtual void readFromClients() = 0; + virtual void send(Packet& packet, PlayerDefinition & playerDefinition) = 0; + virtual void send(Packet& packet) = 0; + virtual void parseConnect(Packet& packet) = 0; + virtual void parseDisconnect() = 0; + virtual void parseClientPing() = 0; + virtual void parsePing() = 0; // Debug event EventRelay m_EInputCommand; bool OnInputCommand(const Events::InputCommand& e); @@ -88,7 +83,7 @@ private: bool OnEntityDeleted(const Events::EntityDeleted& e); EventRelay m_EComponentDeleted; bool OnComponentDeleted(const Events::ComponentDeleted& e); - void parsePlayerTransform(Packet& packet); + virtual void parsePlayerTransform(Packet& packet) = 0; }; #endif diff --git a/include/Engine/Network/TCPClient.h b/include/Engine/Network/TCPClient.h index d342641b..14415eef 100644 --- a/include/Engine/Network/TCPClient.h +++ b/include/Engine/Network/TCPClient.h @@ -1,7 +1,23 @@ #ifndef TCPClient_h__ #define TCPClient_h__ +#include "Client.h" +class TCPClient : public Client +{ +public: + TCPClient(ConfigFile* config); + ~TCPClient(); + void Start(World* world, EventBroker* eventBroker); +private: + // Assio TCP logic + boost::asio::ip::tcp::endpoint m_Endpoint; + boost::asio::io_service m_IOService; + boost::shared_ptr m_Socket; + void readFromServer(); + int receive(char * data); + void send(Packet & packet); +}; #endif \ No newline at end of file diff --git a/include/Engine/Network/TCPServer.h b/include/Engine/Network/TCPServer.h new file mode 100644 index 00000000..23f6d666 --- /dev/null +++ b/include/Engine/Network/TCPServer.h @@ -0,0 +1,37 @@ +#ifndef TCPServer_h__ +#define TCPServer_h__ + +#include "Server.h" + +class TCPServer : public Server +{ +public: + TCPServer(); + ~TCPServer(); + +private: + // TCP logic + boost::asio::ip::udp::endpoint m_ReceiverEndpoint; + boost::asio::io_service m_IOService; + std::unique_ptr acceptor; + boost::shared_ptr lastReceivedSocket; + + void Start(World* world, EventBroker* eventBroker); + void readFromClients(); + void acceptNewConnections(); + void handle_accept(boost::shared_ptr socket, const boost::system::error_code & error); + void parseDisconnect(); + void parseConnect(Packet & packet); + ///// Implement method to get which player it was + void parseClientPing(); + void parsePing(); + void parseOnInputCommand(Packet & packet); + void parsePlayerTransform(Packet & packet); + ///////////////////////// + void send(Packet & packet, PlayerDefinition & playerDefinition); + void send(Packet & packet); + int receive(char * data, boost::asio::ip::tcp::socket& socket); + PlayerID GetPlayerIDFromEndpoint(boost::asio::ip::udp::endpoint endpoint); +}; + +#endif \ No newline at end of file diff --git a/include/Game/Game.h b/include/Game/Game.h index 85d0190c..060f97f4 100644 --- a/include/Game/Game.h +++ b/include/Game/Game.h @@ -26,8 +26,10 @@ // Network #include #include "Network/Network.h" -#include "Network/Server.h" +#include "Network/HybridServer.h" #include "Network/HybridClient.h" +#include "Network/TCPClient.h" +#include "Network/TCPServer.h" // Sound #include "Sound/SoundSystem.h" diff --git a/src/Engine/Network/Client.cpp b/src/Engine/Network/Client.cpp index 6c43cc8b..6f9519d5 100644 --- a/src/Engine/Network/Client.cpp +++ b/src/Engine/Network/Client.cpp @@ -1,9 +1,6 @@ #include "Network/Client.h" -using namespace boost::asio::ip; - - -Client::Client(ConfigFile* config) : m_Socket(m_IOService) +Client::Client(ConfigFile* config) { Network::initialize(); @@ -12,13 +9,11 @@ Client::Client(ConfigFile* config) : m_Socket(m_IOService) // Init timer m_TimeSinceSentInputs = std::clock(); // Default is local host - std::string address = config->Get("Networking.Address", "127.0.0.1"); - int port = config->Get("Networking.Port", 27666); - m_ReceiverEndpoint = udp::endpoint(boost::asio::ip::address::from_string(address), port); + address = config->Get("Networking.Address", "127.0.0.1"); + port = config->Get("Networking.Port", 27666); // Set up network stream m_PlayerName = config->Get("Networking.Name", "Raptorcopter"); m_SendInputIntervalMs = config->Get("Networking.SendInputIntervalMs", 33); - } Client::~Client() @@ -33,8 +28,6 @@ void Client::Start(World* world, EventBroker* eventBroker) EVENT_SUBSCRIBE_MEMBER(m_EInputCommand, &Client::OnInputCommand); EVENT_SUBSCRIBE_MEMBER(m_EPlayerDamage, &Client::OnPlayerDamage); EVENT_SUBSCRIBE_MEMBER(m_EPlayerSpawned, &Client::OnPlayerSpawned); - - m_Socket.connect(m_ReceiverEndpoint); LOG_INFO("I am client. BIP BOP"); } @@ -54,17 +47,6 @@ void Client::Update() Network::Update(); } -void Client::readFromServer() -{ - while (m_Socket.available()) { - bytesRead = receive(readBuf); - if (bytesRead > 0) { - Packet packet(readBuf, bytesRead); - parseMessageType(packet); - } - } -} - void Client::parseMessageType(Packet& packet) { int messageType = packet.ReadPrimitive(); @@ -258,40 +240,6 @@ void Client::parseSnapshot(Packet& packet) } } -int Client::receive(char* data) -{ - boost::system::error_code error; - - int bytesReceived = m_Socket.receive_from(boost - ::asio::buffer((void*)data, INPUTSIZE), - m_ReceiverEndpoint, - 0, error); - // Network Debug data - if (isReadingData) { - m_NetworkData.TotalDataReceived += bytesReceived; - m_NetworkData.DataReceivedThisInterval += bytesReceived; - m_NetworkData.AmountOfMessagesReceived++; - } - if (error) { - //LOG_ERROR("receive: %s", error.message().c_str()); - } - return bytesReceived; -} - -void Client::send(Packet& packet) -{ - m_Socket.send_to(boost::asio::buffer( - packet.Data(), - packet.Size()), - m_ReceiverEndpoint, 0); - // Network Debug data - if (isReadingData) { - m_NetworkData.TotalDataSent += packet.Size(); - m_NetworkData.DataSentThisInterval += packet.Size(); - m_NetworkData.AmountOfMessagesSent++; - } -} - void Client::connect() { Packet packet(MessageType::Connect, m_SendPacketID); @@ -457,7 +405,6 @@ void Client::insertIntoServerClientMaps(EntityID serverEntityID, EntityID client { m_ServerIDToClientID.insert(std::make_pair(serverEntityID, clientEntityID)); m_ClientIDToServerID.insert(std::make_pair(clientEntityID, serverEntityID)); - } void Client::deleteFromServerClientMaps(EntityID serverEntityID, EntityID clientEntityID) diff --git a/src/Engine/Network/HybridClient.cpp b/src/Engine/Network/HybridClient.cpp index 798ff578..fd0b6649 100644 --- a/src/Engine/Network/HybridClient.cpp +++ b/src/Engine/Network/HybridClient.cpp @@ -1,12 +1,64 @@ #include "Network/HybridClient.h" +using namespace boost::asio::ip; -HybridClient::HybridClient(ConfigFile * config) : Client(config) +HybridClient::HybridClient(ConfigFile * config) : Client(config), m_Socket(m_IOService) { - + m_ReceiverEndpoint = udp::endpoint(boost::asio::ip::address::from_string(address), port); } HybridClient::~HybridClient() { } + +void HybridClient::Start(World* world, EventBroker* eventBroker) +{ + Client::Start(world, eventBroker); + m_Socket.connect(m_ReceiverEndpoint); +} + +void HybridClient::readFromServer() +{ + while (m_Socket.available()) { + bytesRead = receive(readBuf); + if (bytesRead > 0) { + Packet packet(readBuf, bytesRead); + parseMessageType(packet); + } + } +} + +int HybridClient::receive(char* data) +{ + boost::system::error_code error; + + int bytesReceived = m_Socket.receive_from(boost + ::asio::buffer((void*)data, INPUTSIZE), + m_ReceiverEndpoint, + 0, error); + // Network Debug data + if (isReadingData) { + m_NetworkData.TotalDataReceived += bytesReceived; + m_NetworkData.DataReceivedThisInterval += bytesReceived; + m_NetworkData.AmountOfMessagesReceived++; + } + if (error) { + //LOG_ERROR("receive: %s", error.message().c_str()); + } + return bytesReceived; +} + +void HybridClient::send(Packet& packet) +{ + m_Socket.send_to(boost::asio::buffer( + packet.Data(), + packet.Size()), + m_ReceiverEndpoint, 0); + // Network Debug data + if (isReadingData) { + m_NetworkData.TotalDataSent += packet.Size(); + m_NetworkData.DataSentThisInterval += packet.Size(); + m_NetworkData.AmountOfMessagesSent++; + } +} \ No newline at end of file diff --git a/src/Engine/Network/HybridServer.cpp b/src/Engine/Network/HybridServer.cpp new file mode 100644 index 00000000..e4142725 --- /dev/null +++ b/src/Engine/Network/HybridServer.cpp @@ -0,0 +1,203 @@ +#include "Network/HybridServer.h" + +HybridServer::HybridServer() +{ + m_Socket = std::unique_ptr(new boost::asio::ip::udp::socket(m_IOService, boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 27666))); + +} + +HybridServer::~HybridServer() +{ } + + +void HybridServer::readFromClients() +{ + while (m_Socket->available()) { + try { + bytesRead = receive(readBuffer); + Packet packet(readBuffer, bytesRead); + parseMessageType(packet); + } catch (const std::exception& err) { + //LOG_ERROR("%i: Read from client crashed %s", m_PacketID, err.what()); + } + } + std::clock_t currentTime = std::clock(); + // Send snapshot + if (snapshotInterval < (1000 * (currentTime - previousSnapshotMessage) / (double)CLOCKS_PER_SEC)) { + sendSnapshot(); + previousSnapshotMessage = currentTime; + } + + // Send pings each + if (pingIntervalMs < (1000 * (currentTime - previousePingMessage) / (double)CLOCKS_PER_SEC)) { + sendPing(); + previousePingMessage = currentTime; + } + + // Time out logic + if (checkTimeOutInterval < (1000 * (currentTime - timOutTimer) / (double)CLOCKS_PER_SEC)) { + checkForTimeOuts(); + timOutTimer = currentTime; + } +} + +void HybridServer::parseClientPing() +{ + LOG_INFO("%i: Parsing ping", m_PacketID); + PlayerID player = GetPlayerIDFromEndpoint(m_ReceiverEndpoint); + if (player == -1) { + return; + } + // Return ping + Packet packet(MessageType::Ping, m_ConnectedPlayers[player].PacketID); + packet.WriteString("Ping received"); + send(packet); +} + +void HybridServer::parsePing() +{ + for (int i = 0; i < m_ConnectedPlayers.size(); i++) { + if (m_ConnectedPlayers[i].Endpoint.address() == m_ReceiverEndpoint.address()) { + m_ConnectedPlayers[i].StopTime = std::clock(); + break; + } + } +} + +void HybridServer::parseDisconnect() +{ + LOG_INFO("%i: Parsing disconnect", m_PacketID); + + for (auto& kv : m_ConnectedPlayers) { + if (kv.second.Endpoint.address() == m_ReceiverEndpoint.address() && + kv.second.Endpoint.port() == m_ReceiverEndpoint.port()) { + disconnect(kv.first); + break; + } + } +} + +void HybridServer::parseConnect(Packet& packet) +{ + LOG_INFO("Parsing connections"); + // Check if player is already connected + if (GetPlayerIDFromEndpoint(m_ReceiverEndpoint) != -1) { + return; + } + // Create a new player + PlayerDefinition pd; + pd.EntityID = 0; // Overlook this + pd.Endpoint = m_ReceiverEndpoint; + pd.Name = packet.ReadString(); + pd.PacketID = 0; + pd.StopTime = std::clock(); + m_ConnectedPlayers[m_NextPlayerID++] = pd; + LOG_INFO("Spectator \"%s\" connected on IP: %s", pd.Name.c_str(), pd.Endpoint.address().to_string().c_str()); + + // Send a message to the player that connected + Packet connnectPacket(MessageType::Connect, pd.PacketID); + send(connnectPacket); + + // Send notification that a player has connected + Packet notificationPacket(MessageType::PlayerConnected); + broadcast(notificationPacket); +} + +void HybridServer::parseOnInputCommand(Packet& packet) +{ + PlayerID player = -1; + // Check which player it was who sent the message + player = GetPlayerIDFromEndpoint(m_ReceiverEndpoint); + if (player != -1) { + while (packet.DataReadSize() < packet.Size()) { + Events::InputCommand e; + e.Command = packet.ReadString(); + e.PlayerID = player; // Set correct player id + e.Player = EntityWrapper(m_World, m_ConnectedPlayers.at(player).EntityID); + e.Value = packet.ReadPrimitive(); + m_EventBroker->Publish(e); + LOG_INFO("Server::parseOnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID); + } + } +} + +void HybridServer::parsePlayerTransform(Packet& packet) +{ + glm::vec3 position; + glm::vec3 orientation; + position.x = packet.ReadPrimitive(); + position.y = packet.ReadPrimitive(); + position.z = packet.ReadPrimitive(); + orientation.x = packet.ReadPrimitive(); + orientation.y = packet.ReadPrimitive(); + orientation.z = packet.ReadPrimitive(); + + PlayerID playerID = GetPlayerIDFromEndpoint(m_ReceiverEndpoint); + EntityWrapper player(m_World, m_ConnectedPlayers.at(playerID).EntityID); + + if (player.Valid()) { + player["Transform"]["Position"] = position; + player["Transform"]["Orientation"] = orientation; + } +} + +void HybridServer::send(Packet& packet, PlayerDefinition & playerDefinition) +{ + try { + int bytesSent = m_Socket->send_to( + boost::asio::buffer(packet.Data(), packet.Size()), + playerDefinition.Endpoint, + 0); + // Network Debug data + if (isReadingData) { + m_NetworkData.TotalDataSent += packet.Size(); + m_NetworkData.DataSentThisInterval += packet.Size(); + m_NetworkData.AmountOfMessagesSent++; + } + } catch (const boost::system::system_error& e) { + // TODO: Clean up invalid endpoints out of m_ConnectedPlayers later + playerDefinition.Endpoint = boost::asio::ip::udp::endpoint(); + } +} +// Send back to endpoint of received packet +void HybridServer::send(Packet & packet) +{ + m_Socket->send_to( + boost::asio::buffer( + packet.Data(), + packet.Size()), + m_ReceiverEndpoint, + 0); + if (isReadingData) { + // Network Debug data + m_NetworkData.TotalDataSent += packet.Size(); + m_NetworkData.DataSentThisInterval += packet.Size(); + } +} + + +int HybridServer::receive(char * data) +{ + unsigned int length = m_Socket->receive_from( + boost::asio::buffer((void*)data + , INPUTSIZE) + , m_ReceiverEndpoint, 0); + // Network Debug data + if (isReadingData) { + m_NetworkData.TotalDataReceived += length; + m_NetworkData.DataReceivedThisInterval += length; + m_NetworkData.AmountOfMessagesReceived++; + } + return length; +} + +PlayerID HybridServer::GetPlayerIDFromEndpoint(boost::asio::ip::udp::endpoint endpoint) +{ + for (auto& kv : m_ConnectedPlayers) { + if (kv.second.Endpoint.address() == endpoint.address() && + kv.second.Endpoint.port() == endpoint.port()) { + return kv.first; + } + } + return -1; +} diff --git a/src/Engine/Network/Server.cpp b/src/Engine/Network/Server.cpp index adf14413..37b2e752 100644 --- a/src/Engine/Network/Server.cpp +++ b/src/Engine/Network/Server.cpp @@ -1,19 +1,16 @@ #include "Network/Server.h" -Server::Server() : m_Socket(m_IOService, boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 27666)) +Server::Server() { Network::initialize(); ConfigFile* config = ResourceManager::Load("Config.ini"); snapshotInterval = 1000 * config->Get("Networking.SnapshotInterval", 0.05); pingIntervalMs = config->Get("Networking.PingIntervalMs", 1000); - } - Server::~Server() { } - void Server::Start(World* world, EventBroker* eventBroker) { m_World = world; @@ -36,41 +33,9 @@ void Server::Update() } -void Server::readFromClients() -{ - while (m_Socket.available()) { - try { - bytesRead = receive(readBuffer); - Packet packet(readBuffer, bytesRead); - parseMessageType(packet); - } catch (const std::exception& err) { - //LOG_ERROR("%i: Read from client crashed %s", m_PacketID, err.what()); - } - } - std::clock_t currentTime = std::clock(); - // Send snapshot - if (snapshotInterval < (1000 * (currentTime - previousSnapshotMessage) / (double)CLOCKS_PER_SEC)) { - sendSnapshot(); - previousSnapshotMessage = currentTime; - } - - // Send pings each - if (pingIntervalMs < (1000 * (currentTime - previousePingMessage) / (double)CLOCKS_PER_SEC)) { - sendPing(); - previousePingMessage = currentTime; - } - - // Time out logic - if (checkTimeOutInterval < (1000 * (currentTime - timOutTimer) / (double)CLOCKS_PER_SEC)) { - checkForTimeOuts(); - timOutTimer = currentTime; - } -} - void Server::parseMessageType(Packet& packet) { int messageType = packet.ReadPrimitive(); // Read what type off message was sent from server - // Read packet ID m_PreviousPacketID = m_PacketID; // Set previous packet id m_PacketID = packet.ReadPrimitive(); //Read new packet id @@ -103,60 +68,11 @@ void Server::parseMessageType(Packet& packet) } } -int Server::receive(char * data) -{ - unsigned int length = m_Socket.receive_from( - boost::asio::buffer((void*)data - , INPUTSIZE) - , m_ReceiverEndpoint, 0); - // Network Debug data - if (isReadingData) { - m_NetworkData.TotalDataReceived += length; - m_NetworkData.DataReceivedThisInterval += length; - m_NetworkData.AmountOfMessagesReceived++; - } - return length; -} - -void Server::send(PlayerID player, Packet& packet) -{ - try { - int bytesSent = m_Socket.send_to( - boost::asio::buffer(packet.Data(), packet.Size()), - m_ConnectedPlayers[player].Endpoint, - 0); - // Network Debug data - if (isReadingData) { - m_NetworkData.TotalDataSent += packet.Size(); - m_NetworkData.DataSentThisInterval += packet.Size(); - m_NetworkData.AmountOfMessagesSent++; - } - } catch (const boost::system::system_error& e) { - // TODO: Clean up invalid endpoints out of m_ConnectedPlayers later - m_ConnectedPlayers[player].Endpoint = boost::asio::ip::udp::endpoint(); - } -} - -void Server::send(Packet & packet) -{ - m_Socket.send_to( - boost::asio::buffer( - packet.Data(), - packet.Size()), - m_ReceiverEndpoint, - 0); - if (isReadingData) { - // Network Debug data - m_NetworkData.TotalDataSent += packet.Size(); - m_NetworkData.DataSentThisInterval += packet.Size(); - } -} - void Server::broadcast(Packet& packet) { for (auto& kv : m_ConnectedPlayers) { packet.ChangePacketID(kv.second.PacketID); - send(kv.first, packet); + send(packet, kv.second); } } @@ -259,24 +175,6 @@ void Server::disconnect(PlayerID playerID) m_ConnectedPlayers.erase(playerID); } -void Server::parseOnInputCommand(Packet& packet) -{ - PlayerID player = -1; - // Check which player it was who sent the message - player = GetPlayerIDFromEndpoint(m_ReceiverEndpoint); - if (player != -1) { - while (packet.DataReadSize() < packet.Size()) { - Events::InputCommand e; - e.Command = packet.ReadString(); - e.PlayerID = player; // Set correct player id - e.Player = EntityWrapper(m_World, m_ConnectedPlayers.at(player).EntityID); - e.Value = packet.ReadPrimitive(); - m_EventBroker->Publish(e); - LOG_INFO("Server::parseOnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID); - } - } -} - void Server::parseOnPlayerDamage(Packet & packet) { Events::PlayerDamage e; @@ -286,75 +184,6 @@ void Server::parseOnPlayerDamage(Packet & packet) //LOG_DEBUG("Server::parseOnPlayerDamage: Command is %s. Value is %f. PlayerID is %i.", e.DamageAmount, e.PlayerDamagedID, e.TypeOfDamage.c_str()); } -void Server::parseConnect(Packet& packet) -{ - LOG_INFO("Parsing connections"); - // Check if player is already connected - if (GetPlayerIDFromEndpoint(m_ReceiverEndpoint) != -1) { - return; - } - for (auto& kv : m_ConnectedPlayers) { - if (kv.second.Endpoint.address() == m_ReceiverEndpoint.address() && - kv.second.Endpoint.port() == m_ReceiverEndpoint.port()) { - // Already connected - return; - } - } - // Create a new player - PlayerDefinition pd; - pd.EntityID = 0; // Overlook this - pd.Endpoint = m_ReceiverEndpoint; - pd.Name = packet.ReadString(); - pd.PacketID = 0; - pd.StopTime = std::clock(); - m_ConnectedPlayers[m_NextPlayerID++] = pd; - LOG_INFO("Spectator \"%s\" connected on IP: %s", pd.Name.c_str(), pd.Endpoint.address().to_string().c_str()); - - // Send a message to the player that connected - Packet connnectPacket(MessageType::Connect, pd.PacketID); - send(connnectPacket); - - // Send notification that a player has connected - Packet notificationPacket(MessageType::PlayerConnected); - broadcast(notificationPacket); -} - -void Server::parseDisconnect() -{ - LOG_INFO("%i: Parsing disconnect", m_PacketID); - - for (auto& kv : m_ConnectedPlayers) { - if (kv.second.Endpoint.address() == m_ReceiverEndpoint.address() && - kv.second.Endpoint.port() == m_ReceiverEndpoint.port()) { - disconnect(kv.first); - break; - } - } -} - -void Server::parseClientPing() -{ - LOG_INFO("%i: Parsing ping", m_PacketID); - PlayerID player = GetPlayerIDFromEndpoint(m_ReceiverEndpoint); - if (player == -1) { - return; - } - // Return ping - Packet packet(MessageType::Ping, m_ConnectedPlayers[player].PacketID); - packet.WriteString("Ping received"); - send(packet); -} - -void Server::parsePing() -{ - for (int i = 0; i < m_ConnectedPlayers.size(); i++) { - if (m_ConnectedPlayers[i].Endpoint.address() == m_ReceiverEndpoint.address()) { - m_ConnectedPlayers[i].StopTime = std::clock(); - break; - } - } -} - void Server::identifyPacketLoss() { // if no packets lost, difference should be equal to 1 @@ -371,17 +200,6 @@ void Server::kick(PlayerID player) send(packet); } -PlayerID Server::GetPlayerIDFromEndpoint(boost::asio::ip::udp::endpoint endpoint) -{ - for (auto& kv : m_ConnectedPlayers) { - if (kv.second.Endpoint.address() == endpoint.address() && - kv.second.Endpoint.port() == endpoint.port()) { - return kv.first; - } - } - return -1; -} - bool Server::OnInputCommand(const Events::InputCommand & e) { //LOG_DEBUG("Server::OnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID); @@ -408,7 +226,7 @@ bool Server::OnPlayerSpawned(const Events::PlayerSpawned & e) packet.WritePrimitive(e.Spawner.ID); // We don't send PlayerID here because it will always be set to -1 packet.WriteString(m_ConnectedPlayers[e.PlayerID].Name); - send(e.PlayerID, packet); + send(packet, m_ConnectedPlayers[e.PlayerID]); return false; } @@ -432,23 +250,3 @@ bool Server::OnComponentDeleted(const Events::ComponentDeleted & e) } return false; } - -void Server::parsePlayerTransform(Packet& packet) -{ - glm::vec3 position; - glm::vec3 orientation; - position.x = packet.ReadPrimitive(); - position.y = packet.ReadPrimitive(); - position.z = packet.ReadPrimitive(); - orientation.x = packet.ReadPrimitive(); - orientation.y = packet.ReadPrimitive(); - orientation.z = packet.ReadPrimitive(); - - PlayerID playerID = GetPlayerIDFromEndpoint(m_ReceiverEndpoint); - EntityWrapper player(m_World, m_ConnectedPlayers.at(playerID).EntityID); - - if (player.Valid()) { - player["Transform"]["Position"] = position; - player["Transform"]["Orientation"] = orientation; - } -} diff --git a/src/Engine/Network/TCPClient.cpp b/src/Engine/Network/TCPClient.cpp index e69de29b..d4909f56 100644 --- a/src/Engine/Network/TCPClient.cpp +++ b/src/Engine/Network/TCPClient.cpp @@ -0,0 +1,48 @@ +#include "Network/TCPClient.h" + +using namespace boost::asio::ip; + +TCPClient::TCPClient(ConfigFile * config) : Client(config) +{ + m_Endpoint = tcp::endpoint(boost::asio::ip::address::from_string(address), port); + m_Socket = boost::shared_ptr(new tcp::socket(m_IOService)); +} + +TCPClient::~TCPClient() +{ + +} + +void TCPClient::Start(World * world, EventBroker * eventBroker) +{ + Client::Start(world, eventBroker); + boost::system::error_code error = boost::asio::error::host_not_found; + while (error) { + m_Socket->close(); + m_Socket->connect(m_Endpoint,error); + LOG_INFO(error.message().c_str()); + } +} + +void TCPClient::readFromServer() +{ + +} + +int TCPClient::receive(char * data) +{ + return 0; +} + +void TCPClient::send(Packet & packet) +{ + m_Socket->send(boost::asio::buffer( + packet.Data(), + packet.Size())); + // Network Debug data + if (isReadingData) { + m_NetworkData.TotalDataSent += packet.Size(); + m_NetworkData.DataSentThisInterval += packet.Size(); + m_NetworkData.AmountOfMessagesSent++; + } +} diff --git a/src/Engine/Network/TCPServer.cpp b/src/Engine/Network/TCPServer.cpp new file mode 100644 index 00000000..930e7913 --- /dev/null +++ b/src/Engine/Network/TCPServer.cpp @@ -0,0 +1,148 @@ +#include "Network/TCPServer.h" +using namespace boost::asio::ip; + +TCPServer::TCPServer() +{ + acceptor = std::unique_ptr(new tcp::acceptor(m_IOService, tcp::endpoint(tcp::v4(), 27666))); +} + +TCPServer::~TCPServer() +{ + +} + +void TCPServer::Start(World* world, EventBroker* eventBroker) +{ + Server::Start(world, eventBroker); +} + +void TCPServer::readFromClients() +{ + acceptNewConnections(); + for (auto& kv : m_ConnectedPlayers) { + while (kv.second.TCPSocket->available()) { + try { + bytesRead = receive(readBuffer, *kv.second.TCPSocket); + lastReceivedSocket = kv.second.TCPSocket; + Packet packet(readBuffer, bytesRead); + parseMessageType(packet); + } catch (const std::exception& err) { + //LOG_ERROR("%i: Read from client crashed %s", m_PacketID, err.what()); + } + } + } + + std::clock_t currentTime = std::clock(); + // Send snapshot + if (snapshotInterval < (1000 * (currentTime - previousSnapshotMessage) / (double)CLOCKS_PER_SEC)) { + sendSnapshot(); + previousSnapshotMessage = currentTime; + } + + // Send pings each + if (pingIntervalMs < (1000 * (currentTime - previousePingMessage) / (double)CLOCKS_PER_SEC)) { + sendPing(); + previousePingMessage = currentTime; + } + + // Time out logic + if (checkTimeOutInterval < (1000 * (currentTime - timOutTimer) / (double)CLOCKS_PER_SEC)) { + checkForTimeOuts(); + timOutTimer = currentTime; + } +} + +void TCPServer::acceptNewConnections() +{ + boost::shared_ptr newSocket = boost::shared_ptr(new tcp::socket(m_IOService)); + m_IOService.poll(); + acceptor->async_accept(*newSocket, + boost::bind(&TCPServer::handle_accept, this, newSocket, + boost::asio::placeholders::error)); +} + +void TCPServer::handle_accept(boost::shared_ptr socket, const boost::system::error_code& error) +{ + if (!error) { + // Add tcp socket to connections + PlayerDefinition pd; + pd.StopTime = std::clock(); + pd.TCPSocket = socket; + m_ConnectedPlayers[m_NextPlayerID++] = pd; + } +} +void TCPServer::parseClientPing() +{ + +} +void TCPServer::parsePing() +{ + +} +void TCPServer::parseDisconnect() +{ + +} +void TCPServer::parseConnect(Packet & packet) +{ + +} +void TCPServer::parseOnInputCommand(Packet & packet) +{ + +} +void TCPServer::parsePlayerTransform(Packet & packet) +{ + +} +void TCPServer::send(Packet & packet, PlayerDefinition & playerDefinition) +{ + try { + int bytesSent = playerDefinition.TCPSocket->send( + boost::asio::buffer(packet.Data(), packet.Size()), + 0); + // Network Debug data + if (isReadingData) { + m_NetworkData.TotalDataSent += packet.Size(); + m_NetworkData.DataSentThisInterval += packet.Size(); + m_NetworkData.AmountOfMessagesSent++; + } + } catch (const boost::system::system_error& e) { + // TODO: Clean up invalid endpoints out of m_ConnectedPlayers later + playerDefinition.Endpoint = boost::asio::ip::udp::endpoint(); + } +} + +void TCPServer::send(Packet & packet) +{ + lastReceivedSocket->send( + boost::asio::buffer( + packet.Data(), + packet.Size()), + 0); + if (isReadingData) { + // Network Debug data + m_NetworkData.TotalDataSent += packet.Size(); + m_NetworkData.DataSentThisInterval += packet.Size(); + } +} + +//boost::shared_ptr socket +int TCPServer::receive(char * data,boost::asio::ip::tcp::socket& socket) +{ + unsigned int length = socket.read_some( + boost::asio::buffer((void*)data, INPUTSIZE)); + // Network Debug data + if (isReadingData) { + m_NetworkData.TotalDataReceived += length; + m_NetworkData.DataReceivedThisInterval += length; + m_NetworkData.AmountOfMessagesReceived++; + } + return length; + +} + +PlayerID TCPServer::GetPlayerIDFromEndpoint(boost::asio::ip::udp::endpoint endpoint) +{ + return PlayerID(); +} \ No newline at end of file diff --git a/src/Game/Game.cpp b/src/Game/Game.cpp index c26510ec..969fa46c 100644 --- a/src/Game/Game.cpp +++ b/src/Game/Game.cpp @@ -181,11 +181,11 @@ void Game::networkFunction() bool isServer = m_Config->Get("Networking.IsServer", false); if (!isServer) { m_IsClientOrServer = true; - m_ClientOrServer = new HybridClient(m_Config); + m_ClientOrServer = new TCPClient(m_Config); } if (isServer) { m_IsClientOrServer = true; - m_ClientOrServer = new Server(); + m_ClientOrServer = new TCPServer(); } m_ClientOrServer->Start(m_World, m_EventBroker);