From f52cddb44592d64dabfa0133efbebb777f5594e9 Mon Sep 17 00:00:00 2001 From: Jocke Date: Wed, 20 Jan 2016 13:43:11 +0100 Subject: [PATCH] Added packet loss logic for multiple clients. Changed packet class to fit our needs. --- include/Engine/Network/Packet.h | 3 +- include/Engine/Network/PlayerDefinition.h | 2 + include/Engine/Network/Server.h | 8 ++-- src/Engine/Network/Client.cpp | 6 +-- src/Engine/Network/Packet.cpp | 21 +++++++++-- src/Engine/Network/Server.cpp | 46 ++++++++++++++++------- 6 files changed, 58 insertions(+), 28 deletions(-) diff --git a/include/Engine/Network/Packet.h b/include/Engine/Network/Packet.h index 112ebe34..2891bf87 100644 --- a/include/Engine/Network/Packet.h +++ b/include/Engine/Network/Packet.h @@ -14,6 +14,7 @@ public: Packet(MessageType type, unsigned int& packetID); // Used to create packet from already existing data buffer. Packet(char* data, const int sizeOfPacket); + Packet(MessageType type); ~Packet(); void Init(MessageType type, unsigned int& packetID); @@ -49,7 +50,7 @@ public: // Pops the first element as if it was a string. std::string ReadString(); char* ReadData(int SizeOfData); - + void ChangePacketID(unsigned int& packetID); int Size() { return m_Offset; }; char* Data() { return m_Data; }; unsigned int DataReadSize() { return m_ReturnDataOffset; } diff --git a/include/Engine/Network/PlayerDefinition.h b/include/Engine/Network/PlayerDefinition.h index dbacda95..4b8b8e6e 100644 --- a/include/Engine/Network/PlayerDefinition.h +++ b/include/Engine/Network/PlayerDefinition.h @@ -6,6 +6,8 @@ struct PlayerDefinition { int EntityID = -1; std::string Name = ""; boost::asio::ip::udp::endpoint Endpoint; + unsigned int PacketID; + std::clock_t StopTime; }; #endif diff --git a/include/Engine/Network/Server.h b/include/Engine/Network/Server.h index 9aba921a..3b871e43 100644 --- a/include/Engine/Network/Server.h +++ b/include/Engine/Network/Server.h @@ -43,16 +43,14 @@ private: //Timers std::clock_t m_StartPingTime; - std::clock_t m_StopTimes[8]; // Game logic World* m_World; EventBroker* m_EventBroker; // Packet loss logic - unsigned int m_PacketID; - unsigned int m_PreviousPacketID; - unsigned int m_SendPacketID; + unsigned int m_PacketID = 0; + unsigned int m_PreviousPacketID = 0; // Private member functions int receive(char* data, size_t length); @@ -73,8 +71,8 @@ private: void parseServerPing(); void identifyPacketLoss(); EntityID createPlayer(); + int GetPlayerIDFromEndpoint(boost::asio::ip::udp::endpoint endpoint); // Debug event - EventRelay m_EInputCommand; bool OnInputCommand(const Events::InputCommand& e); }; diff --git a/src/Engine/Network/Client.cpp b/src/Engine/Network/Client.cpp index ae71d0ae..fd6825b5 100644 --- a/src/Engine/Network/Client.cpp +++ b/src/Engine/Network/Client.cpp @@ -57,9 +57,7 @@ void Client::parseMessageType(Packet& packet) // Read packet ID m_PreviousPacketID = m_PacketID; // Set previous packet id m_PacketID = packet.ReadPrimitive(); //Read new packet id - if (m_PacketID <= m_PreviousPacketID) - return; - //IdentifyPacketLoss(); + identifyPacketLoss(); switch (static_cast(messageType)) { case MessageType::Connect: @@ -282,7 +280,7 @@ void Client::identifyPacketLoss() // if no packets lost, difference should be equal to 1 int difference = m_PacketID - m_PreviousPacketID; if (difference != 1) { - LOG_INFO("%i Packet(s) were lost...", difference); + LOG_INFO("%i Packet(s) were lost...", difference -1); } } diff --git a/src/Engine/Network/Packet.cpp b/src/Engine/Network/Packet.cpp index 568a78e3..6308a130 100644 --- a/src/Engine/Network/Packet.cpp +++ b/src/Engine/Network/Packet.cpp @@ -17,20 +17,26 @@ Packet::Packet(char* data, const int sizeOfPacket) m_Offset = sizeOfPacket; } +Packet::Packet(MessageType type) +{ + m_Data = new char[m_MaxPacketSize]; + unsigned int dummy = 0; + Init(type, dummy); +} + Packet::~Packet() { delete[] m_Data; } void Packet::Init(MessageType type, unsigned int & packetID) -{ +{ m_ReturnDataOffset = 0; m_Offset = 0; // Create message header // Add message type int messageType = static_cast(type); Packet::WritePrimitive(messageType); - packetID = packetID % 1000; // Packet id modulos Packet::WritePrimitive(packetID); packetID++; } @@ -80,14 +86,21 @@ char * Packet::ReadData(int SizeOfData) return (m_Data + oldReturnDataOffset); } +void Packet::ChangePacketID(unsigned int & packetID) +{ + packetID = packetID + 1; + // Overwrite old PacketID + memcpy(m_Data + sizeof(int), &packetID, sizeof(int)); +} + void Packet::resizeData() -{ +{ // Allocate memory to store our data in char* holdData = new char[m_MaxPacketSize]; // Copy our data to the newly allocated memory memcpy(holdData, m_Data, m_Offset); - // Increase max packet size + // Increase max packet size m_MaxPacketSize = m_MaxPacketSize * 2; // Delete our data delete m_Data; diff --git a/src/Engine/Network/Server.cpp b/src/Engine/Network/Server.cpp index 1f9db461..ce3a735c 100644 --- a/src/Engine/Network/Server.cpp +++ b/src/Engine/Network/Server.cpp @@ -16,7 +16,7 @@ void Server::Start(World* world, EventBroker* eventBroker) // Subscribe to events EVENT_SUBSCRIBE_MEMBER(m_EInputCommand, &Server::OnInputCommand); for (size_t i = 0; i < MAXCONNECTIONS; i++) { - m_StopTimes[i] = std::clock(); + m_PlayerDefinitions[i].StopTime = std::clock(); } LOG_INFO("I am Server. BIP BOP\n"); } @@ -66,7 +66,7 @@ void Server::parseMessageType(Packet& packet) // Read packet ID m_PreviousPacketID = m_PacketID; // Set previous packet id m_PacketID = packet.ReadPrimitive(); //Read new packet id - //IdentifyPacketLoss(); + //identifyPacketLoss(); switch (static_cast(messageType)) { case MessageType::Connect: parseConnect(packet); @@ -126,6 +126,7 @@ void Server::broadcast(Packet& packet) { for (int i = 0; i < MAXCONNECTIONS; ++i) { if (m_PlayerDefinitions[i].Endpoint.address() != boost::asio::ip::address()) { + packet.ChangePacketID(m_PlayerDefinitions[i].PacketID); send(packet, i); } } @@ -137,7 +138,7 @@ void Server::sendSnapshot() // Should time this std::unordered_map worldComponentPools = m_World->GetComponentPools(); for (auto& it : worldComponentPools) { - Packet packet(MessageType::Snapshot, m_SendPacketID); + Packet packet(MessageType::Snapshot); ComponentPool* componentPool = it.second; ComponentInfo componentInfo = componentPool->ComponentInfo(); // Component Type @@ -166,12 +167,12 @@ void Server::sendPing() // Prints connected players ping for (size_t i = 0; i < MAXCONNECTIONS; i++) { if (m_PlayerDefinitions[i].Endpoint.address() != boost::asio::ip::address()) { - int ping = 1000 * (m_StopTimes[i] - m_StartPingTime) / static_cast(CLOCKS_PER_SEC); - LOG_INFO("Last packetID received %i: Player %i's ping: %i", m_PacketID, i, ping); + int ping = 1000 * (m_PlayerDefinitions[i].StopTime - m_StartPingTime) / static_cast(CLOCKS_PER_SEC); + LOG_INFO("Last packetID received %i: Player %i's ping: %i", m_PlayerDefinitions[i].PacketID, i, ping); } } // Create ping message - Packet packet(MessageType::ServerPing, m_SendPacketID); + Packet packet(MessageType::ServerPing); packet.WriteString("Ping from server"); // Time message m_StartPingTime = std::clock(); @@ -187,8 +188,8 @@ void Server::checkForTimeOuts() for (size_t i = 0; i < MAXCONNECTIONS; i++) { if (m_PlayerDefinitions[i].Endpoint.address() != boost::asio::ip::address()) { - int stopPing = 1000 * m_StopTimes[i] - / static_cast(CLOCKS_PER_SEC); + int stopPing = 1000 * m_PlayerDefinitions[i].StopTime / + static_cast(CLOCKS_PER_SEC); if (startPing > stopPing + timeOutTimeMs) { LOG_INFO("Player %i timed out!", i); disconnect(i); @@ -206,6 +207,7 @@ void Server::disconnect(int i) m_PlayerDefinitions[i].Endpoint = boost::asio::ip::udp::endpoint(); m_PlayerDefinitions[i].EntityID = -1; m_PlayerDefinitions[i].Name = ""; + m_PlayerDefinitions[i].PacketID = 0; } void Server::parseOnInputCommand(Packet& packet) @@ -259,19 +261,20 @@ void Server::parseConnect(Packet& packet) m_PlayerDefinitions[i].EntityID = createPlayer(); m_PlayerDefinitions[i].Endpoint = m_ReceiverEndpoint; m_PlayerDefinitions[i].Name = packet.ReadString(); + m_PlayerDefinitions[i].PacketID = 0; - m_StopTimes[i] = std::clock(); + m_PlayerDefinitions[i].StopTime = std::clock(); LOG_INFO("Player \"%s\" connected on IP: %s", m_PlayerDefinitions[i].Name.c_str(), m_PlayerDefinitions[i].Endpoint.address().to_string().c_str()); // Send a message to the player that connected - Packet packet(MessageType::Connect, m_SendPacketID); + Packet packet(MessageType::Connect, m_PlayerDefinitions[i].PacketID); packet.WritePrimitive(i); // Player ID packet.WritePrimitive(m_PlayerDefinitions[i].EntityID); // Entity ID send(packet, i); // Send notification that a player has connected - Packet notificationPacket(MessageType::PlayerConnected, m_PacketID); + Packet notificationPacket(MessageType::PlayerConnected); broadcast(notificationPacket); break; @@ -294,17 +297,21 @@ void Server::parseDisconnect() void Server::parseClientPing() { LOG_INFO("%i: Parsing ping", m_PacketID); + int playerID = GetPlayerIDFromEndpoint(m_ReceiverEndpoint); + if (playerID == -1) { + return; + } // Return ping - Packet packet(MessageType::ClientPing, m_SendPacketID); + Packet packet(MessageType::ClientPing, m_PlayerDefinitions[playerID].PacketID); packet.WriteString("Ping received"); - send(packet); // This dosen't work for multiple users + send(packet); } void Server::parseServerPing() { for (int i = 0; i < MAXCONNECTIONS; i++) { if (m_PlayerDefinitions[i].Endpoint.address() == m_ReceiverEndpoint.address()) { - m_StopTimes[i] = std::clock(); + m_PlayerDefinitions[i].StopTime = std::clock(); break; } } @@ -331,6 +338,17 @@ EntityID Server::createPlayer() return entityID; } +int Server::GetPlayerIDFromEndpoint(boost::asio::ip::udp::endpoint endpoint) +{ + for (int i = 0; i < MAXCONNECTIONS; i++) { + if (m_PlayerDefinitions[i].Endpoint.address() == endpoint.address() && + m_PlayerDefinitions[i].Endpoint.port() == endpoint.port()) { + return i; + } + } + return -1; +} + bool Server::OnInputCommand(const Events::InputCommand & e) { //LOG_INFO("Server::OnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID);