From ac0c6ff9528d0377f32063ce67244139d7fddde5 Mon Sep 17 00:00:00 2001 From: Jocke Date: Wed, 27 Jan 2016 18:22:28 +0100 Subject: [PATCH] WIP started on reliable messages --- include/Engine/Network/Client.h | 1 + include/Engine/Network/Network.h | 2 + include/Engine/Network/Packet.h | 8 +-- include/Engine/Network/PlayerDefinition.h | 6 +++ include/Engine/Network/Server.h | 27 +++++----- src/Engine/Network/Client.cpp | 14 ++--- src/Engine/Network/Packet.cpp | 37 ++++++++++---- src/Engine/Network/Server.cpp | 62 ++++++++++++++--------- src/Tests/CollisionTest.cpp | 2 +- src/Tests/HealthSystemTest.cpp | 4 +- 10 files changed, 104 insertions(+), 59 deletions(-) diff --git a/include/Engine/Network/Client.h b/include/Engine/Network/Client.h index 4f1baa67..b52d3402 100644 --- a/include/Engine/Network/Client.h +++ b/include/Engine/Network/Client.h @@ -43,6 +43,7 @@ private: PacketID m_PacketID = 0; PacketID m_PreviousPacketID = 0; PacketID m_SendPacketID = 0; + AckBitPattern ackBitField = 0; // Game logic World* m_World; diff --git a/include/Engine/Network/Network.h b/include/Engine/Network/Network.h index 03fcc0f3..87b6bbd9 100644 --- a/include/Engine/Network/Network.h +++ b/include/Engine/Network/Network.h @@ -11,10 +11,12 @@ #include "Core/ConfigFile.h" #include #include +#include #define INPUTSIZE 4097 typedef unsigned int PlayerID; typedef unsigned int PacketID; +typedef unsigned int AckBitPattern; class Network { diff --git a/include/Engine/Network/Packet.h b/include/Engine/Network/Packet.h index d38ddf58..653023d8 100644 --- a/include/Engine/Network/Packet.h +++ b/include/Engine/Network/Packet.h @@ -11,12 +11,12 @@ class Packet public: // arg1: Type of message (Connect, Disconnect...) // arg2: PacketID for identifying packet loss. - Packet(MessageType type, unsigned int& packetID); + Packet(MessageType type, unsigned int& packetID, unsigned int lastReceivedPacket, unsigned int ackBitField); // 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); + void Init(MessageType type, unsigned int& packetID, unsigned int lastReceivedPacket, unsigned int ackBitField); // Add primitive types like int, float, char... template @@ -50,7 +50,9 @@ public: // Pops the first element as if it was a string. std::string ReadString(); char* ReadData(int SizeOfData); - void ChangePacketID(unsigned int& packetID); + // No purpose any more + //void ChangePacketID(unsigned int& packetID); + void ChangeHeaderInfo(unsigned int& packetID, unsigned int lastReceivedPacket, unsigned int ackBitField); 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 863948b3..2a72c87f 100644 --- a/include/Engine/Network/PlayerDefinition.h +++ b/include/Engine/Network/PlayerDefinition.h @@ -7,7 +7,13 @@ struct PlayerDefinition { ::EntityID EntityID = EntityID_Invalid; std::string Name = ""; boost::asio::ip::udp::endpoint Endpoint; + // The ID of the last sent packet. (Local sequence number) unsigned int PacketID; + // The ID of the last received packet. (Remote sequence number) + // This is sent as the ackNumber. + unsigned int LastPacketReceivedID; + // The bit pattern of the last 32 received packets. + unsigned int AckBitField; std::clock_t StopTime; }; diff --git a/include/Engine/Network/Server.h b/include/Engine/Network/Server.h index 17029809..9c934aeb 100644 --- a/include/Engine/Network/Server.h +++ b/include/Engine/Network/Server.h @@ -37,7 +37,7 @@ private: char readBuffer[INPUTSIZE] = { 0 }; int bytesRead = 0; // time for previouse message - std::clock_t previousePingMessage = std::clock(); + std::clock_t previousPingMessage = std::clock(); std::clock_t previousSnapshotMessage = std::clock(); std::clock_t timOutTimer = std::clock(); // How often we send messages (milliseconds) @@ -58,25 +58,26 @@ private: PacketID m_PreviousPacketID = 0; // Private member functions - int receive(char* data); - void readFromClients(); - void send(PlayerID player, Packet& packet); - void send(Packet& packet); - void broadcast(Packet& packet); - void sendSnapshot(); void addChildrenToPacket(Packet& packet, EntityID entityID); - void sendPing(); + void broadcast(Packet& packet); void checkForTimeOuts(); void disconnect(PlayerID playerID); + void identifyPacketLoss(); + void kick(PlayerID player); + int receive(char* data); + void readFromClients(); + void send(PlayerID playerID, Packet& packet); + void send(Packet& packet); + void sendSnapshot(); + void sendPing(); + void parseClientPing(PlayerID playerID); + void parseConnect(Packet& packet, PlayerID playerID); + void parseDisconnect(); 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); // Debug event EventRelay m_EInputCommand; diff --git a/src/Engine/Network/Client.cpp b/src/Engine/Network/Client.cpp index 05e9da61..97b0226d 100644 --- a/src/Engine/Network/Client.cpp +++ b/src/Engine/Network/Client.cpp @@ -130,7 +130,7 @@ void Client::parsePing() LOG_INFO("%i: response time with ctime(ms): %f", m_PacketID, m_DurationOfPingTime); m_StartPingTime = std::clock(); - Packet packet(MessageType::Ping, m_SendPacketID); + Packet packet(MessageType::Ping, m_SendPacketID, m_PacketID, ackBitField); packet.WriteString("Ping recieved"); send(packet); } @@ -294,7 +294,7 @@ void Client::send(Packet& packet) void Client::connect() { - Packet packet(MessageType::Connect, m_SendPacketID); + Packet packet(MessageType::Connect, m_SendPacketID, m_PacketID, ackBitField); packet.WriteString(m_PlayerName); m_StartPingTime = std::clock(); send(packet); @@ -304,7 +304,7 @@ void Client::disconnect() { m_PreviousPacketID = 0; m_PacketID = 0; - Packet packet(MessageType::Disconnect, m_SendPacketID); + Packet packet(MessageType::Disconnect, m_SendPacketID, m_PacketID, ackBitField); send(packet); } @@ -344,7 +344,7 @@ bool Client::OnInputCommand(const Events::InputCommand & e) bool Client::OnPlayerDamage(const Events::PlayerDamage & e) { - Packet packet(MessageType::OnPlayerDamage, m_SendPacketID); + Packet packet(MessageType::OnPlayerDamage, m_SendPacketID, m_PacketID, ackBitField); packet.WritePrimitive(e.Damage); packet.WritePrimitive(e.Player.ID); send(packet); @@ -368,7 +368,7 @@ void Client::sendLocalPlayerTransform() ComponentWrapper cTransform = m_LocalPlayer["Transform"]; glm::vec3& position = cTransform["Position"]; glm::vec3& orientation = cTransform["Orientation"]; - Packet packet(MessageType::PlayerTransform, m_SendPacketID); + Packet packet(MessageType::PlayerTransform, m_SendPacketID, m_PacketID, ackBitField); packet.WritePrimitive(position.x); packet.WritePrimitive(position.y); packet.WritePrimitive(position.z); @@ -413,7 +413,7 @@ EntityID Client::createPlayer() void Client::sendInputCommands() { if (m_InputCommandBuffer.size() > 0) { - Packet packet(MessageType::OnInputCommand, m_SendPacketID); + Packet packet(MessageType::OnInputCommand, m_SendPacketID, m_PacketID, ackBitField); for (int i = 0; i < m_InputCommandBuffer.size(); i++) { packet.WriteString(m_InputCommandBuffer[i].Command); packet.WritePrimitive(m_InputCommandBuffer[i].Value); @@ -425,7 +425,7 @@ void Client::sendInputCommands() void Client::becomePlayer() { - Packet packet = Packet(MessageType::BecomePlayer, m_SendPacketID); + Packet packet(MessageType::BecomePlayer, m_SendPacketID, m_PacketID, ackBitField); send(packet); } diff --git a/src/Engine/Network/Packet.cpp b/src/Engine/Network/Packet.cpp index d40a1b32..3026c821 100644 --- a/src/Engine/Network/Packet.cpp +++ b/src/Engine/Network/Packet.cpp @@ -1,9 +1,9 @@ #include "Network/Packet.h" -Packet::Packet(MessageType type, unsigned int& packetID) +Packet::Packet(MessageType type, unsigned int& packetID, unsigned int lastReceivedPacket, unsigned int ackBitField) { m_Data = new char[m_MaxPacketSize]; - Init(type, packetID); + Init(type, packetID, lastReceivedPacket, ackBitField); } // Create message @@ -21,7 +21,9 @@ Packet::Packet(MessageType type) { m_Data = new char[m_MaxPacketSize]; unsigned int dummy = 0; - Init(type, dummy); + // Dummy allocates memory for later insertion of + // correct values + Init(type, dummy, dummy, dummy); } Packet::~Packet() @@ -29,15 +31,17 @@ Packet::~Packet() delete[] m_Data; } -void Packet::Init(MessageType type, unsigned int & packetID) +void Packet::Init(MessageType type, unsigned int & packetID, unsigned int lastReceivedPacket, unsigned int ackBitField) { m_ReturnDataOffset = 0; m_Offset = 0; // Create message header // Add message type int messageType = static_cast(type); - Packet::WritePrimitive(messageType); - Packet::WritePrimitive(packetID); + WritePrimitive(messageType); + WritePrimitive(packetID); + WritePrimitive(lastReceivedPacket); + WritePrimitive(ackBitField); packetID++; m_HeaderSize = m_Offset; } @@ -87,16 +91,31 @@ char * Packet::ReadData(int SizeOfData) return (m_Data + oldReturnDataOffset); } -void Packet::ChangePacketID(unsigned int & packetID) +//void Packet::ChangePacketID(unsigned int & packetID) +//{ +// packetID = packetID + 1; +// // Overwrite old PacketID +// memcpy(m_Data + sizeof(int), &packetID, sizeof(int)); +//} + +void Packet::ChangeHeaderInfo(unsigned int& packetID, unsigned int lastReceivedPacket, unsigned int ackBitField) { packetID = packetID + 1; + // Start at sizeOf(int) cause of MessageType + int offset = sizeof(int); // Overwrite old PacketID - memcpy(m_Data + sizeof(int), &packetID, sizeof(int)); + memcpy(m_Data + sizeof(unsigned int), &packetID, offset); + offset += sizeof(unsigned int); + // Overwrite old LastReceivedPacket + memcpy(m_Data + sizeof(unsigned int), &lastReceivedPacket, offset); + offset += sizeof(unsigned int); + // Overwrite old ackBitField + memcpy(m_Data + sizeof(unsigned int), &ackBitField, offset); + offset += sizeof(unsigned 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 diff --git a/src/Engine/Network/Server.cpp b/src/Engine/Network/Server.cpp index 30676d80..756e886d 100644 --- a/src/Engine/Network/Server.cpp +++ b/src/Engine/Network/Server.cpp @@ -32,6 +32,16 @@ void Server::Update() m_EventBroker->Process(); if (isReadingData) { Network::Update(); + // Test bit patterns + //std::bitset<32> bitPattern; + //bitPattern[0].flip(); + //bitPattern[15].flip(); + //bitPattern[31].flip(); + //std::cout << "bitPattern: " << bitPattern << '\n'; + //unsigned int bitPatternInt = static_cast(bitPattern.to_ulong()); + //std::cout << "Int pattern: " << bitPatternInt << '\n'; + //std::bitset<32> bitPatternRev(bitPatternInt); + //std::cout << "bitPatternReverted: " << bitPatternRev << '\n'; } } @@ -55,9 +65,9 @@ void Server::readFromClients() } // Send pings each - if (pingIntervalMs < (1000 * (currentTime - previousePingMessage) / (double)CLOCKS_PER_SEC)) { + if (pingIntervalMs < (1000 * (currentTime - previousPingMessage) / (double)CLOCKS_PER_SEC)) { sendPing(); - previousePingMessage = currentTime; + previousPingMessage = currentTime; } // Time out logic @@ -69,15 +79,19 @@ void Server::readFromClients() void Server::parseMessageType(Packet& packet) { - int messageType = packet.ReadPrimitive(); // Read what type off message was sent from server + PlayerID playerID = GetPlayerIDFromEndpoint(m_ReceiverEndpoint); + 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 + if (playerID != -1) { + // TODO: Bit pattern stuff!"#!"# + m_ConnectedPlayers[playerID].LastPacketReceivedID = packet.ReadPrimitive(); + } + //identifyPacketLoss(); switch (static_cast(messageType)) { case MessageType::Connect: - parseConnect(packet); + parseConnect(packet, playerID); break; case MessageType::Ping: parsePing(); @@ -118,12 +132,12 @@ int Server::receive(char * data) return length; } -void Server::send(PlayerID player, Packet& packet) +void Server::send(PlayerID playerID, Packet& packet) { try { int bytesSent = m_Socket.send_to( boost::asio::buffer(packet.Data(), packet.Size()), - m_ConnectedPlayers[player].Endpoint, + m_ConnectedPlayers[playerID].Endpoint, 0); // Network Debug data if (isReadingData) { @@ -133,7 +147,7 @@ void Server::send(PlayerID player, Packet& packet) } } 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(); + m_ConnectedPlayers[playerID].Endpoint = boost::asio::ip::udp::endpoint(); } } @@ -155,7 +169,11 @@ void Server::send(Packet & packet) void Server::broadcast(Packet& packet) { for (auto& kv : m_ConnectedPlayers) { - packet.ChangePacketID(kv.second.PacketID); + packet.ChangeHeaderInfo( + kv.second.PacketID, + kv.second.LastPacketReceivedID, + kv.second.AckBitField + ); send(kv.first, packet); } } @@ -285,20 +303,13 @@ 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) +void Server::parseConnect(Packet& packet, PlayerID playerID) { LOG_INFO("Parsing connections"); // Check if player is already connected - if (GetPlayerIDFromEndpoint(m_ReceiverEndpoint) != -1) { + if (playerID != -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 @@ -306,11 +317,11 @@ void Server::parseConnect(Packet& packet) pd.Name = packet.ReadString(); pd.PacketID = 0; pd.StopTime = std::clock(); + Packet connnectPacket(MessageType::Connect, pd.PacketID, pd.LastPacketReceivedID, pd.AckBitField); 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 @@ -331,15 +342,18 @@ void Server::parseDisconnect() } } -void Server::parseClientPing() +void Server::parseClientPing(PlayerID player) { - 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 packet( + MessageType::Ping, + m_ConnectedPlayers[player].PacketID, + m_ConnectedPlayers[player].LastPacketReceivedID, + m_ConnectedPlayers[player].AckBitField + ); packet.WriteString("Ping received"); send(packet); } diff --git a/src/Tests/CollisionTest.cpp b/src/Tests/CollisionTest.cpp index 67b6ce19..6cb6c88b 100644 --- a/src/Tests/CollisionTest.cpp +++ b/src/Tests/CollisionTest.cpp @@ -29,7 +29,7 @@ void RayTest(std::string fileName) { Ray ray(glm::vec3(-50, 0, 0), glm::vec3(1, 0, 0)); //using a - here, else we have to init the renderingsystem + //here, else we have to init the renderingsystem ResourceManager::RegisterType("RawModel"); auto unitBox = ResourceManager::Load(fileName); BOOST_REQUIRE(unitBox != nullptr); diff --git a/src/Tests/HealthSystemTest.cpp b/src/Tests/HealthSystemTest.cpp index bdd9ba4b..08bd22dc 100644 --- a/src/Tests/HealthSystemTest.cpp +++ b/src/Tests/HealthSystemTest.cpp @@ -69,8 +69,8 @@ GameHealthSystemTest::GameHealthSystemTest() m_EventBroker->Publish(e3); //damage player with 50 Events::PlayerDamage e; - e.DamageAmount = 50.0f; - e.PlayerDamagedID = healthsID; + e.Damage = 50.0f; + //e.Player = healthsID; m_EventBroker->Publish(e); //heal some other player with 40 Events::PlayerHealthPickup e2;