Compare commits

...

1 Commits

Author SHA1 Message Date
Jocke ac0c6ff952 WIP started on reliable messages 2016-01-27 18:22:28 +01:00
10 changed files with 104 additions and 59 deletions
+1
View File
@@ -43,6 +43,7 @@ private:
PacketID m_PacketID = 0; PacketID m_PacketID = 0;
PacketID m_PreviousPacketID = 0; PacketID m_PreviousPacketID = 0;
PacketID m_SendPacketID = 0; PacketID m_SendPacketID = 0;
AckBitPattern ackBitField = 0;
// Game logic // Game logic
World* m_World; World* m_World;
+2
View File
@@ -11,10 +11,12 @@
#include "Core/ConfigFile.h" #include "Core/ConfigFile.h"
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
#include <bitset>
#define INPUTSIZE 4097 #define INPUTSIZE 4097
typedef unsigned int PlayerID; typedef unsigned int PlayerID;
typedef unsigned int PacketID; typedef unsigned int PacketID;
typedef unsigned int AckBitPattern;
class Network class Network
{ {
+5 -3
View File
@@ -11,12 +11,12 @@ class Packet
public: public:
// arg1: Type of message (Connect, Disconnect...) // arg1: Type of message (Connect, Disconnect...)
// arg2: PacketID for identifying packet loss. // 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. // Used to create packet from already existing data buffer.
Packet(char* data, const int sizeOfPacket); Packet(char* data, const int sizeOfPacket);
Packet(MessageType type); Packet(MessageType type);
~Packet(); ~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... // Add primitive types like int, float, char...
template<typename T> template<typename T>
@@ -50,7 +50,9 @@ public:
// Pops the first element as if it was a string. // Pops the first element as if it was a string.
std::string ReadString(); std::string ReadString();
char* ReadData(int SizeOfData); 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; }; int Size() { return m_Offset; };
char* Data() { return m_Data; }; char* Data() { return m_Data; };
unsigned int DataReadSize() { return m_ReturnDataOffset; } unsigned int DataReadSize() { return m_ReturnDataOffset; }
@@ -7,7 +7,13 @@ struct PlayerDefinition {
::EntityID EntityID = EntityID_Invalid; ::EntityID EntityID = EntityID_Invalid;
std::string Name = ""; std::string Name = "";
boost::asio::ip::udp::endpoint Endpoint; boost::asio::ip::udp::endpoint Endpoint;
// The ID of the last sent packet. (Local sequence number)
unsigned int PacketID; 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; std::clock_t StopTime;
}; };
+14 -13
View File
@@ -37,7 +37,7 @@ private:
char readBuffer[INPUTSIZE] = { 0 }; char readBuffer[INPUTSIZE] = { 0 };
int bytesRead = 0; int bytesRead = 0;
// time for previouse message // 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 previousSnapshotMessage = std::clock();
std::clock_t timOutTimer = std::clock(); std::clock_t timOutTimer = std::clock();
// How often we send messages (milliseconds) // How often we send messages (milliseconds)
@@ -58,25 +58,26 @@ private:
PacketID m_PreviousPacketID = 0; PacketID m_PreviousPacketID = 0;
// Private member functions // 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 addChildrenToPacket(Packet& packet, EntityID entityID);
void sendPing(); void broadcast(Packet& packet);
void checkForTimeOuts(); void checkForTimeOuts();
void disconnect(PlayerID playerID); 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 parseMessageType(Packet& packet);
void parseOnInputCommand(Packet& packet); void parseOnInputCommand(Packet& packet);
void parseOnPlayerDamage(Packet& packet); void parseOnPlayerDamage(Packet& packet);
void parseConnect(Packet& packet);
void parseDisconnect();
void parseClientPing();
void parsePing(); void parsePing();
void identifyPacketLoss();
void kick(PlayerID player);
PlayerID GetPlayerIDFromEndpoint(boost::asio::ip::udp::endpoint endpoint); PlayerID GetPlayerIDFromEndpoint(boost::asio::ip::udp::endpoint endpoint);
// Debug event // Debug event
EventRelay<Server, Events::InputCommand> m_EInputCommand; EventRelay<Server, Events::InputCommand> m_EInputCommand;
+7 -7
View File
@@ -130,7 +130,7 @@ void Client::parsePing()
LOG_INFO("%i: response time with ctime(ms): %f", m_PacketID, m_DurationOfPingTime); LOG_INFO("%i: response time with ctime(ms): %f", m_PacketID, m_DurationOfPingTime);
m_StartPingTime = std::clock(); m_StartPingTime = std::clock();
Packet packet(MessageType::Ping, m_SendPacketID); Packet packet(MessageType::Ping, m_SendPacketID, m_PacketID, ackBitField);
packet.WriteString("Ping recieved"); packet.WriteString("Ping recieved");
send(packet); send(packet);
} }
@@ -294,7 +294,7 @@ void Client::send(Packet& packet)
void Client::connect() void Client::connect()
{ {
Packet packet(MessageType::Connect, m_SendPacketID); Packet packet(MessageType::Connect, m_SendPacketID, m_PacketID, ackBitField);
packet.WriteString(m_PlayerName); packet.WriteString(m_PlayerName);
m_StartPingTime = std::clock(); m_StartPingTime = std::clock();
send(packet); send(packet);
@@ -304,7 +304,7 @@ void Client::disconnect()
{ {
m_PreviousPacketID = 0; m_PreviousPacketID = 0;
m_PacketID = 0; m_PacketID = 0;
Packet packet(MessageType::Disconnect, m_SendPacketID); Packet packet(MessageType::Disconnect, m_SendPacketID, m_PacketID, ackBitField);
send(packet); send(packet);
} }
@@ -344,7 +344,7 @@ bool Client::OnInputCommand(const Events::InputCommand & e)
bool Client::OnPlayerDamage(const Events::PlayerDamage & 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.Damage);
packet.WritePrimitive(e.Player.ID); packet.WritePrimitive(e.Player.ID);
send(packet); send(packet);
@@ -368,7 +368,7 @@ void Client::sendLocalPlayerTransform()
ComponentWrapper cTransform = m_LocalPlayer["Transform"]; ComponentWrapper cTransform = m_LocalPlayer["Transform"];
glm::vec3& position = cTransform["Position"]; glm::vec3& position = cTransform["Position"];
glm::vec3& orientation = cTransform["Orientation"]; 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.x);
packet.WritePrimitive(position.y); packet.WritePrimitive(position.y);
packet.WritePrimitive(position.z); packet.WritePrimitive(position.z);
@@ -413,7 +413,7 @@ EntityID Client::createPlayer()
void Client::sendInputCommands() void Client::sendInputCommands()
{ {
if (m_InputCommandBuffer.size() > 0) { 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++) { for (int i = 0; i < m_InputCommandBuffer.size(); i++) {
packet.WriteString(m_InputCommandBuffer[i].Command); packet.WriteString(m_InputCommandBuffer[i].Command);
packet.WritePrimitive(m_InputCommandBuffer[i].Value); packet.WritePrimitive(m_InputCommandBuffer[i].Value);
@@ -425,7 +425,7 @@ void Client::sendInputCommands()
void Client::becomePlayer() void Client::becomePlayer()
{ {
Packet packet = Packet(MessageType::BecomePlayer, m_SendPacketID); Packet packet(MessageType::BecomePlayer, m_SendPacketID, m_PacketID, ackBitField);
send(packet); send(packet);
} }
+28 -9
View File
@@ -1,9 +1,9 @@
#include "Network/Packet.h" #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]; m_Data = new char[m_MaxPacketSize];
Init(type, packetID); Init(type, packetID, lastReceivedPacket, ackBitField);
} }
// Create message // Create message
@@ -21,7 +21,9 @@ Packet::Packet(MessageType type)
{ {
m_Data = new char[m_MaxPacketSize]; m_Data = new char[m_MaxPacketSize];
unsigned int dummy = 0; unsigned int dummy = 0;
Init(type, dummy); // Dummy allocates memory for later insertion of
// correct values
Init(type, dummy, dummy, dummy);
} }
Packet::~Packet() Packet::~Packet()
@@ -29,15 +31,17 @@ Packet::~Packet()
delete[] m_Data; 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_ReturnDataOffset = 0;
m_Offset = 0; m_Offset = 0;
// Create message header // Create message header
// Add message type // Add message type
int messageType = static_cast<int>(type); int messageType = static_cast<int>(type);
Packet::WritePrimitive<int>(messageType); WritePrimitive<int>(messageType);
Packet::WritePrimitive<int>(packetID); WritePrimitive<unsigned int>(packetID);
WritePrimitive<unsigned int>(lastReceivedPacket);
WritePrimitive<unsigned int>(ackBitField);
packetID++; packetID++;
m_HeaderSize = m_Offset; m_HeaderSize = m_Offset;
} }
@@ -87,16 +91,31 @@ char * Packet::ReadData(int SizeOfData)
return (m_Data + oldReturnDataOffset); 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; packetID = packetID + 1;
// Start at sizeOf(int) cause of MessageType
int offset = sizeof(int);
// Overwrite old PacketID // 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() void Packet::resizeData()
{ {
// Allocate memory to store our data in // Allocate memory to store our data in
char* holdData = new char[m_MaxPacketSize]; char* holdData = new char[m_MaxPacketSize];
// Copy our data to the newly allocated memory // Copy our data to the newly allocated memory
+38 -24
View File
@@ -32,6 +32,16 @@ void Server::Update()
m_EventBroker->Process<Server>(); m_EventBroker->Process<Server>();
if (isReadingData) { if (isReadingData) {
Network::Update(); 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<unsigned int>(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 // Send pings each
if (pingIntervalMs < (1000 * (currentTime - previousePingMessage) / (double)CLOCKS_PER_SEC)) { if (pingIntervalMs < (1000 * (currentTime - previousPingMessage) / (double)CLOCKS_PER_SEC)) {
sendPing(); sendPing();
previousePingMessage = currentTime; previousPingMessage = currentTime;
} }
// Time out logic // Time out logic
@@ -69,15 +79,19 @@ void Server::readFromClients()
void Server::parseMessageType(Packet& packet) void Server::parseMessageType(Packet& packet)
{ {
int messageType = packet.ReadPrimitive<int>(); // Read what type off message was sent from server PlayerID playerID = GetPlayerIDFromEndpoint(m_ReceiverEndpoint);
int messageType = packet.ReadPrimitive<int>(); // Read what type off message was sent from server
// Read packet ID // Read packet ID
m_PreviousPacketID = m_PacketID; // Set previous packet id if (playerID != -1) {
m_PacketID = packet.ReadPrimitive<int>(); //Read new packet id // TODO: Bit pattern stuff!"#!"#
m_ConnectedPlayers[playerID].LastPacketReceivedID = packet.ReadPrimitive<PacketID>();
}
//identifyPacketLoss(); //identifyPacketLoss();
switch (static_cast<MessageType>(messageType)) { switch (static_cast<MessageType>(messageType)) {
case MessageType::Connect: case MessageType::Connect:
parseConnect(packet); parseConnect(packet, playerID);
break; break;
case MessageType::Ping: case MessageType::Ping:
parsePing(); parsePing();
@@ -118,12 +132,12 @@ int Server::receive(char * data)
return length; return length;
} }
void Server::send(PlayerID player, Packet& packet) void Server::send(PlayerID playerID, Packet& packet)
{ {
try { try {
int bytesSent = m_Socket.send_to( int bytesSent = m_Socket.send_to(
boost::asio::buffer(packet.Data(), packet.Size()), boost::asio::buffer(packet.Data(), packet.Size()),
m_ConnectedPlayers[player].Endpoint, m_ConnectedPlayers[playerID].Endpoint,
0); 0);
// Network Debug data // Network Debug data
if (isReadingData) { if (isReadingData) {
@@ -133,7 +147,7 @@ void Server::send(PlayerID player, Packet& packet)
} }
} catch (const boost::system::system_error& e) { } catch (const boost::system::system_error& e) {
// TODO: Clean up invalid endpoints out of m_ConnectedPlayers later // 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) void Server::broadcast(Packet& packet)
{ {
for (auto& kv : m_ConnectedPlayers) { 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); 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()); //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"); LOG_INFO("Parsing connections");
// Check if player is already connected // Check if player is already connected
if (GetPlayerIDFromEndpoint(m_ReceiverEndpoint) != -1) { if (playerID != -1) {
return; 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 // Create a new player
PlayerDefinition pd; PlayerDefinition pd;
pd.EntityID = 0; // Overlook this pd.EntityID = 0; // Overlook this
@@ -306,11 +317,11 @@ void Server::parseConnect(Packet& packet)
pd.Name = packet.ReadString(); pd.Name = packet.ReadString();
pd.PacketID = 0; pd.PacketID = 0;
pd.StopTime = std::clock(); pd.StopTime = std::clock();
Packet connnectPacket(MessageType::Connect, pd.PacketID, pd.LastPacketReceivedID, pd.AckBitField);
m_ConnectedPlayers[m_NextPlayerID++] = pd; m_ConnectedPlayers[m_NextPlayerID++] = pd;
LOG_INFO("Spectator \"%s\" connected on IP: %s", pd.Name.c_str(), pd.Endpoint.address().to_string().c_str()); 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 // Send a message to the player that connected
Packet connnectPacket(MessageType::Connect, pd.PacketID);
send(connnectPacket); send(connnectPacket);
// Send notification that a player has connected // 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) { if (player == -1) {
return; return;
} }
// Return ping // 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"); packet.WriteString("Ping received");
send(packet); send(packet);
} }
+1 -1
View File
@@ -29,7 +29,7 @@ void RayTest(std::string fileName) {
Ray ray(glm::vec3(-50, 0, 0), glm::vec3(1, 0, 0)); Ray ray(glm::vec3(-50, 0, 0), glm::vec3(1, 0, 0));
//using a //using a
here, else we have to init the renderingsystem //here, else we have to init the renderingsystem
ResourceManager::RegisterType<RawModel>("RawModel"); ResourceManager::RegisterType<RawModel>("RawModel");
auto unitBox = ResourceManager::Load<RawModel>(fileName); auto unitBox = ResourceManager::Load<RawModel>(fileName);
BOOST_REQUIRE(unitBox != nullptr); BOOST_REQUIRE(unitBox != nullptr);
+2 -2
View File
@@ -69,8 +69,8 @@ GameHealthSystemTest::GameHealthSystemTest()
m_EventBroker->Publish(e3); m_EventBroker->Publish(e3);
//damage player with 50 //damage player with 50
Events::PlayerDamage e; Events::PlayerDamage e;
e.DamageAmount = 50.0f; e.Damage = 50.0f;
e.PlayerDamagedID = healthsID; //e.Player = healthsID;
m_EventBroker->Publish(e); m_EventBroker->Publish(e);
//heal some other player with 40 //heal some other player with 40
Events::PlayerHealthPickup e2; Events::PlayerHealthPickup e2;