From 7ae42a5bf7e7ccb1a789a7257f8d56228b01ccf7 Mon Sep 17 00:00:00 2001 From: stiffly Date: Wed, 6 Jan 2016 11:39:32 +0100 Subject: [PATCH 01/27] Removed some comments. Basically did nothing --- include/Engine/Network/Network.h | 1 + src/Engine/Input/InputProxy.cpp | 4 ++-- src/Engine/Network/Client.cpp | 14 +++++--------- src/Engine/Network/Server.cpp | 8 ++++++-- src/Game/Game.cpp | 13 ++++++------- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/include/Engine/Network/Network.h b/include/Engine/Network/Network.h index 0f7baefe..c5107b2b 100644 --- a/include/Engine/Network/Network.h +++ b/include/Engine/Network/Network.h @@ -14,6 +14,7 @@ public: virtual ~Network() { }; virtual void Start(World* m_world, EventBroker *eventBroker) = 0; virtual void Update() = 0; + virtual void Close() = 0; }; #endif \ No newline at end of file diff --git a/src/Engine/Input/InputProxy.cpp b/src/Engine/Input/InputProxy.cpp index c3e4d669..ad589df3 100644 --- a/src/Engine/Input/InputProxy.cpp +++ b/src/Engine/Input/InputProxy.cpp @@ -62,7 +62,7 @@ void InputProxy::Process() e.Command = command; e.Value = currentValue; m_EventBroker->Publish(e); - LOG_DEBUG("Input: Published command %s=%f for player %i", e.Command.c_str(), e.Value, e.PlayerID); + //LOG_DEBUG("Input: Published command %s=%f for player %i", e.Command.c_str(), e.Value, e.PlayerID); m_LastCommandValues[command] = currentValue; } } @@ -78,7 +78,7 @@ void InputProxy::Process() } //e.Value = std::max(-1.f, std::min(e.Value, 1.f)); m_EventBroker->Publish(e); - LOG_DEBUG("Input: Published command %s=%f for player %i", e.Command.c_str(), e.Value, e.PlayerID); + //LOG_DEBUG("Input: Published command %s=%f for player %i", e.Command.c_str(), e.Value, e.PlayerID); } m_CommandQueue.clear(); } diff --git a/src/Engine/Network/Client.cpp b/src/Engine/Network/Client.cpp index 5c7e9c8f..a417c4e5 100644 --- a/src/Engine/Network/Client.cpp +++ b/src/Engine/Network/Client.cpp @@ -17,7 +17,7 @@ Client::Client(ConfigFile* config) : m_Socket(m_IOService) Client::~Client() { - + m_EventBroker->Unsubscribe(m_EInputCommand); } void Client::Start(World* world, EventBroker* eventBroker) @@ -27,14 +27,10 @@ void Client::Start(World* world, EventBroker* eventBroker) m_World = world; // Subscribe to events - m_EInputCommand = decltype(m_EInputCommand)(std::bind(&Client::OnInputCommand, this, std::placeholders::_1)); - m_EventBroker->Subscribe(m_EInputCommand); + //m_EInputCommand = decltype(m_EInputCommand)(std::bind(&Client::OnInputCommand, this, std::placeholders::_1)); + //m_EventBroker->Subscribe(m_EInputCommand); + EVENT_SUBSCRIBE_MEMBER(m_EInputCommand, &Client::OnInputCommand); - - //while (m_PlayerName.size() > 7) { - // LOG_INFO("Please enter your name (No longer than 7 characters):"); - // std::cin >> m_PlayerName; - //} m_Socket.connect(m_ReceiverEndpoint); LOG_INFO("I am client. BIP BOP"); } @@ -73,7 +69,7 @@ void Client::readFromServer() void Client::sendSnapshotToServer() { - // Reset previouse key state in snapshot. + // Reset previous key state in snapshot. m_NextSnapshot.InputForward = ""; m_NextSnapshot.InputRight = ""; diff --git a/src/Engine/Network/Server.cpp b/src/Engine/Network/Server.cpp index 261583cc..c53dce8f 100644 --- a/src/Engine/Network/Server.cpp +++ b/src/Engine/Network/Server.cpp @@ -4,7 +4,9 @@ Server::Server() : m_Socket(m_IOService, boost::asio::ip::udp::endpoint(boost::a { } Server::~Server() -{ } +{ + +} void Server::Start(World* world, EventBroker* eventBroker) @@ -25,6 +27,8 @@ void Server::Update() void Server::Close() { m_ThreadIsRunning = false; + m_Socket.close(); + } void Server::readFromClients() @@ -271,7 +275,7 @@ void Server::parseConnect(Packet& packet) m_StopTimes[i] = std::clock(); - LOG_INFO("Player \"%s\" connected on IP: %s", m_PlayerDefinitions[i].Name, m_PlayerDefinitions[i].Endpoint.address().to_string()); + LOG_INFO("Player \"%s\" connected on IP: %s", m_PlayerDefinitions[i].Name.c_str(), m_PlayerDefinitions[i].Endpoint.address().to_string().c_str()); Packet packet(MessageType::Connect, m_SendPacketID); packet.WritePrimitive(i); // Player ID diff --git a/src/Game/Game.cpp b/src/Game/Game.cpp index f1582d5d..d8bebea6 100644 --- a/src/Game/Game.cpp +++ b/src/Game/Game.cpp @@ -128,11 +128,15 @@ bool Game::debugOnInputCommand(const Events::InputCommand& e) } } if (e.Command == "SwitchToServer" && e.Value > 0) { + m_ClientOrServer->Close(); // memory leak for now, use delete when it works + //delete m_ClientOrServer; m_ClientOrServer = new Server(); LOG_INFO("Switching to server"); m_ClientOrServer->Start(m_World, m_EventBroker); } - if (e.Command == "SwitchToClient" && e.Value > 0) { + else if (e.Command == "SwitchToClient" && e.Value > 0) { + m_ClientOrServer->Close(); // memory leak for now, use delete when it works + //delete m_ClientOrServer; m_ClientOrServer = new Client(m_Config); m_ClientOrServer->Start(m_World, m_EventBroker); LOG_INFO("Switching to client"); @@ -163,10 +167,5 @@ void Game::networkFunction() m_ClientOrServer = new Server(); } m_ClientOrServer->Start(m_World, m_EventBroker); - // I don't think we are reaching this part of the code right now. - // ~Game() is not called if the game is exited by closing console windows - // When server or client is done set it to false. - //m_IsClientOrServer = false; - // Destroy it - //delete m_ClientOrServer; + } \ No newline at end of file From f47f913bf571c824fc31766ffdd7792f0f4244bc Mon Sep 17 00:00:00 2001 From: Jocke Date: Wed, 13 Jan 2016 16:09:16 +0100 Subject: [PATCH 02/27] Added logic for sending input from Client to Server. Fixed so that snapshots set their parent correctly. Will get problems if we have more components than unsigned int max size, but that was already a problem. Client now maps Entitys received from server with local Entitys by mapping their EntityIDs. --- include/Engine/Network/Client.h | 9 +++- include/Engine/Network/Server.h | 2 +- src/Engine/Network/Client.cpp | 83 +++++++++++++++++++-------------- src/Engine/Network/Server.cpp | 51 ++++---------------- 4 files changed, 65 insertions(+), 80 deletions(-) diff --git a/include/Engine/Network/Client.h b/include/Engine/Network/Client.h index a5488210..da734810 100644 --- a/include/Engine/Network/Client.h +++ b/include/Engine/Network/Client.h @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -45,6 +46,10 @@ private: std::string m_PlayerName; int m_PlayerID = -1; + // Server Client Lookup map + // Assumes that root node for client and server is EntityID 0. + std::unordered_map m_ServerToClientMap; + // Network logic PlayerDefinition m_PlayerDefinitions[MAXCONNECTIONS]; SnapshotDefinitions m_NextSnapshot; @@ -56,7 +61,7 @@ private: // Private member functions void readFromServer(); - void sendSnapshotToServer(); + void sendInputEvents(); int receive(char* data, size_t length); void send(Packet& packet); void connect(); @@ -73,7 +78,7 @@ private: void identifyPacketLoss(); bool isConnected(); EntityID createPlayer(); - + bool hasMappedEntity(EntityID entityID); // Events EventBroker* m_EventBroker; EventRelay m_EInputCommand; diff --git a/include/Engine/Network/Server.h b/include/Engine/Network/Server.h index 893eed0b..84d8c143 100644 --- a/include/Engine/Network/Server.h +++ b/include/Engine/Network/Server.h @@ -12,6 +12,7 @@ #include "Core/World.h" #include "Core/EventBroker.h" #include "Network/Network.h" +#include "Input/EInputCommand.h" class Server : public Network { @@ -72,7 +73,6 @@ private: void parseDisconnect(); void parseClientPing(); void parseServerPing(); - void parseSnapshot(Packet& packet); void identifyPacketLoss(); EntityID createPlayer(); }; diff --git a/src/Engine/Network/Client.cpp b/src/Engine/Network/Client.cpp index b8849ed0..3ecee0e0 100644 --- a/src/Engine/Network/Client.cpp +++ b/src/Engine/Network/Client.cpp @@ -5,6 +5,8 @@ using namespace boost::asio::ip; Client::Client(ConfigFile* config) : m_Socket(m_IOService) { + // Asumes root node is EntityID 0 + m_ServerToClientMap.insert(std::make_pair(0, 0)); // Default is local host std::string address = config->Get("Networking.Address", "127.0.0.1"); int port = config->Get("Networking.Port", 13); @@ -16,8 +18,7 @@ Client::Client(ConfigFile* config) : m_Socket(m_IOService) } Client::~Client() -{ -} +{ } void Client::Start(World* world, EventBroker* eventBroker) { @@ -55,7 +56,7 @@ void Client::readFromServer() } } -void Client::sendSnapshotToServer() +void Client::sendInputEvents() { // Reset previous key state in snapshot. m_NextSnapshot.InputForward = ""; @@ -187,9 +188,16 @@ void Client::parseSnapshot(Packet& packet) { std::string componentType = packet.ReadString(); while (packet.DataReadSize() < packet.Size()) { - EntityID entityID = packet.ReadPrimitive(); + // Components EntityID + EntityID receivedEntityID = packet.ReadPrimitive(); + // Parents EntityID + EntityID receivedParentEntityID = packet.ReadPrimitive(); ComponentInfo componentInfo = m_World->GetComponents(componentType)->ComponentInfo(); - if (m_World->ValidEntity(entityID)) { + // Check if the received EntityID is mapped to one of our local EntityIDs + if (hasMappedEntity(receivedEntityID)) { + // Get the local EntityID + EntityID entityID = m_ServerToClientMap.at(receivedEntityID); + // Check if the component exists if (m_World->HasComponent(entityID, componentType)) { // If the entity and the component exists update it updateFields(packet, componentInfo, entityID, componentType); @@ -202,11 +210,12 @@ void Client::parseSnapshot(Packet& packet) } // If the entity dosent exist nor the component } else { - //Create Entity + // Create Entity // If entity dosen't exist EntityID newEntityID = m_World->CreateEntity(); + m_ServerToClientMap.insert(std::make_pair(receivedEntityID, newEntityID)); // Check if EntityIDs are out of sync - if (newEntityID != entityID) { + if (newEntityID != receivedEntityID) { LOG_INFO("Client::parseSnapshot(Packet& packet): Newly created EntityID is not the \ same as the one sent by server (EntityIDs are out of sync)"); } @@ -215,6 +224,21 @@ void Client::parseSnapshot(Packet& packet) // Copy data to newly created component updateFields(packet, componentInfo, newEntityID, componentType); } + + // Parent Logic + // Don't need to check if receivedEntityID is mapped. (It should have been set) + if (receivedParentEntityID != std::numeric_limits::max()) { + if (hasMappedEntity(receivedParentEntityID)) { + m_World->SetParent(m_ServerToClientMap.at(receivedEntityID), m_ServerToClientMap.at(receivedParentEntityID)); + // If Parent dosen't exist create one and map receivedParentEntityID to it. + } else { + // Create the new parent and add it to map + EntityID newParentEntityID = m_World->CreateEntity(); + m_ServerToClientMap.insert(std::make_pair(receivedParentEntityID, newParentEntityID)); + // Set the newly created Entity as parent. + m_World->SetParent(m_ServerToClientMap.at(receivedEntityID), newParentEntityID); + } + } } } @@ -273,40 +297,22 @@ void Client::moveMessageHead(char*& data, size_t& length, size_t stepSize) bool Client::OnInputCommand(const Events::InputCommand & e) { - if (isConnected()) { - ComponentWrapper& player = m_World->GetComponent(m_PlayerDefinitions[m_PlayerID].EntityID, "Player"); - if (e.Command == "Forward") { - if (e.Value > 0) { - (bool&)player["Forward"] = true; - (bool&)player["Back"] = false; - } else if (e.Value < 0) { - (bool&)player["Back"] = true; - (bool&)player["Forward"] = false; - } else { - (bool&)player["Forward"] = false; - (bool&)player["Back"] = false; - } - } - if (e.Command == "Right") { - if (e.Value > 0) { - (bool&)player["Right"] = true; - (bool&)player["Left"] = false; - } else if (e.Value < 0) { - (bool&)player["Left"] = true; - (bool&)player["Right"] = false; - } else { - (bool&)player["Left"] = false; - (bool&)player["Right"] = false; - } - } - } - if (e.Command == "ConnectToServer") { // Connect for now + if (e.Command == "Forward" || e.Command == "Right") { + Packet packet(MessageType::Event, m_SendPacketID); + packet.WriteString(e.Command); + packet.WritePrimitive(e.PlayerID); + packet.WritePrimitive(e.Value); + send(packet); + LOG_INFO("Client::OnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID); + return true; + } else if (e.Command == "ConnectToServer") { // Connect for now connect(); + LOG_INFO("Client::OnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID); + return true; } return false; } - void Client::identifyPacketLoss() { // if no packets lost, difference should be equal to 1 @@ -335,3 +341,8 @@ EntityID Client::createPlayer() ComponentWrapper player = m_World->AttachComponent(entityID, "Player"); return entityID; } + +bool Client::hasMappedEntity(EntityID entityID) +{ + return m_ServerToClientMap.find(entityID) != m_ServerToClientMap.end(); +} diff --git a/src/Engine/Network/Server.cpp b/src/Engine/Network/Server.cpp index 07fed65b..e98213a5 100644 --- a/src/Engine/Network/Server.cpp +++ b/src/Engine/Network/Server.cpp @@ -76,7 +76,6 @@ void Server::parseMessageType(Packet& packet) case MessageType::Message: break; case MessageType::Snapshot: - parseSnapshot(packet); break; case MessageType::Disconnect: parseDisconnect(); @@ -149,13 +148,15 @@ void Server::sendSnapshot() std::unordered_map worldComponentPools = m_World->GetComponentPools(); for (auto& it : worldComponentPools) { Packet packet(MessageType::Snapshot, m_SendPacketID); - std::string componentType = it.first; ComponentPool* componentPool = it.second; ComponentInfo componentInfo = componentPool->ComponentInfo(); + // Component Type packet.WriteString(componentInfo.Name); - for (auto& componentWrapper : *componentPool) { + // Components EntityID packet.WritePrimitive(componentWrapper.EntityID); + // Parents EntityID + packet.WritePrimitive(m_World->GetParent(componentWrapper.EntityID)); for (auto& componentField : componentWrapper.Info.FieldsInOrder) { ComponentInfo::Field_t fieldInfo = componentInfo.Fields.at(componentField); if (fieldInfo.Type == "string") { @@ -228,29 +229,12 @@ void Server::parseEvent(Packet& packet) // If no player matches the address return. if (i >= 8) return; - - unsigned int entityId = m_PlayerDefinitions[i].EntityID; - std::string eventString = packet.ReadString(); - if ("+Forward" == eventString) { - m_World->GetComponent(entityId, "Player")["Forward"] = true; - m_World->GetComponent(entityId, "Player")["Back"] = false; - } else if ("-Forward" == eventString) { - m_World->GetComponent(entityId, "Player")["Forward"] = false; - m_World->GetComponent(entityId, "Player")["Back"] = true; - } else if ("0Forward" == eventString) { - m_World->GetComponent(entityId, "Player")["Forward"] = false; - m_World->GetComponent(entityId, "Player")["Back"] = false; - } - if ("+Right" == eventString) { - m_World->GetComponent(entityId, "Player")["Left"] = false; - m_World->GetComponent(entityId, "Player")["Right"] = true; - } else if ("-Right" == eventString) { - m_World->GetComponent(entityId, "Player")["Right"] = false; - m_World->GetComponent(entityId, "Player")["Left"] = true; - } else if ("0Right" == eventString) { - m_World->GetComponent(entityId, "Player")["Right"] = false; - m_World->GetComponent(entityId, "Player")["Left"] = false; - } + Events::InputCommand e; + e.Command = packet.ReadString(); + e.PlayerID = packet.ReadPrimitive(); + e.Value = packet.ReadPrimitive(); + m_EventBroker->Publish(e); + LOG_INFO("Client::OnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID); } void Server::parseConnect(Packet& packet) @@ -319,21 +303,6 @@ void Server::parseServerPing() } } -// NOT USED -void Server::parseSnapshot(Packet& packet) -{ - // Does no logic. Returns snapshot if client request one - // The snapshot is not a real snapshot tho... - for (int i = 0; i < MAXCONNECTIONS; i++) { - if (m_PlayerDefinitions[i].Endpoint.address() != boost::asio::ip::address()) { - m_Socket.send_to( - boost::asio::buffer("I'm sending a snapshot to you guys!"), - m_PlayerDefinitions[i].Endpoint, - 0); - } - } -} - void Server::identifyPacketLoss() { // if no packets lost, difference should be equal to 1 From a060640da3eee5e2017819fbd4fa8322302645e9 Mon Sep 17 00:00:00 2001 From: Jocke Date: Wed, 13 Jan 2016 18:00:12 +0100 Subject: [PATCH 03/27] Removed unnecessary unnecessary if in Client::OnInputCommand. Change name from Server::parseEvent to Server::parseOnInputCommand --- include/Engine/Network/Client.h | 3 ++- include/Engine/Network/MessageType.h | 1 + include/Engine/Network/Server.h | 2 +- src/Engine/Network/Client.cpp | 13 ++++++------- src/Engine/Network/Server.cpp | 6 ++++-- 5 files changed, 14 insertions(+), 11 deletions(-) diff --git a/include/Engine/Network/Client.h b/include/Engine/Network/Client.h index da734810..6b73c95c 100644 --- a/include/Engine/Network/Client.h +++ b/include/Engine/Network/Client.h @@ -81,8 +81,9 @@ private: bool hasMappedEntity(EntityID entityID); // Events EventBroker* m_EventBroker; + EventRelay m_EInputCommand; - bool OnInputCommand(const Events::InputCommand &e); + bool OnInputCommand(const Events::InputCommand& e); }; #endif diff --git a/include/Engine/Network/MessageType.h b/include/Engine/Network/MessageType.h index 8d09c7ee..68bda9b0 100644 --- a/include/Engine/Network/MessageType.h +++ b/include/Engine/Network/MessageType.h @@ -12,6 +12,7 @@ enum class MessageType Message, Snapshot, Event, + OnInputCommand }; #endif diff --git a/include/Engine/Network/Server.h b/include/Engine/Network/Server.h index 84d8c143..ec2560b5 100644 --- a/include/Engine/Network/Server.h +++ b/include/Engine/Network/Server.h @@ -68,7 +68,7 @@ private: void checkForTimeOuts(); void disconnect(int i); void parseMessageType(Packet& packet); - void parseEvent(Packet& packet); + void parseOnInputCommand(Packet& packet); void parseConnect(Packet& packet); void parseDisconnect(); void parseClientPing(); diff --git a/src/Engine/Network/Client.cpp b/src/Engine/Network/Client.cpp index 3ecee0e0..37ee35d9 100644 --- a/src/Engine/Network/Client.cpp +++ b/src/Engine/Network/Client.cpp @@ -254,7 +254,6 @@ int Client::receive(char* data, size_t length) if (error) { LOG_ERROR("receive: %s", error.message().c_str()); } - return bytesReceived; } @@ -297,18 +296,18 @@ void Client::moveMessageHead(char*& data, size_t& length, size_t stepSize) bool Client::OnInputCommand(const Events::InputCommand & e) { - if (e.Command == "Forward" || e.Command == "Right") { - Packet packet(MessageType::Event, m_SendPacketID); + if (e.Command == "ConnectToServer") { // Connect for now + connect(); + LOG_INFO("Client::OnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID); + return true; + } else { + Packet packet(MessageType::OnInputCommand, m_SendPacketID); packet.WriteString(e.Command); packet.WritePrimitive(e.PlayerID); packet.WritePrimitive(e.Value); send(packet); LOG_INFO("Client::OnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID); return true; - } else if (e.Command == "ConnectToServer") { // Connect for now - connect(); - LOG_INFO("Client::OnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID); - return true; } return false; } diff --git a/src/Engine/Network/Server.cpp b/src/Engine/Network/Server.cpp index e98213a5..6b59a31a 100644 --- a/src/Engine/Network/Server.cpp +++ b/src/Engine/Network/Server.cpp @@ -81,8 +81,10 @@ void Server::parseMessageType(Packet& packet) parseDisconnect(); break; case MessageType::Event: - parseEvent(packet); break; + case MessageType::OnInputCommand: + parseOnInputCommand(packet); + break;; default: break; } @@ -218,7 +220,7 @@ void Server::disconnect(int i) m_PlayerDefinitions[i].Name = ""; } -void Server::parseEvent(Packet& packet) +void Server::parseOnInputCommand(Packet& packet) { size_t i; for (i = 0; i < MAXCONNECTIONS; i++) { From db18a453685d5c220dfec27462d1312a0919f412 Mon Sep 17 00:00:00 2001 From: Jocke Date: Thu, 14 Jan 2016 10:16:11 +0100 Subject: [PATCH 04/27] We are now sending EPlayerDamage events. Client now listens to EPlayerDamage events and send them to Server. Server publishes EPlayerDamage events received from Client. --- include/Engine/Network/Client.h | 5 ++++- include/Engine/Network/MessageType.h | 3 ++- include/Engine/Network/Server.h | 2 ++ src/Engine/Network/Client.cpp | 14 ++++++++++++-- src/Engine/Network/Server.cpp | 26 +++++++++++++++----------- 5 files changed, 35 insertions(+), 15 deletions(-) diff --git a/include/Engine/Network/Client.h b/include/Engine/Network/Client.h index 6b73c95c..3027ad87 100644 --- a/include/Engine/Network/Client.h +++ b/include/Engine/Network/Client.h @@ -16,6 +16,7 @@ #include "Core/EventBroker.h" #include "Core/ConfigFile.h" #include "Input/EInputCommand.h" +#include "Core/EPlayerDamage.h" class Client : public Network { @@ -79,11 +80,13 @@ private: bool isConnected(); EntityID createPlayer(); bool hasMappedEntity(EntityID entityID); + // Events EventBroker* m_EventBroker; - EventRelay m_EInputCommand; bool OnInputCommand(const Events::InputCommand& e); + EventRelay m_EPlayeDamage; + bool OnPlayerDamage(const Events::PlayerDamage& e); }; #endif diff --git a/include/Engine/Network/MessageType.h b/include/Engine/Network/MessageType.h index 68bda9b0..42b049e8 100644 --- a/include/Engine/Network/MessageType.h +++ b/include/Engine/Network/MessageType.h @@ -12,7 +12,8 @@ enum class MessageType Message, Snapshot, Event, - OnInputCommand + OnInputCommand, + OnPlayerDamage }; #endif diff --git a/include/Engine/Network/Server.h b/include/Engine/Network/Server.h index ec2560b5..dc7b25cd 100644 --- a/include/Engine/Network/Server.h +++ b/include/Engine/Network/Server.h @@ -13,6 +13,7 @@ #include "Core/EventBroker.h" #include "Network/Network.h" #include "Input/EInputCommand.h" +#include "Core/EPlayerDamage.h" class Server : public Network { @@ -69,6 +70,7 @@ private: void disconnect(int i); void parseMessageType(Packet& packet); void parseOnInputCommand(Packet& packet); + void parseOnPlayerDamage(Packet& packet); void parseConnect(Packet& packet); void parseDisconnect(); void parseClientPing(); diff --git a/src/Engine/Network/Client.cpp b/src/Engine/Network/Client.cpp index 37ee35d9..c073e79a 100644 --- a/src/Engine/Network/Client.cpp +++ b/src/Engine/Network/Client.cpp @@ -298,7 +298,7 @@ bool Client::OnInputCommand(const Events::InputCommand & e) { if (e.Command == "ConnectToServer") { // Connect for now connect(); - LOG_INFO("Client::OnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID); + LOG_DEBUG("Client::OnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID); return true; } else { Packet packet(MessageType::OnInputCommand, m_SendPacketID); @@ -306,12 +306,22 @@ bool Client::OnInputCommand(const Events::InputCommand & e) packet.WritePrimitive(e.PlayerID); packet.WritePrimitive(e.Value); send(packet); - LOG_INFO("Client::OnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID); + LOG_DEBUG("Client::OnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID); return true; } return false; } +bool Client::OnPlayerDamage(const Events::PlayerDamage & e) +{ + Packet packet(MessageType::OnInputCommand, m_SendPacketID); + packet.WritePrimitive(e.DamageAmount); + packet.WritePrimitive(e.PlayerDamagedID); + packet.WriteString(e.TypeOfDamage); + send(packet); + return false; +} + void Client::identifyPacketLoss() { // if no packets lost, difference should be equal to 1 diff --git a/src/Engine/Network/Server.cpp b/src/Engine/Network/Server.cpp index 6b59a31a..1a915863 100644 --- a/src/Engine/Network/Server.cpp +++ b/src/Engine/Network/Server.cpp @@ -84,7 +84,10 @@ void Server::parseMessageType(Packet& packet) break; case MessageType::OnInputCommand: parseOnInputCommand(packet); - break;; + break; + case MessageType::OnPlayerDamage: + parseOnPlayerDamage(packet); + break; default: break; } @@ -222,21 +225,22 @@ void Server::disconnect(int i) void Server::parseOnInputCommand(Packet& packet) { - size_t i; - for (i = 0; i < MAXCONNECTIONS; i++) { - if (m_PlayerDefinitions[i].Endpoint.address() == m_ReceiverEndpoint.address()) { - break; - } - } - // If no player matches the address return. - if (i >= 8) - return; Events::InputCommand e; e.Command = packet.ReadString(); e.PlayerID = packet.ReadPrimitive(); e.Value = packet.ReadPrimitive(); m_EventBroker->Publish(e); - LOG_INFO("Client::OnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID); + LOG_DEBUG("Server::OnInputCommand: 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; + e.DamageAmount = packet.ReadPrimitive(); + e.PlayerDamagedID = packet.ReadPrimitive(); + e.TypeOfDamage = packet.ReadString(); + m_EventBroker->Publish(e); + LOG_DEBUG("Server::OnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.DamageAmount, e.PlayerDamagedID, e.TypeOfDamage.c_str()); } void Server::parseConnect(Packet& packet) From 696f44a673788475d2df091ed1e2d5893c4d9934 Mon Sep 17 00:00:00 2001 From: Jocke Date: Thu, 14 Jan 2016 17:11:54 +0100 Subject: [PATCH 05/27] Added logic for mapping between ServerEntityIDs and LocalEntityIDs removed old code that wasn't used. Added 1 map to Client and renamed m_ServerToClientMap to m_ServerIDToClientID. // Good to know To keep this structure please use insertIntoServerClientMaps() when adding items to them. m_ServerIDToClientID and m_ClientIDToServerID maps between server EntityIDs and local EntityIDs. To see if a local EntityID exist in m_ClientIDToServerID use clientServerMapsHasEntity(EntityID clientEntityID); To see if server EntityID exist in m_ServerIDToClientID use serverClientMapsHasEntity(EntityID serverEntityID); --- include/Engine/Network/Client.h | 23 ++--- include/Engine/Network/MessageType.h | 4 +- include/Engine/Network/Server.h | 4 - src/Engine/Network/Client.cpp | 122 ++++++++------------------- src/Engine/Network/Server.cpp | 34 ++------ 5 files changed, 56 insertions(+), 131 deletions(-) diff --git a/include/Engine/Network/Client.h b/include/Engine/Network/Client.h index 3027ad87..81b2b834 100644 --- a/include/Engine/Network/Client.h +++ b/include/Engine/Network/Client.h @@ -34,8 +34,6 @@ private: // Sending message to server logic int bytesRead = -1; char readBuf[INPUTSIZE] = { 0 }; - int snapshotInterval = 33; - std::clock_t previousSnapshotMessage = std::clock(); // Packet loss logic unsigned int m_PacketID = 0; @@ -46,40 +44,43 @@ private: World* m_World; std::string m_PlayerName; int m_PlayerID = -1; - + EntityID m_ServerEntityID = std::numeric_limits::max(); // Server Client Lookup map // Assumes that root node for client and server is EntityID 0. - std::unordered_map m_ServerToClientMap; + + // Don't Add items to these two maps with insert, use insertIntoServerClientMaps(EntityID, EntityID)!!!! + std::unordered_map m_ServerIDToClientID; + std::unordered_map m_ClientIDToServerID; // Network logic PlayerDefinition m_PlayerDefinitions[MAXCONNECTIONS]; SnapshotDefinitions m_NextSnapshot; double m_DurationOfPingTime; std::clock_t m_StartPingTime; - // Use to check if we should send disconnect message - // if game is turned of by closing window. - bool m_WasStarted = false; // Private member functions void readFromServer(); - void sendInputEvents(); int receive(char* data, size_t length); void send(Packet& packet); void connect(); void disconnect(); void ping(); - void moveMessageHead(char*& data, size_t& length, size_t stepSize); void parseMessageType(Packet& packet); - void parseEventMessage(Packet& packet); void updateFields(Packet& packet, const ComponentInfo& componentInfo, const EntityID& entityID, const std::string& componentType); void parseConnect(Packet& packet); + void parsePlayerConnected(Packet& packet); void parsePing(); void parseServerPing(); void parseSnapshot(Packet& packet); void identifyPacketLoss(); bool isConnected(); EntityID createPlayer(); - bool hasMappedEntity(EntityID entityID); + // Mapping Logic + // Returns if local EntityID exist in map + bool clientServerMapsHasEntity(EntityID clientEntityID); + // Returns if server EntityID exist in map + bool serverClientMapsHasEntity(EntityID serverEntityID); + void insertIntoServerClientMaps(EntityID serverEntityID, EntityID clientEntityID); // Events EventBroker* m_EventBroker; diff --git a/include/Engine/Network/MessageType.h b/include/Engine/Network/MessageType.h index 42b049e8..ba9684d9 100644 --- a/include/Engine/Network/MessageType.h +++ b/include/Engine/Network/MessageType.h @@ -11,9 +11,9 @@ enum class MessageType ServerPing, Message, Snapshot, - Event, OnInputCommand, - OnPlayerDamage + OnPlayerDamage, + PlayerConnected }; #endif diff --git a/include/Engine/Network/Server.h b/include/Engine/Network/Server.h index dc7b25cd..4c71be95 100644 --- a/include/Engine/Network/Server.h +++ b/include/Engine/Network/Server.h @@ -48,8 +48,6 @@ private: // Game logic World* m_World; EventBroker* m_EventBroker; - // vec.size() = ammount of players to create, stores playerID's - std::vector m_PlayersToCreate; // Packet loss logic unsigned int m_PacketID; @@ -61,8 +59,6 @@ private: void readFromClients(); void send(Packet& packet, int playerID); void send(Packet& packet); - void moveMessageHead(char*& data, size_t& length, size_t stepSize); - void broadcast(std::string message); void broadcast(Packet& packet); void sendSnapshot(); void sendPing(); diff --git a/src/Engine/Network/Client.cpp b/src/Engine/Network/Client.cpp index c073e79a..37534a27 100644 --- a/src/Engine/Network/Client.cpp +++ b/src/Engine/Network/Client.cpp @@ -6,15 +6,13 @@ using namespace boost::asio::ip; Client::Client(ConfigFile* config) : m_Socket(m_IOService) { // Asumes root node is EntityID 0 - m_ServerToClientMap.insert(std::make_pair(0, 0)); + insertIntoServerClientMaps(0, 0); // Default is local host std::string address = config->Get("Networking.Address", "127.0.0.1"); int port = config->Get("Networking.Port", 13); m_ReceiverEndpoint = udp::endpoint(boost::asio::ip::address::from_string(address), port); // Set up network stream m_PlayerName = config->Get("Networking.Name", "Raptorcopter"); - m_NextSnapshot.InputForward = ""; - m_NextSnapshot.InputRight = ""; } Client::~Client() @@ -22,7 +20,6 @@ Client::~Client() void Client::Start(World* world, EventBroker* eventBroker) { - m_WasStarted = true; m_EventBroker = eventBroker; m_World = world; @@ -47,58 +44,6 @@ void Client::readFromServer() parseMessageType(packet); } } - std::clock_t currentTime = std::clock(); - if (snapshotInterval < (1000 * (currentTime - previousSnapshotMessage) / (double)CLOCKS_PER_SEC)) { - if (isConnected()) { - //sendSnapshotToServer(); - } - previousSnapshotMessage = currentTime; - } -} - -void Client::sendInputEvents() -{ - // Reset previous key state in snapshot. - m_NextSnapshot.InputForward = ""; - m_NextSnapshot.InputRight = ""; - - auto player = m_World->GetComponent(m_PlayerDefinitions[m_PlayerID].EntityID, "Player"); - - // See if any movement keys are down - // We dont care if it's overwritten by later - // if statement. Watcha gonna do, right! - if (player["Forward"]) { - m_NextSnapshot.InputForward = "+Forward"; - } - if (player["Left"]) { - m_NextSnapshot.InputRight = "-Right"; - } - if (player["Back"]) { - m_NextSnapshot.InputForward = "-Forward"; - } - if (player["Right"]) { - m_NextSnapshot.InputRight = "+Right"; - } - - if (m_NextSnapshot.InputForward != "") { - Packet packet(MessageType::Event, m_SendPacketID); - packet.WriteString(m_NextSnapshot.InputForward); - send(packet); - } else { - Packet packet(MessageType::Event, m_SendPacketID); - packet.WriteString("0Forward"); - send(packet); - } - - if (m_NextSnapshot.InputRight != "") { - Packet packet(MessageType::Event, m_SendPacketID); - packet.WriteString(m_NextSnapshot.InputRight); - send(packet); - } else { - Packet packet(MessageType::Event, m_SendPacketID); - packet.WriteString("0Right"); - send(packet); - } } void Client::parseMessageType(Packet& packet) @@ -130,9 +75,8 @@ void Client::parseMessageType(Packet& packet) break; case MessageType::Disconnect: break; - case MessageType::Event: - parseEventMessage(packet); - break; + case MessageType::PlayerConnected: + parsePlayerConnected(packet); default: break; } @@ -140,10 +84,19 @@ void Client::parseMessageType(Packet& packet) void Client::parseConnect(Packet& packet) { + // Set your own player id m_PlayerID = packet.ReadPrimitive(); + m_ServerEntityID = packet.ReadPrimitive(); + // Map ServerEntityID and your PlayerID LOG_INFO("%i: I am player: %i", m_PacketID, m_PlayerID); } +void Client::parsePlayerConnected(Packet & packet) +{ + // Map ServerEntityID and other player's PlayerID + LOG_INFO("A Player connected"); +} + void Client::parsePing() { m_DurationOfPingTime = 1000 * (std::clock() - m_StartPingTime) / static_cast(CLOCKS_PER_SEC); @@ -157,19 +110,6 @@ void Client::parseServerPing() send(packet); } -void Client::parseEventMessage(Packet& packet) -{ - int Id = -1; - std::string command = packet.ReadString(); - if (command.find("+Player") != std::string::npos) { - Id = packet.ReadPrimitive(); - // Sett Player name - m_PlayerDefinitions[Id].Name = command.erase(0, 7); - } else { - LOG_INFO("%i: Event message: %s", m_PacketID, command.c_str()); - } -} - void Client::updateFields(Packet& packet, const ComponentInfo& componentInfo, const EntityID& entityID, const std::string& componentType) { for (auto field : componentInfo.FieldsInOrder) { @@ -194,9 +134,9 @@ void Client::parseSnapshot(Packet& packet) EntityID receivedParentEntityID = packet.ReadPrimitive(); ComponentInfo componentInfo = m_World->GetComponents(componentType)->ComponentInfo(); // Check if the received EntityID is mapped to one of our local EntityIDs - if (hasMappedEntity(receivedEntityID)) { + if (clientServerMapsHasEntity(receivedEntityID)) { // Get the local EntityID - EntityID entityID = m_ServerToClientMap.at(receivedEntityID); + EntityID entityID = m_ServerIDToClientID.at(receivedEntityID); // Check if the component exists if (m_World->HasComponent(entityID, componentType)) { // If the entity and the component exists update it @@ -213,7 +153,7 @@ void Client::parseSnapshot(Packet& packet) // Create Entity // If entity dosen't exist EntityID newEntityID = m_World->CreateEntity(); - m_ServerToClientMap.insert(std::make_pair(receivedEntityID, newEntityID)); + insertIntoServerClientMaps(receivedEntityID, newEntityID); // Check if EntityIDs are out of sync if (newEntityID != receivedEntityID) { LOG_INFO("Client::parseSnapshot(Packet& packet): Newly created EntityID is not the \ @@ -228,15 +168,15 @@ void Client::parseSnapshot(Packet& packet) // Parent Logic // Don't need to check if receivedEntityID is mapped. (It should have been set) if (receivedParentEntityID != std::numeric_limits::max()) { - if (hasMappedEntity(receivedParentEntityID)) { - m_World->SetParent(m_ServerToClientMap.at(receivedEntityID), m_ServerToClientMap.at(receivedParentEntityID)); + if (clientServerMapsHasEntity(receivedParentEntityID)) { + m_World->SetParent(m_ServerIDToClientID.at(receivedEntityID), m_ServerIDToClientID.at(receivedParentEntityID)); // If Parent dosen't exist create one and map receivedParentEntityID to it. } else { // Create the new parent and add it to map EntityID newParentEntityID = m_World->CreateEntity(); - m_ServerToClientMap.insert(std::make_pair(receivedParentEntityID, newParentEntityID)); + insertIntoServerClientMaps(receivedParentEntityID, newParentEntityID); // Set the newly created Entity as parent. - m_World->SetParent(m_ServerToClientMap.at(receivedEntityID), newParentEntityID); + m_World->SetParent(m_ServerIDToClientID.at(receivedEntityID), newParentEntityID); } } } @@ -252,7 +192,7 @@ int Client::receive(char* data, size_t length) 0, error); if (error) { - LOG_ERROR("receive: %s", error.message().c_str()); + //LOG_ERROR("receive: %s", error.message().c_str()); } return bytesReceived; } @@ -288,12 +228,6 @@ void Client::ping() send(packet); } -void Client::moveMessageHead(char*& data, size_t& length, size_t stepSize) -{ - data += stepSize; - length -= stepSize; -} - bool Client::OnInputCommand(const Events::InputCommand & e) { if (e.Command == "ConnectToServer") { // Connect for now @@ -351,7 +285,19 @@ EntityID Client::createPlayer() return entityID; } -bool Client::hasMappedEntity(EntityID entityID) +bool Client::clientServerMapsHasEntity(EntityID clientEntityID) { - return m_ServerToClientMap.find(entityID) != m_ServerToClientMap.end(); + return m_ClientIDToServerID.find(clientEntityID) != m_ClientIDToServerID.end(); +} + +bool Client::serverClientMapsHasEntity(EntityID serverEntityID) +{ + return m_ServerIDToClientID.find(serverEntityID) != m_ServerIDToClientID.end(); +} + +void Client::insertIntoServerClientMaps(EntityID serverEntityID, EntityID clientEntityID) +{ + m_ServerIDToClientID.insert(std::make_pair(serverEntityID, clientEntityID)); + m_ClientIDToServerID.insert(std::make_pair(clientEntityID, serverEntityID)); + } diff --git a/src/Engine/Network/Server.cpp b/src/Engine/Network/Server.cpp index 1a915863..5ec674d0 100644 --- a/src/Engine/Network/Server.cpp +++ b/src/Engine/Network/Server.cpp @@ -50,7 +50,7 @@ void Server::readFromClients() // Time out logic if (checkTimeOutInterval < (1000 * (currentTime - timOutTimer) / (double)CLOCKS_PER_SEC)) { - //checkForTimeOuts(); + checkForTimeOuts(); timOutTimer = currentTime; } } @@ -80,8 +80,6 @@ void Server::parseMessageType(Packet& packet) case MessageType::Disconnect: parseDisconnect(); break; - case MessageType::Event: - break; case MessageType::OnInputCommand: parseOnInputCommand(packet); break; @@ -120,23 +118,6 @@ void Server::send(Packet & packet) 0); } -void Server::moveMessageHead(char *& data, size_t & length, size_t stepSize) -{ - data += stepSize; - length -= stepSize; -} - -void Server::broadcast(std::string message) -{ - Packet packet(MessageType::Event, m_SendPacketID); - packet.WriteString(message); - for (int i = 0; i < MAXCONNECTIONS; i++) { - if (m_PlayerDefinitions[i].Endpoint.address() != boost::asio::ip::address()) { - send(packet, i); - } - } -} - void Server::broadcast(Packet& packet) { for (int i = 0; i < MAXCONNECTIONS; ++i) { @@ -214,7 +195,7 @@ void Server::checkForTimeOuts() void Server::disconnect(int i) { - broadcast("A player disconnected"); + //broadcast("A player disconnected"); LOG_INFO("Player %i disconnected/timed out", i); // Remove enteties and stuff @@ -234,7 +215,7 @@ void Server::parseOnInputCommand(Packet& packet) } void Server::parseOnPlayerDamage(Packet & packet) -{ +{ Events::PlayerDamage e; e.DamageAmount = packet.ReadPrimitive(); e.PlayerDamagedID = packet.ReadPrimitive(); @@ -264,15 +245,16 @@ void Server::parseConnect(Packet& packet) 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.WritePrimitive(i); // Player ID - + packet.WritePrimitive(m_PlayerDefinitions[i].EntityID); // Entity ID send(packet, i); // Send notification that a player has connected - std::string str = m_PacketID + "Player " + m_PlayerDefinitions[i].Name + " connected on: " - + m_PlayerDefinitions[i].Endpoint.address().to_string(); - broadcast(str); + Packet notificationPacket(MessageType::PlayerConnected, m_PacketID); + broadcast(notificationPacket); + break; } } From db62d767ac12587cf6961b8d8beef0223a4ef057 Mon Sep 17 00:00:00 2001 From: Jocke Date: Fri, 15 Jan 2016 12:06:20 +0100 Subject: [PATCH 06/27] Fixed bug in Client::parseSnapshot(). --- src/Engine/Network/Client.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Engine/Network/Client.cpp b/src/Engine/Network/Client.cpp index 37534a27..55292234 100644 --- a/src/Engine/Network/Client.cpp +++ b/src/Engine/Network/Client.cpp @@ -134,7 +134,7 @@ void Client::parseSnapshot(Packet& packet) EntityID receivedParentEntityID = packet.ReadPrimitive(); ComponentInfo componentInfo = m_World->GetComponents(componentType)->ComponentInfo(); // Check if the received EntityID is mapped to one of our local EntityIDs - if (clientServerMapsHasEntity(receivedEntityID)) { + if (serverClientMapsHasEntity(receivedEntityID)) { // Get the local EntityID EntityID entityID = m_ServerIDToClientID.at(receivedEntityID); // Check if the component exists @@ -168,7 +168,7 @@ void Client::parseSnapshot(Packet& packet) // Parent Logic // Don't need to check if receivedEntityID is mapped. (It should have been set) if (receivedParentEntityID != std::numeric_limits::max()) { - if (clientServerMapsHasEntity(receivedParentEntityID)) { + if (serverClientMapsHasEntity(receivedParentEntityID)) { m_World->SetParent(m_ServerIDToClientID.at(receivedEntityID), m_ServerIDToClientID.at(receivedParentEntityID)); // If Parent dosen't exist create one and map receivedParentEntityID to it. } else { From d995713d3b4e1e4216e9d462081a0ab2d1375b36 Mon Sep 17 00:00:00 2001 From: Jocke Date: Mon, 18 Jan 2016 11:05:32 +0100 Subject: [PATCH 07/27] Added input queue to Client and Input Listener debug code in server. --- assets | 2 +- include/Engine/Network/Client.h | 2 ++ include/Engine/Network/Server.h | 4 ++++ src/Engine/Network/Client.cpp | 27 +++++++++++++++------- src/Engine/Network/Server.cpp | 40 ++++++++++++++++++++++++++------- 5 files changed, 58 insertions(+), 17 deletions(-) diff --git a/assets b/assets index 6cbf2365..a3c92ac8 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 6cbf2365d49e6280750ea3bcd0f9c271779e6f15 +Subproject commit a3c92ac876dd061776c36d1594bd82264372f028 diff --git a/include/Engine/Network/Client.h b/include/Engine/Network/Client.h index 81b2b834..7aa20126 100644 --- a/include/Engine/Network/Client.h +++ b/include/Engine/Network/Client.h @@ -57,6 +57,7 @@ private: SnapshotDefinitions m_NextSnapshot; double m_DurationOfPingTime; std::clock_t m_StartPingTime; + std::vector m_InputCommandBuffer; // Private member functions void readFromServer(); @@ -75,6 +76,7 @@ private: void identifyPacketLoss(); bool isConnected(); EntityID createPlayer(); + void sendInputCommands(); // Mapping Logic // Returns if local EntityID exist in map bool clientServerMapsHasEntity(EntityID clientEntityID); diff --git a/include/Engine/Network/Server.h b/include/Engine/Network/Server.h index 4c71be95..9aba921a 100644 --- a/include/Engine/Network/Server.h +++ b/include/Engine/Network/Server.h @@ -73,6 +73,10 @@ private: void parseServerPing(); void identifyPacketLoss(); EntityID createPlayer(); + // Debug event + + EventRelay m_EInputCommand; + bool OnInputCommand(const Events::InputCommand& e); }; #endif diff --git a/src/Engine/Network/Client.cpp b/src/Engine/Network/Client.cpp index 55292234..e07bcf7a 100644 --- a/src/Engine/Network/Client.cpp +++ b/src/Engine/Network/Client.cpp @@ -25,6 +25,7 @@ void Client::Start(World* world, EventBroker* eventBroker) // Subscribe to events EVENT_SUBSCRIBE_MEMBER(m_EInputCommand, &Client::OnInputCommand); + EVENT_SUBSCRIBE_MEMBER(m_EPlayeDamage, &Client::OnPlayerDamage); m_Socket.connect(m_ReceiverEndpoint); LOG_INFO("I am client. BIP BOP"); @@ -44,6 +45,7 @@ void Client::readFromServer() parseMessageType(packet); } } + sendInputCommands(); } void Client::parseMessageType(Packet& packet) @@ -92,7 +94,7 @@ void Client::parseConnect(Packet& packet) } void Client::parsePlayerConnected(Packet & packet) -{ +{ // Map ServerEntityID and other player's PlayerID LOG_INFO("A Player connected"); } @@ -235,12 +237,8 @@ bool Client::OnInputCommand(const Events::InputCommand & e) LOG_DEBUG("Client::OnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID); return true; } else { - Packet packet(MessageType::OnInputCommand, m_SendPacketID); - packet.WriteString(e.Command); - packet.WritePrimitive(e.PlayerID); - packet.WritePrimitive(e.Value); - send(packet); - LOG_DEBUG("Client::OnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID); + m_InputCommandBuffer.push_back(e); + LOG_INFO("Client::OnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID); return true; } return false; @@ -285,6 +283,19 @@ EntityID Client::createPlayer() return entityID; } +void Client::sendInputCommands() +{ + if (m_InputCommandBuffer.size() > 0) { + Packet packet(MessageType::OnInputCommand, m_SendPacketID); + for (int i = 0; i < m_InputCommandBuffer.size(); i++) { + packet.WriteString(m_InputCommandBuffer[i].Command); + packet.WritePrimitive(m_InputCommandBuffer[i].Value); + } + send(packet); + m_InputCommandBuffer.clear(); + } +} + bool Client::clientServerMapsHasEntity(EntityID clientEntityID) { return m_ClientIDToServerID.find(clientEntityID) != m_ClientIDToServerID.end(); @@ -296,7 +307,7 @@ bool Client::serverClientMapsHasEntity(EntityID serverEntityID) } void Client::insertIntoServerClientMaps(EntityID serverEntityID, EntityID clientEntityID) -{ +{ m_ServerIDToClientID.insert(std::make_pair(serverEntityID, clientEntityID)); m_ClientIDToServerID.insert(std::make_pair(clientEntityID, serverEntityID)); diff --git a/src/Engine/Network/Server.cpp b/src/Engine/Network/Server.cpp index 5ec674d0..2563d9b1 100644 --- a/src/Engine/Network/Server.cpp +++ b/src/Engine/Network/Server.cpp @@ -13,6 +13,8 @@ void Server::Start(World* world, EventBroker* eventBroker) { m_World = world; m_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(); } @@ -22,6 +24,7 @@ void Server::Start(World* world, EventBroker* eventBroker) void Server::Update() { readFromClients(); + m_EventBroker->Process(); } void Server::readFromClients() @@ -206,12 +209,26 @@ void Server::disconnect(int i) void Server::parseOnInputCommand(Packet& packet) { - Events::InputCommand e; - e.Command = packet.ReadString(); - e.PlayerID = packet.ReadPrimitive(); - e.Value = packet.ReadPrimitive(); - m_EventBroker->Publish(e); - LOG_DEBUG("Server::OnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID); + int playerID = -1; + // Check which player it was who sent the message + for (int i = 0; i < MAXCONNECTIONS; i++) { + // if the player is connected set playerID to the correct PlayerID + if (m_PlayerDefinitions[i].Endpoint.address() == m_ReceiverEndpoint.address() + && m_PlayerDefinitions[i].Endpoint.port() == m_ReceiverEndpoint.port()) { + playerID = i; + break; + } + } + if (playerID != -1) { + while (packet.DataReadSize() < packet.Size()) { + Events::InputCommand e; + e.Command = packet.ReadString(); + e.PlayerID = playerID; // Set correct player id + e.Value = packet.ReadPrimitive(); + m_EventBroker->Publish(e); + LOG_DEBUG("Server::parseOnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID); + } + } } void Server::parseOnPlayerDamage(Packet & packet) @@ -221,7 +238,7 @@ void Server::parseOnPlayerDamage(Packet & packet) e.PlayerDamagedID = packet.ReadPrimitive(); e.TypeOfDamage = packet.ReadString(); m_EventBroker->Publish(e); - LOG_DEBUG("Server::OnInputCommand: 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) @@ -229,7 +246,8 @@ void Server::parseConnect(Packet& packet) LOG_INFO("Parsing connections"); // Check if player is already connected for (int i = 0; i < MAXCONNECTIONS; i++) { - if (m_PlayerDefinitions[i].Endpoint.address() == m_ReceiverEndpoint.address()) { + if (m_PlayerDefinitions[i].Endpoint.address() == m_ReceiverEndpoint.address() && + m_PlayerDefinitions[i].Endpoint.port() == m_ReceiverEndpoint.port()) { return; } } @@ -311,3 +329,9 @@ EntityID Server::createPlayer() ComponentWrapper player = m_World->AttachComponent(entityID, "Player"); return entityID; } + +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); + return true; +} From 6ba6deb863476e523d194c46e47b29b67b66163a Mon Sep 17 00:00:00 2001 From: Jocke Date: Mon, 18 Jan 2016 11:35:35 +0100 Subject: [PATCH 08/27] Removed some debug spam. --- src/Engine/Network/Client.cpp | 4 ++-- src/Engine/Network/Server.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Engine/Network/Client.cpp b/src/Engine/Network/Client.cpp index e07bcf7a..d6e8f4c5 100644 --- a/src/Engine/Network/Client.cpp +++ b/src/Engine/Network/Client.cpp @@ -234,11 +234,11 @@ bool Client::OnInputCommand(const Events::InputCommand & e) { if (e.Command == "ConnectToServer") { // Connect for now connect(); - LOG_DEBUG("Client::OnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID); + //LOG_DEBUG("Client::OnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID); return true; } else { m_InputCommandBuffer.push_back(e); - LOG_INFO("Client::OnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID); + //LOG_DEBUG("Client::OnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID); return true; } return false; diff --git a/src/Engine/Network/Server.cpp b/src/Engine/Network/Server.cpp index 2563d9b1..422d6523 100644 --- a/src/Engine/Network/Server.cpp +++ b/src/Engine/Network/Server.cpp @@ -226,7 +226,7 @@ void Server::parseOnInputCommand(Packet& packet) e.PlayerID = playerID; // Set correct player id e.Value = packet.ReadPrimitive(); m_EventBroker->Publish(e); - LOG_DEBUG("Server::parseOnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID); + LOG_INFO("Server::parseOnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID); } } } @@ -332,6 +332,6 @@ EntityID Server::createPlayer() 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); + //LOG_INFO("Server::OnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID); return true; } From d7780d8248eb696b44fc7b9ca43cab55cb0dff38 Mon Sep 17 00:00:00 2001 From: stiffly Date: Mon, 18 Jan 2016 17:11:37 +0100 Subject: [PATCH 09/27] WIP implementing interpolation --- include/Engine/Network/EInterpolate.h | 20 +++++++++++ include/Game/InterpolationSystem.h | 42 ++++++++++++++++++++++ src/Game/InterpolationSystem.cpp | 50 +++++++++++++++++++++++++++ 3 files changed, 112 insertions(+) create mode 100644 include/Engine/Network/EInterpolate.h create mode 100644 include/Game/InterpolationSystem.h create mode 100644 src/Game/InterpolationSystem.cpp diff --git a/include/Engine/Network/EInterpolate.h b/include/Engine/Network/EInterpolate.h new file mode 100644 index 00000000..65038e49 --- /dev/null +++ b/include/Engine/Network/EInterpolate.h @@ -0,0 +1,20 @@ +#ifndef Events_Interpolate_h__ +#define Events_Interpolate_h__ + +#include + +#include "Core/EventBroker.h" +#include "Core/Entity.h" + +namespace Events +{ + +struct Interpolate : Event +{ + EntityID Entity; + boost::shared_array DataArray; +}; + +} + +#endif \ No newline at end of file diff --git a/include/Game/InterpolationSystem.h b/include/Game/InterpolationSystem.h new file mode 100644 index 00000000..c87ee5a7 --- /dev/null +++ b/include/Game/InterpolationSystem.h @@ -0,0 +1,42 @@ +#ifndef Systems_InterpolationSystem_h__ +#define Systems_InterpolationSystem_h__ + +#include +#include +#include +#include + +#include "Common.h" +#include "Core/System.h" +#include "Core/EventBroker.h" + +#include "Network/EInterpolate.h" + +struct Transform { + glm::vec3 Position; + glm::vec3 Scale; + glm::vec3 Orientation; + double interpolationTime; +}; + +class InterpolationSystem : public PureSystem +{ +public: + InterpolationSystem(EventBroker* eventbroker) + : PureSystem(eventbroker, "Transform") + { + EVENT_SUBSCRIBE_MEMBER(m_EInterpolate, &InterpolationSystem::OnInterpolate); + } + ~InterpolationSystem() { } + + virtual void UpdateComponent(World* world, ComponentWrapper& transform, double dt) override; +private: + std::unordered_map> m_InterpolationPoints; + + glm::vec3 vectorInterpolation(glm::vec3 prev, glm::vec3 next, double currentTime); + + EventRelay m_EInterpolate; + bool InterpolationSystem::OnInterpolate(const Events::Interpolate& e); +}; + +#endif diff --git a/src/Game/InterpolationSystem.cpp b/src/Game/InterpolationSystem.cpp new file mode 100644 index 00000000..d2d81fda --- /dev/null +++ b/src/Game/InterpolationSystem.cpp @@ -0,0 +1,50 @@ +#include "InterpolationSystem.h" + +void InterpolationSystem::UpdateComponent(World * world, ComponentWrapper & transform, double dt) +{ + if (m_InterpolationPoints[transform.EntityID].size() > 0) { + Transform& sTransform = m_InterpolationPoints[transform.EntityID].front(); + sTransform.interpolationTime += dt; + if (sTransform.interpolationTime > 0.05) { + double time = std::fmod(sTransform.interpolationTime, 0.05f); + m_InterpolationPoints[transform.EntityID].pop(); + if (m_InterpolationPoints[transform.EntityID].size() <= 0) { + return; + } + sTransform = m_InterpolationPoints[transform.EntityID].front(); + sTransform.interpolationTime = time; + } + glm::vec3 nextPosition = sTransform.Position; + glm::vec3 currentPosition = static_cast(transform["Position"]); + transform["Position"] = vectorInterpolation(currentPosition, nextPosition, sTransform.interpolationTime); + } +} + +glm::vec3 InterpolationSystem::vectorInterpolation(glm::vec3 prev, glm::vec3 next, double currentTime) +{ + glm::vec3 difference = next - prev; + glm::vec3 position = difference / 0.05f * static_cast(currentTime); + return position; +} + +bool InterpolationSystem::OnInterpolate(const Events::Interpolate & e) +{ + Transform transform; + int offset = 0; + // Read the data + memcpy(&transform.Position, e.DataArray.get() + offset, sizeof(glm::vec3)); + offset += sizeof(glm::vec3); + memcpy(&transform.Orientation, e.DataArray.get() + offset, sizeof(glm::vec3)); + offset += sizeof(glm::vec3); + memcpy(&transform.Scale, e.DataArray.get() + offset, sizeof(glm::vec3)); + + // Check if queue already exists + if (m_InterpolationPoints.find(e.Entity) != m_InterpolationPoints.end()) { // Did exist, push to queue + m_InterpolationPoints[e.Entity].push(transform); + } else { // Did not exist, create queue + std::queue transformQueue; + transformQueue.push(transform); + m_InterpolationPoints[e.Entity] = transformQueue; + } + return false; +} From 0c7f2c5198d821217b48a4992f4eac3a605a4a89 Mon Sep 17 00:00:00 2001 From: Jocke Date: Mon, 18 Jan 2016 17:12:07 +0100 Subject: [PATCH 10/27] WIP implemented Interpolation (server logic) --- include/Engine/Network/Client.h | 5 ++++- src/Engine/Network/Client.cpp | 22 ++++++++++++++++++++-- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/include/Engine/Network/Client.h b/include/Engine/Network/Client.h index 7aa20126..6aaa9e77 100644 --- a/include/Engine/Network/Client.h +++ b/include/Engine/Network/Client.h @@ -4,9 +4,11 @@ #include #include #include +#include #include #include +#include #include "Network/Network.h" #include "Network/MessageType.h" @@ -68,10 +70,11 @@ private: void ping(); void parseMessageType(Packet& packet); void updateFields(Packet& packet, const ComponentInfo& componentInfo, const EntityID& entityID, const std::string& componentType); - void parseConnect(Packet& packet); + void parseConnect(Packet& packet); void parsePlayerConnected(Packet& packet); void parsePing(); void parseServerPing(); + void InterpolateFields(Packet & packet, const ComponentInfo & componentInfo, const EntityID & entityID, const std::string & componentType); void parseSnapshot(Packet& packet); void identifyPacketLoss(); bool isConnected(); diff --git a/src/Engine/Network/Client.cpp b/src/Engine/Network/Client.cpp index d6e8f4c5..9ffd570b 100644 --- a/src/Engine/Network/Client.cpp +++ b/src/Engine/Network/Client.cpp @@ -112,6 +112,21 @@ void Client::parseServerPing() send(packet); } +// Fields with strings will not work right now +void Client::InterpolateFields(Packet& packet, const ComponentInfo& componentInfo, const EntityID& entityID, const std::string& componentType) +{ + int sizeOfFields = 0; + for (auto field : componentInfo.FieldsInOrder) { + ComponentInfo::Field_t fieldInfo = componentInfo.Fields.at(field); + sizeOfFields = fieldInfo.Stride; + } + // Is the size correct? + boost::shared_array eventData(new char[componentInfo.Meta.Stride]); + memcpy(eventData.get(), packet.ReadData(componentInfo.Meta.Stride), componentInfo.Meta.Stride); + //Send event to interpolat system + +} + void Client::updateFields(Packet& packet, const ComponentInfo& componentInfo, const EntityID& entityID, const std::string& componentType) { for (auto field : componentInfo.FieldsInOrder) { @@ -125,7 +140,6 @@ void Client::updateFields(Packet& packet, const ComponentInfo& componentInfo, co } } -// Field parse void Client::parseSnapshot(Packet& packet) { std::string componentType = packet.ReadString(); @@ -142,7 +156,11 @@ void Client::parseSnapshot(Packet& packet) // Check if the component exists if (m_World->HasComponent(entityID, componentType)) { // If the entity and the component exists update it - updateFields(packet, componentInfo, entityID, componentType); + if (componentType == "Transform") { + InterpolateFields(packet, componentInfo, entityID, componentType); + } else { + updateFields(packet, componentInfo, entityID, componentType); + } // if entity exists but not the component } else { // Create component From 62c3f72355201b52dbde5d38a7eed96eecac03e8 Mon Sep 17 00:00:00 2001 From: stiffly Date: Mon, 18 Jan 2016 17:27:37 +0100 Subject: [PATCH 11/27] Fixed cmake for interpolationsystem. --- include/Engine/Network/EInterpolate.h | 2 +- src/Game/CMakeLists.txt | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/include/Engine/Network/EInterpolate.h b/include/Engine/Network/EInterpolate.h index 65038e49..93bf1a5c 100644 --- a/include/Engine/Network/EInterpolate.h +++ b/include/Engine/Network/EInterpolate.h @@ -12,7 +12,7 @@ namespace Events struct Interpolate : Event { EntityID Entity; - boost::shared_array DataArray; + boost::shared_array DataArray; }; } diff --git a/src/Game/CMakeLists.txt b/src/Game/CMakeLists.txt index 04146670..769cbd4f 100644 --- a/src/Game/CMakeLists.txt +++ b/src/Game/CMakeLists.txt @@ -21,6 +21,7 @@ set(SOURCE_FILES "Game.cpp" "HealthSystem.cpp" "PlayerSystem.cpp" + "InterpolationSystem.cpp" ) set(LIBRARIES From 765509b51095da7c96cf815e0a44778fc907f429 Mon Sep 17 00:00:00 2001 From: stiffly Date: Mon, 18 Jan 2016 17:34:17 +0100 Subject: [PATCH 12/27] Added interpolationsystem to pipeline. --- include/Game/Game.h | 2 +- src/Engine/Network/Client.cpp | 1 + src/Game/Game.cpp | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/include/Game/Game.h b/include/Game/Game.h index dfe1cff6..6614957f 100644 --- a/include/Game/Game.h +++ b/include/Game/Game.h @@ -20,7 +20,7 @@ #include "Core/EntityFile.h" #include "Rendering/RenderSystem.h" #include "Core/EntityFileParser.h" - +#include "InterpolationSystem.h" // Network #include #include "Network/Network.h" diff --git a/src/Engine/Network/Client.cpp b/src/Engine/Network/Client.cpp index 9ffd570b..139d15ae 100644 --- a/src/Engine/Network/Client.cpp +++ b/src/Engine/Network/Client.cpp @@ -33,6 +33,7 @@ void Client::Start(World* world, EventBroker* eventBroker) void Client::Update() { + m_EventBroker->Process(); readFromServer(); } diff --git a/src/Game/Game.cpp b/src/Game/Game.cpp index ba660a7d..7ccd7fac 100644 --- a/src/Game/Game.cpp +++ b/src/Game/Game.cpp @@ -66,6 +66,7 @@ Game::Game(int argc, char* argv[]) m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel, m_Renderer); m_SystemPipeline->AddSystem(updateOrderLevel); + m_SystemPipeline->AddSystem(updateOrderLevel); //Collision and TriggerSystem should update after player. ++updateOrderLevel; @@ -119,7 +120,6 @@ void Game::Tick() // Iterate through systems and update world! m_SystemPipeline->Update(m_World, dt); m_Renderer->Update(dt); - m_EventBroker->Process(); GLERROR("Game::Tick m_RenderQueueFactory->Update"); m_Renderer->Draw(*m_RenderFrame); From 3e90ed564c0de4288e29f84087fd481c596681d3 Mon Sep 17 00:00:00 2001 From: Jocke Date: Mon, 18 Jan 2016 18:07:39 +0100 Subject: [PATCH 13/27] Moved Struct in InterpolationSystem.h and fixed bug. --- include/Game/InterpolationSystem.h | 14 ++++++++------ src/Game/InterpolationSystem.cpp | 3 ++- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/include/Game/InterpolationSystem.h b/include/Game/InterpolationSystem.h index c87ee5a7..2acea373 100644 --- a/include/Game/InterpolationSystem.h +++ b/include/Game/InterpolationSystem.h @@ -12,15 +12,17 @@ #include "Network/EInterpolate.h" -struct Transform { - glm::vec3 Position; - glm::vec3 Scale; - glm::vec3 Orientation; - double interpolationTime; -}; class InterpolationSystem : public PureSystem { + struct Transform + { + glm::vec3 Position; + glm::vec3 Scale; + glm::vec3 Orientation; + double interpolationTime; + }; + public: InterpolationSystem(EventBroker* eventbroker) : PureSystem(eventbroker, "Transform") diff --git a/src/Game/InterpolationSystem.cpp b/src/Game/InterpolationSystem.cpp index d2d81fda..72207531 100644 --- a/src/Game/InterpolationSystem.cpp +++ b/src/Game/InterpolationSystem.cpp @@ -16,7 +16,7 @@ void InterpolationSystem::UpdateComponent(World * world, ComponentWrapper & tran } glm::vec3 nextPosition = sTransform.Position; glm::vec3 currentPosition = static_cast(transform["Position"]); - transform["Position"] = vectorInterpolation(currentPosition, nextPosition, sTransform.interpolationTime); + (glm::vec3&)transform["Position"] += vectorInterpolation(currentPosition, nextPosition, sTransform.interpolationTime); } } @@ -37,6 +37,7 @@ bool InterpolationSystem::OnInterpolate(const Events::Interpolate & e) memcpy(&transform.Orientation, e.DataArray.get() + offset, sizeof(glm::vec3)); offset += sizeof(glm::vec3); memcpy(&transform.Scale, e.DataArray.get() + offset, sizeof(glm::vec3)); + transform.interpolationTime = 0.0f; // Check if queue already exists if (m_InterpolationPoints.find(e.Entity) != m_InterpolationPoints.end()) { // Did exist, push to queue From 88eb3ca2dbf3d4da34aed86a985ccc386e7c9632 Mon Sep 17 00:00:00 2001 From: stiffly Date: Mon, 18 Jan 2016 18:07:59 +0100 Subject: [PATCH 14/27] Scraping queues for interpolation --- include/Game/InterpolationSystem.h | 16 ++++---- src/Engine/Network/Packet.cpp | 8 ++-- src/Engine/Network/Server.cpp | 4 +- src/Game/InterpolationSystem.cpp | 60 ++++++++++++++++++------------ 4 files changed, 50 insertions(+), 38 deletions(-) diff --git a/include/Game/InterpolationSystem.h b/include/Game/InterpolationSystem.h index c87ee5a7..3984ab5e 100644 --- a/include/Game/InterpolationSystem.h +++ b/include/Game/InterpolationSystem.h @@ -12,15 +12,14 @@ #include "Network/EInterpolate.h" -struct Transform { - glm::vec3 Position; - glm::vec3 Scale; - glm::vec3 Orientation; - double interpolationTime; -}; - class InterpolationSystem : public PureSystem { + struct Transform { + glm::vec3 Position; + glm::vec3 Scale; + glm::vec3 Orientation; + double interpolationTime; + }; public: InterpolationSystem(EventBroker* eventbroker) : PureSystem(eventbroker, "Transform") @@ -31,7 +30,8 @@ public: virtual void UpdateComponent(World* world, ComponentWrapper& transform, double dt) override; private: - std::unordered_map> m_InterpolationPoints; + //std::unordered_map> m_InterpolationPoints; + std::unordered_map m_InterpolationPoints; glm::vec3 vectorInterpolation(glm::vec3 prev, glm::vec3 next, double currentTime); diff --git a/src/Engine/Network/Packet.cpp b/src/Engine/Network/Packet.cpp index 2b2c7938..568a78e3 100644 --- a/src/Engine/Network/Packet.cpp +++ b/src/Engine/Network/Packet.cpp @@ -40,7 +40,7 @@ void Packet::WriteString(const std::string& str) // Message, add one extra byte for null terminator int sizeOfString = str.size() + 1; if (m_Offset + sizeOfString > m_MaxPacketSize) { - LOG_WARNING("Package::WriteString(): Data size in packet exceeded maximum package size. New size is %i bytes\n", m_MaxPacketSize*2); + //LOG_WARNING("Package::WriteString(): Data size in packet exceeded maximum package size. New size is %i bytes\n", m_MaxPacketSize*2); resizeData(); } memcpy(m_Data + m_Offset, str.data(), sizeOfString * sizeof(char)); @@ -50,7 +50,7 @@ void Packet::WriteString(const std::string& str) void Packet::WriteData(char * data, int sizeOfData) { if (m_Offset + sizeOfData > m_MaxPacketSize) { - LOG_WARNING("Packet::WriteData(): Data size in packet exceeded maximum packet size. New size is %i bytes\n", m_MaxPacketSize*2); + //LOG_WARNING("Packet::WriteData(): Data size in packet exceeded maximum packet size. New size is %i bytes\n", m_MaxPacketSize*2); resizeData(); } memcpy(m_Data + m_Offset, data, sizeOfData); @@ -61,7 +61,7 @@ std::string Packet::ReadString() { std::string returnValue(m_Data + m_ReturnDataOffset); if (m_Offset < m_ReturnDataOffset + returnValue.size()) { - LOG_WARNING("packet ReadString(): Oh no! You are trying to remove things outside my memory kingdom"); + //LOG_WARNING("packet ReadString(): Oh no! You are trying to remove things outside my memory kingdom"); return "PopFrontString Failed"; } // +1 for null terminator. @@ -72,7 +72,7 @@ std::string Packet::ReadString() char * Packet::ReadData(int SizeOfData) { if (m_Offset < m_ReturnDataOffset + SizeOfData) { - LOG_WARNING("packet ReadData(): Oh no! You are trying to remove things outside my memory kingdom"); + //LOG_WARNING("packet ReadData(): Oh no! You are trying to remove things outside my memory kingdom"); return nullptr; } unsigned int oldReturnDataOffset = m_ReturnDataOffset; diff --git a/src/Engine/Network/Server.cpp b/src/Engine/Network/Server.cpp index 9ec1a041..1f9db461 100644 --- a/src/Engine/Network/Server.cpp +++ b/src/Engine/Network/Server.cpp @@ -227,7 +227,7 @@ void Server::parseOnInputCommand(Packet& packet) e.PlayerID = playerID; // Set correct player id 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); + //LOG_INFO("Server::parseOnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID); } } } @@ -239,7 +239,7 @@ void Server::parseOnPlayerDamage(Packet & packet) e.PlayerDamagedID = packet.ReadPrimitive(); e.TypeOfDamage = packet.ReadString(); m_EventBroker->Publish(e); - 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) diff --git a/src/Game/InterpolationSystem.cpp b/src/Game/InterpolationSystem.cpp index d2d81fda..d2413234 100644 --- a/src/Game/InterpolationSystem.cpp +++ b/src/Game/InterpolationSystem.cpp @@ -1,23 +1,32 @@ #include "InterpolationSystem.h" +//void InterpolationSystem::UpdateComponent(World * world, ComponentWrapper & transform, double dt) +//{ +// if (m_InterpolationPoints[transform.EntityID].size() > 0) { +// Transform& sTransform = m_InterpolationPoints[transform.EntityID].front(); +// sTransform.interpolationTime += dt; +// if (sTransform.interpolationTime > 0.05) { +// double time = std::fmod(sTransform.interpolationTime, 0.05f); +// m_InterpolationPoints[transform.EntityID].pop(); +// if (m_InterpolationPoints[transform.EntityID].size() <= 0) { +// return; +// } +// sTransform = m_InterpolationPoints[transform.EntityID].front(); +// sTransform.interpolationTime = time; +// } +// glm::vec3 nextPosition = sTransform.Position; +// glm::vec3 currentPosition = static_cast(transform["Position"]); +// transform["Position"] = vectorInterpolation(currentPosition, nextPosition, sTransform.interpolationTime); +// } +//} + void InterpolationSystem::UpdateComponent(World * world, ComponentWrapper & transform, double dt) { - if (m_InterpolationPoints[transform.EntityID].size() > 0) { - Transform& sTransform = m_InterpolationPoints[transform.EntityID].front(); - sTransform.interpolationTime += dt; - if (sTransform.interpolationTime > 0.05) { - double time = std::fmod(sTransform.interpolationTime, 0.05f); - m_InterpolationPoints[transform.EntityID].pop(); - if (m_InterpolationPoints[transform.EntityID].size() <= 0) { - return; - } - sTransform = m_InterpolationPoints[transform.EntityID].front(); - sTransform.interpolationTime = time; - } - glm::vec3 nextPosition = sTransform.Position; - glm::vec3 currentPosition = static_cast(transform["Position"]); - transform["Position"] = vectorInterpolation(currentPosition, nextPosition, sTransform.interpolationTime); - } + Transform& sTransform = m_InterpolationPoints[transform.EntityID]; + sTransform.interpolationTime += dt; + glm::vec3 nextPosition = sTransform.Position; + glm::vec3 currentPosition = static_cast(transform["Position"]); + transform["Position"] = vectorInterpolation(currentPosition, nextPosition, sTransform.interpolationTime); } glm::vec3 InterpolationSystem::vectorInterpolation(glm::vec3 prev, glm::vec3 next, double currentTime) @@ -37,14 +46,17 @@ bool InterpolationSystem::OnInterpolate(const Events::Interpolate & e) memcpy(&transform.Orientation, e.DataArray.get() + offset, sizeof(glm::vec3)); offset += sizeof(glm::vec3); memcpy(&transform.Scale, e.DataArray.get() + offset, sizeof(glm::vec3)); - + transform.interpolationTime = 0; + m_InterpolationPoints[e.Entity] = transform; // Check if queue already exists - if (m_InterpolationPoints.find(e.Entity) != m_InterpolationPoints.end()) { // Did exist, push to queue - m_InterpolationPoints[e.Entity].push(transform); - } else { // Did not exist, create queue - std::queue transformQueue; - transformQueue.push(transform); - m_InterpolationPoints[e.Entity] = transformQueue; - } + //if (m_InterpolationPoints.find(e.Entity) != m_InterpolationPoints.end()) { // Did exist, push to queue + // m_InterpolationPoints[e.Entity].push(transform); + //} + + //else { // Did not exist, create queue + // std::queue transformQueue; + // transformQueue.push(transform); + // m_InterpolationPoints[e.Entity] = transformQueue; + //} return false; } From b2358a1854fad1b28d928cd0782977332c7bf9e4 Mon Sep 17 00:00:00 2001 From: William Moberg Date: Mon, 18 Jan 2016 18:16:24 +0100 Subject: [PATCH 15/27] Added bool in Physics to toggle gravity for entities. --- resources/Schema/Components/Physics.xml | 1 + resources/Schema/Components/Physics.xsd | 1 + src/Game/Systems/PlayerMovementSystem.cpp | 4 +++- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/resources/Schema/Components/Physics.xml b/resources/Schema/Components/Physics.xml index 7dce027c..9d1638fb 100644 --- a/resources/Schema/Components/Physics.xml +++ b/resources/Schema/Components/Physics.xml @@ -1,4 +1,5 @@ + true diff --git a/resources/Schema/Components/Physics.xsd b/resources/Schema/Components/Physics.xsd index 001dd2c8..cc5e24bb 100644 --- a/resources/Schema/Components/Physics.xsd +++ b/resources/Schema/Components/Physics.xsd @@ -10,6 +10,7 @@ + diff --git a/src/Game/Systems/PlayerMovementSystem.cpp b/src/Game/Systems/PlayerMovementSystem.cpp index 536624b3..57eef38d 100644 --- a/src/Game/Systems/PlayerMovementSystem.cpp +++ b/src/Game/Systems/PlayerMovementSystem.cpp @@ -9,7 +9,9 @@ void PlayerMovementSystem::UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& cPhysics = entity["Physics"]; glm::vec3& velocity = cPhysics["Velocity"]; - velocity.y -= 9.82 * dt; + if (cPhysics["Gravity"]) { + velocity.y -= 9.82 * dt; + } glm::vec3& position = cTransform["Position"]; position += velocity * (float)dt; From 621d935d7aced969cc920bb32acbaada49db4baf Mon Sep 17 00:00:00 2001 From: William Moberg Date: Mon, 18 Jan 2016 18:24:11 +0100 Subject: [PATCH 16/27] Octree returns correct boxes when testing along an axis by searching through the correct child subtrees. --- src/Engine/Core/AABB.cpp | 2 ++ src/Engine/Core/Octree.cpp | 8 ++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Engine/Core/AABB.cpp b/src/Engine/Core/AABB.cpp index 22272104..55b362fe 100644 --- a/src/Engine/Core/AABB.cpp +++ b/src/Engine/Core/AABB.cpp @@ -15,6 +15,8 @@ AABB::AABB(const glm::vec3& minPos, const glm::vec3& maxPos) m_MinCorner.y = glm::min(m_MaxCorner.y, m_MinCorner.y); m_MaxCorner.z = glm::max(m_MaxCorner.z, m_MinCorner.z); m_MinCorner.z = glm::min(m_MaxCorner.z, m_MinCorner.z); + m_Origin = 0.5f * (m_MaxCorner + m_MinCorner); + m_HalfSize = 0.5f * (m_MaxCorner - m_MinCorner); } } diff --git a/src/Engine/Core/Octree.cpp b/src/Engine/Core/Octree.cpp index 47d06add..58501117 100644 --- a/src/Engine/Core/Octree.cpp +++ b/src/Engine/Core/Octree.cpp @@ -352,9 +352,13 @@ std::vector Octree::Child::childIndicesContainingBox(const AABB& box) const //the dimensions they are responsible for (which octant). bits.flip(); //At this point the bits necessarily have exactly one bit set. + //Check the same bit in the minInd as the one set in bits. + int setOrUnset = (bits.to_ulong() & minInd); for (int c = 0; c < 8; ++c) { - //If the child index have the same bit set as the bits, add box to it. - if (bits.to_ulong() & c) { + //Check the same bit in the child index as the one set in bits. + //Enter here if both c and minInd have the bit set, or if neither have it set. + //I.e, if they are on the same side (+ or -) in the dimension marked by the bit in bits. + if (!((bits.to_ulong() & c) ^ setOrUnset)) { ret.push_back(c); } } From 3142c701e3c68553094c783e0d2b77ee4e3fc37c Mon Sep 17 00:00:00 2001 From: stiffly Date: Tue, 19 Jan 2016 11:42:30 +0100 Subject: [PATCH 17/27] WIP interpolating scale and orientation --- include/Game/InterpolationSystem.h | 13 +++++++++++-- src/Game/InterpolationSystem.cpp | 30 +++++++++++++++++++++--------- 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/include/Game/InterpolationSystem.h b/include/Game/InterpolationSystem.h index c8e88834..73329094 100644 --- a/include/Game/InterpolationSystem.h +++ b/include/Game/InterpolationSystem.h @@ -5,6 +5,7 @@ #include #include #include +#include #include "Common.h" #include "Core/System.h" @@ -12,6 +13,7 @@ #include "Network/EInterpolate.h" +#define SNAPSHOTINTERVAL 0.05f class InterpolationSystem : public PureSystem { @@ -19,7 +21,7 @@ class InterpolationSystem : public PureSystem { glm::vec3 Position; glm::vec3 Scale; - glm::vec3 Orientation; + glm::quat Orientation; double interpolationTime; }; public: @@ -35,7 +37,14 @@ private: //std::unordered_map> m_InterpolationPoints; std::unordered_map m_InterpolationPoints; - glm::vec3 vectorInterpolation(glm::vec3 prev, glm::vec3 next, double currentTime); + //glm::vec3 vectorInterpolation(glm::vec3 prev, glm::vec3 next, double currentTime); + template + T vectorInterpolation(T prev, T next, double currentTime) + { + T difference = next - prev; + T vector = (difference / SNAPSHOTINTERVAL) * static_cast(currentTime); + return vector; + } EventRelay m_EInterpolate; bool InterpolationSystem::OnInterpolate(const Events::Interpolate& e); diff --git a/src/Game/InterpolationSystem.cpp b/src/Game/InterpolationSystem.cpp index 2d8de336..d3592132 100644 --- a/src/Game/InterpolationSystem.cpp +++ b/src/Game/InterpolationSystem.cpp @@ -24,17 +24,27 @@ void InterpolationSystem::UpdateComponent(World * world, ComponentWrapper & tran { Transform& sTransform = m_InterpolationPoints[transform.EntityID]; sTransform.interpolationTime += dt; + // Position glm::vec3 nextPosition = sTransform.Position; glm::vec3 currentPosition = static_cast(transform["Position"]); - (glm::vec3&)transform["Position"] += vectorInterpolation(currentPosition, nextPosition, sTransform.interpolationTime); + (glm::vec3&)transform["Position"] += vectorInterpolation(currentPosition, nextPosition, sTransform.interpolationTime); + // Orientation + glm::quat nextOrientation = sTransform.Orientation; + glm::quat currentOrientation = glm::quat(static_cast(transform["Orientation"])); + (glm::vec3&)transform["Orientation"] = glm::eulerAngles(glm::slerp(currentOrientation, nextOrientation, sTransform.interpolationTime / SNAPSHOTINTERVAL)); + // Scale + glm::vec3 nextScale = sTransform.Scale; + glm::vec3 currentScale = static_cast(transform["Scale"]); + //glm::vec3 resize = vectorInterpolation(currentScale, nextScale, sTransform.interpolationTime); + (glm::vec3&)transform["Scale"] += vectorInterpolation(currentScale, nextScale, sTransform.interpolationTime); } -glm::vec3 InterpolationSystem::vectorInterpolation(glm::vec3 prev, glm::vec3 next, double currentTime) -{ - glm::vec3 difference = next - prev; - glm::vec3 position = difference / 0.05f * static_cast(currentTime); - return position; -} +//glm::vec3 InterpolationSystem::vectorInterpolation(glm::vec3 prev, glm::vec3 next, double currentTime) +//{ +// glm::vec3 difference = next - prev; +// glm::vec3 position = difference / SNAPSHOTINTERVAL * static_cast(currentTime); +// return position; +//} bool InterpolationSystem::OnInterpolate(const Events::Interpolate & e) { @@ -43,9 +53,11 @@ bool InterpolationSystem::OnInterpolate(const Events::Interpolate & e) // Read the data memcpy(&transform.Position, e.DataArray.get() + offset, sizeof(glm::vec3)); offset += sizeof(glm::vec3); - memcpy(&transform.Orientation, e.DataArray.get() + offset, sizeof(glm::vec3)); + glm::vec3 tempOrientation; + memcpy(&tempOrientation, e.DataArray.get() + offset, sizeof(glm::vec3)); + transform.Orientation = glm::quat(tempOrientation); offset += sizeof(glm::vec3); - memcpy(&transform.Scale, e.DataArray.get() + offset, sizeof(glm::vec3)); + memcpy(&transform.Scale, e.DataArray.get() + offset, sizeof(glm::vec3)); transform.interpolationTime = 0.0f; m_InterpolationPoints[e.Entity] = transform; // Check if queue already exists From 713ebbe18c21a098010a5496813b9dff3ce45947 Mon Sep 17 00:00:00 2001 From: William Moberg Date: Tue, 19 Jan 2016 14:50:46 +0100 Subject: [PATCH 18/27] Can add any objects that inherit from AABB into the Octree. --- .../Engine/Collision/CollidableOctreeSystem.h | 4 +- include/Engine/Collision/CollisionSystem.h | 4 +- include/Engine/Collision/TriggerSystem.h | 4 +- include/Engine/Core/Octree.h | 258 +++++++++++++----- include/Game/Game.h | 4 +- src/Engine/Collision/CollisionSystem.cpp | 2 +- src/Engine/Core/Octree.cpp | 133 ++------- src/Game/Game.cpp | 4 +- 8 files changed, 224 insertions(+), 189 deletions(-) diff --git a/include/Engine/Collision/CollidableOctreeSystem.h b/include/Engine/Collision/CollidableOctreeSystem.h index 8fa1f0a4..c61e774c 100644 --- a/include/Engine/Collision/CollidableOctreeSystem.h +++ b/include/Engine/Collision/CollidableOctreeSystem.h @@ -8,7 +8,7 @@ class CollidableOctreeSystem : public ImpureSystem, public PureSystem { public: - CollidableOctreeSystem(EventBroker* eventBroker, Octree* octree) + CollidableOctreeSystem(EventBroker* eventBroker, Octree* octree) : System(eventBroker) , PureSystem("Collidable") , m_Octree(octree) @@ -18,7 +18,7 @@ public: virtual void UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& component, double dt) override; private: - Octree* m_Octree; + Octree* m_Octree; }; #endif \ No newline at end of file diff --git a/include/Engine/Collision/CollisionSystem.h b/include/Engine/Collision/CollisionSystem.h index 561c5158..7815254d 100644 --- a/include/Engine/Collision/CollisionSystem.h +++ b/include/Engine/Collision/CollisionSystem.h @@ -13,7 +13,7 @@ class CollisionSystem : public PureSystem { public: - CollisionSystem(EventBroker* eventBroker, Octree* octree) + CollisionSystem(EventBroker* eventBroker, Octree* octree) : System(eventBroker) , PureSystem("Collidable") , m_Octree(octree) @@ -26,7 +26,7 @@ public: virtual void UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& component, double dt) override; private: - Octree* m_Octree; + Octree* m_Octree; bool zPress; EventRelay m_EKeyUp; diff --git a/include/Engine/Collision/TriggerSystem.h b/include/Engine/Collision/TriggerSystem.h index 65e7c271..1b423e76 100644 --- a/include/Engine/Collision/TriggerSystem.h +++ b/include/Engine/Collision/TriggerSystem.h @@ -14,7 +14,7 @@ class AABB; class TriggerSystem : public PureSystem { public: - TriggerSystem(EventBroker* eventBroker, Octree* octree) + TriggerSystem(EventBroker* eventBroker, Octree* octree) : System(eventBroker) , PureSystem("Trigger") , m_Octree(octree) @@ -27,7 +27,7 @@ public: virtual void UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& component, double dt) override; private: - Octree* m_Octree; + Octree* m_Octree; std::unordered_map> m_EntitiesTouchingTrigger; std::unordered_map> m_EntitiesCompletelyInTrigger; diff --git a/include/Engine/Core/Octree.h b/include/Engine/Core/Octree.h index 954dbcbc..bbd27b3c 100644 --- a/include/Engine/Core/Octree.h +++ b/include/Engine/Core/Octree.h @@ -1,19 +1,27 @@ #ifndef Octree_h__ #define Octree_h__ +#include + #include "../Common.h" #include "AABB.h" +//Fwd declarations. class Ray; +namespace OctSpace +{ +struct Output; +struct ContainedObject; +struct Child; +} + +//T needs to be AABB, or inherit from AABB. +//T also needs to have a default constructor. +template class Octree { public: - struct Output - { - float CollideDistance; - }; - Octree() = delete; ~Octree(); //For the root Octree, [octreeBounds] should be a box containing the entire level. @@ -25,81 +33,201 @@ public: Octree(const Octree&& other) = delete; Octree& operator= (const Octree& other) = delete; //Add a dynamic object (one that moves around) into the tree. - void AddDynamicObject(const AABB& box); + void AddDynamicObject(const T& object); //Add a static object (that does not move) into the tree. - void AddStaticObject(const AABB& box); - //Get the boxes that are in the same area as the input [box], the boxes are put in [outBoxes]. - void BoxesInSameRegion(const AABB& box, std::vector& outBoxes); + void AddStaticObject(const T& object); + //Get the objects that are in the same area as the input [box], the objects are put in [outObjects]. + //The type Box must be AABB, or inherit from AABB. + template + void ObjectsInSameRegion(const Box& box, std::vector& outObjects); //Empty the tree of all objects, static and dynamic. void ClearObjects(); //Empty the tree of all dynamic objects. Static objects remain in the tree. void ClearDynamicObjects(); //Returns true if the ray collides with something in the tree. Result is written to [data]. - bool RayCollides(const Ray& ray, Output& data); + bool RayCollides(const Ray& ray, OctSpace::Output& data); //Returns true if the box collides with something in the tree. //On collision with a box, that box is written to [outBoxIntersected]. - //Note: More efficient than calling BoxesInSameRegion from outside and testing there. + //Note: More efficient than calling ObjectsInSameRegion from outside and testing there. bool BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected); private: - struct Child; //Fwd declaration; - struct ContainedObject - { - ContainedObject() - : Box(AABB()) - , Checked(false) - {} - ContainedObject(AABB box) - : Box(box) - , Checked(false) - {} - AABB Box; - bool Checked; - }; - Child* m_Root; - std::vector m_StaticObjects; - std::vector m_DynamicObjects; - - bool m_UpdatedOnce; - unsigned int m_BoxID; - glm::vec3 m_PrevPos; - glm::quat m_PrevOri; + OctSpace::Child* m_Root; + std::vector m_StaticObjects; + std::vector m_DynamicObjects; void falsifyObjectChecks(); - - struct Child - { - ~Child(); - Child(const AABB& octTreeBounds, - int subDivisions, - std::vector& staticObjects, - std::vector& dynamicObjects); - Child(const Child& other) = delete; - Child(const Child&& other) = delete; - Child& operator= (const Child& other) = delete; - void AddDynamicObject(const AABB& box); - void AddStaticObject(const AABB& box); - void BoxesInSameRegion(const AABB& box, std::vector& outBoxes) const; - void ClearObjects(); - void ClearDynamicObjects(); - bool RayCollides(const Ray& ray, Output& data) const; - bool BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected) const; - - Child* m_Children[8]; - //Indices into the lists in Octree. - std::vector m_StaticObjIndices; - std::vector m_DynamicObjIndices; - AABB m_Box; - //Reference to the lists in Octree. - std::vector& m_StaticObjectsRef; - std::vector& m_DynamicObjectsRef; - - inline bool hasChildren() const; - int childIndexContainingPoint(const glm::vec3& point) const; - std::vector childIndicesContainingBox(const AABB& box) const; - }; }; +namespace OctSpace +{ + +struct Output +{ + float CollideDistance; +}; + +struct ContainedObject +{ + ContainedObject() + : Box(nullptr) + , Checked(false) + {} + template + ContainedObject(const BoxlikeObject& box) + : Box(new BoxlikeObject(box)) + , Checked(false) + {} + std::unique_ptr Box; + bool Checked; +}; + +struct Child +{ + ~Child(); + Child(const AABB& octTreeBounds, + int subDivisions, + std::vector& staticObjects, + std::vector& dynamicObjects); + Child(const Child& other) = delete; + Child(const Child&& other) = delete; + Child& operator= (const Child& other) = delete; + void AddDynamicObject(const AABB& box); + void AddStaticObject(const AABB& box); + template + void ObjectsInSameRegion(const Box& box, std::vector& outObjects) const; + void ClearObjects(); + void ClearDynamicObjects(); + bool RayCollides(const Ray& ray, Output& data) const; + bool BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected) const; + + Child* m_Children[8]; + //Indices into the lists in Octree. + std::vector m_StaticObjIndices; + std::vector m_DynamicObjIndices; + AABB m_Box; + //Reference to the lists in Octree. + std::vector& m_StaticObjectsRef; + std::vector& m_DynamicObjectsRef; + + inline bool hasChildren() const; + int childIndexContainingPoint(const glm::vec3& point) const; + std::vector childIndicesContainingBox(const AABB& box) const; +}; + +} + +template +Octree::Octree(const AABB& octTreeBounds, int subDivisions) + : m_Root(new OctSpace::Child(octTreeBounds, subDivisions, m_StaticObjects, m_DynamicObjects)) +{ + static_assert(std::is_base_of::value, "template argument type T in Octree must be a subclass of AABB."); +} + +template +Octree::~Octree() +{ + delete m_Root; +} + +template +void Octree::AddDynamicObject(const T& object) +{ + m_Root->AddDynamicObject(object); + m_DynamicObjects.emplace_back(object); +} + +template +void Octree::AddStaticObject(const T& object) +{ + m_Root->AddStaticObject(object); + m_StaticObjects.emplace_back(object); +} + +template +template +void Octree::ObjectsInSameRegion(const Box& box, std::vector& outObjects) +{ + static_assert(std::is_base_of::value, "template argument type Box in Octree::ObjectsInSameRegion must be a subclass of AABB."); + falsifyObjectChecks(); + m_Root->ObjectsInSameRegion(box, outObjects); +} + +template +void Octree::ClearObjects() +{ + m_StaticObjects.clear(); + m_DynamicObjects.clear(); + m_Root->ClearObjects(); +} + +template +void Octree::ClearDynamicObjects() +{ + m_DynamicObjects.clear(); + m_Root->ClearDynamicObjects(); +} + +template +bool Octree::RayCollides(const Ray& ray, OctSpace::Output& data) +{ + falsifyObjectChecks(); + data.CollideDistance = -1; + return m_Root->RayCollides(ray, data); +} + +template +bool Octree::BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected) +{ + falsifyObjectChecks(); + return m_Root->BoxCollides(boxToTest, outBoxIntersected); +} + +template +void Octree::falsifyObjectChecks() +{ + for (auto& obj : m_StaticObjects) { + obj.Checked = false; + } + for (auto& obj : m_DynamicObjects) { + obj.Checked = false; + } +} + +template +void OctSpace::Child::ObjectsInSameRegion(const Box& box, std::vector& outObjects) const +{ + if (hasChildren()) { + for (auto i : childIndicesContainingBox(box)) { + m_Children[i]->ObjectsInSameRegion(box, outObjects); + } + } else { + size_t startIndex = outObjects.size(); + int numDuplicates = 0; + outObjects.resize(outObjects.size() + m_StaticObjIndices.size() + m_DynamicObjIndices.size()); + for (size_t i = 0; i < m_StaticObjIndices.size(); ++i) { + ContainedObject& obj = m_StaticObjectsRef[m_StaticObjIndices[i]]; + if (obj.Checked) { + ++numDuplicates; + } else { + obj.Checked = true; + outObjects[startIndex + i - numDuplicates] = *static_cast(obj.Box.get()); + } + } + for (size_t i = 0; i < m_DynamicObjIndices.size(); ++i) { + ContainedObject& obj = m_DynamicObjectsRef[m_DynamicObjIndices[i]]; + if (obj.Checked) { + ++numDuplicates; + } else { + obj.Checked = true; + outObjects[startIndex + i - numDuplicates] = *static_cast(obj.Box.get()); + } + } + for (size_t i = 0; i < numDuplicates; ++i) { + outObjects.pop_back(); + } + } +} #endif \ No newline at end of file diff --git a/include/Game/Game.h b/include/Game/Game.h index dbc2ed45..d3a79328 100644 --- a/include/Game/Game.h +++ b/include/Game/Game.h @@ -47,8 +47,8 @@ private: InputProxy* m_InputProxy; GUI::Frame* m_FrameStack; World* m_World; - Octree* m_OctreeCollision; - Octree* m_OctreeFrustrumCulling; + Octree* m_OctreeCollision; + Octree* m_OctreeFrustrumCulling; SystemPipeline* m_SystemPipeline; RenderFrame* m_RenderFrame; // Network variables diff --git a/src/Engine/Collision/CollisionSystem.cpp b/src/Engine/Collision/CollisionSystem.cpp index d841c75e..a9d125ac 100644 --- a/src/Engine/Collision/CollisionSystem.cpp +++ b/src/Engine/Collision/CollisionSystem.cpp @@ -23,7 +23,7 @@ void CollisionSystem::UpdateComponent(World* world, EntityWrapper& entity, Compo // Collide against octree std::vector octreeResult; - m_Octree->BoxesInSameRegion(*boundingBox, octreeResult); + m_Octree->ObjectsInSameRegion(*boundingBox, octreeResult); for (auto& boxB : octreeResult) { glm::vec3 resolutionVector; if (Collision::IsSameBoxProbably(boxA, boxB)) { diff --git a/src/Engine/Core/Octree.cpp b/src/Engine/Core/Octree.cpp index 58501117..d7feba45 100644 --- a/src/Engine/Core/Octree.cpp +++ b/src/Engine/Core/Octree.cpp @@ -21,72 +21,11 @@ bool isFirstLower(const ChildInfo& first, const ChildInfo& second) } -Octree::Octree(const AABB& octTreeBounds, int subDivisions) - : m_Root(new Child(octTreeBounds, subDivisions, m_StaticObjects, m_DynamicObjects)) - , m_UpdatedOnce(false) -{ } - -Octree::~Octree() +namespace OctSpace { - delete m_Root; -} -void Octree::AddDynamicObject(const AABB& box) -{ - m_Root->AddDynamicObject(box); - m_DynamicObjects.push_back(box); -} - -void Octree::AddStaticObject(const AABB& box) -{ - m_Root->AddStaticObject(box); - m_StaticObjects.push_back(box); -} - -void Octree::BoxesInSameRegion(const AABB& box, std::vector& outBoxes) -{ - falsifyObjectChecks(); - m_Root->BoxesInSameRegion(box, outBoxes); -} - -void Octree::ClearObjects() -{ - m_StaticObjects.clear(); - m_DynamicObjects.clear(); - m_Root->ClearObjects(); -} - -void Octree::ClearDynamicObjects() -{ - m_DynamicObjects.clear(); - m_Root->ClearDynamicObjects(); -} - -bool Octree::RayCollides(const Ray& ray, Output& data) -{ - falsifyObjectChecks(); - data.CollideDistance = -1; - return m_Root->RayCollides(ray, data); -} - -bool Octree::BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected) -{ - falsifyObjectChecks(); - return m_Root->BoxCollides(boxToTest, outBoxIntersected); -} - -void Octree::falsifyObjectChecks() -{ - for (auto& obj : m_StaticObjects) { - obj.Checked = false; - } - for (auto& obj : m_DynamicObjects) { - obj.Checked = false; - } -} - -Octree::Child::Child(const AABB& octTreeBounds, - int subDivisions, +Child::Child(const AABB& octTreeBounds, + int subDivisions, std::vector& staticObjects, std::vector& dynamicObjects) : m_Box(octTreeBounds) @@ -135,7 +74,7 @@ Octree::Child::Child(const AABB& octTreeBounds, } } -Octree::Child::~Child() +Child::~Child() { for (Child*& c : m_Children) { if (c != nullptr) { @@ -145,7 +84,7 @@ Octree::Child::~Child() } } -bool Octree::Child::BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected) const +bool Child::BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected) const { if (hasChildren()) { for (int i : childIndicesContainingBox(boxToTest)) { @@ -155,7 +94,7 @@ bool Octree::Child::BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected) } else { for (int i : m_StaticObjIndices) { if (!m_StaticObjectsRef[i].Checked) { - const AABB& objBox = m_StaticObjectsRef[i].Box; + const AABB& objBox = *m_StaticObjectsRef[i].Box; if (Collision::AABBVsAABB(boxToTest, objBox)) { outBoxIntersected = objBox; return true; @@ -165,7 +104,7 @@ bool Octree::Child::BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected) } for (int i : m_DynamicObjIndices) { if (!m_DynamicObjectsRef[i].Checked) { - const AABB& objBox = m_DynamicObjectsRef[i].Box; + const AABB& objBox = *m_DynamicObjectsRef[i].Box; if (!Collision::IsSameBoxProbably(boxToTest, objBox) && Collision::AABBVsAABB(boxToTest, objBox)) { outBoxIntersected = objBox; @@ -178,7 +117,7 @@ bool Octree::Child::BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected) return false; } -bool Octree::Child::RayCollides(const Ray& ray, Output& data) const +bool Child::RayCollides(const Ray& ray, OctSpace::Output& data) const { //If the node AABB is missed, everything it contains is missed. if (Collision::RayAABBIntr(ray, m_Box)) { @@ -205,7 +144,7 @@ bool Octree::Child::RayCollides(const Ray& ray, Output& data) const float dist; //If we haven't tested against this object before, and the ray hits. if (!m_StaticObjectsRef[i].Checked && - Collision::RayVsAABB(ray, m_StaticObjectsRef[i].Box, dist)) { + Collision::RayVsAABB(ray, *m_StaticObjectsRef[i].Box, dist)) { minDist = std::min(dist, minDist); intersected = true; } @@ -215,7 +154,7 @@ bool Octree::Child::RayCollides(const Ray& ray, Output& data) const float dist; //If we haven't tested against this object before, and the ray hits. if (!m_DynamicObjectsRef[i].Checked && - Collision::RayVsAABB(ray, m_DynamicObjectsRef[i].Box, dist)) { + Collision::RayVsAABB(ray, *m_DynamicObjectsRef[i].Box, dist)) { minDist = std::min(dist, minDist); intersected = true; } @@ -230,7 +169,7 @@ bool Octree::Child::RayCollides(const Ray& ray, Output& data) const } -void Octree::Child::AddDynamicObject(const AABB& box) +void Child::AddDynamicObject(const AABB& box) { if (hasChildren()) { for (auto i : childIndicesContainingBox(box)) { @@ -242,7 +181,7 @@ void Octree::Child::AddDynamicObject(const AABB& box) } } -void Octree::Child::AddStaticObject(const AABB& box) +void Child::AddStaticObject(const AABB& box) { if (hasChildren()) { for (auto i : childIndicesContainingBox(box)) { @@ -254,41 +193,7 @@ void Octree::Child::AddStaticObject(const AABB& box) } } -void Octree::Child::BoxesInSameRegion(const AABB& box, std::vector& outBoxes) const -{ - if (hasChildren()) { - for (auto i : childIndicesContainingBox(box)) { - m_Children[i]->BoxesInSameRegion(box, outBoxes); - } - } else { - size_t startIndex = outBoxes.size(); - int numDuplicates = 0; - outBoxes.resize(outBoxes.size() + m_StaticObjIndices.size() + m_DynamicObjIndices.size()); - for (size_t i = 0; i < m_StaticObjIndices.size(); ++i){ - ContainedObject& obj = m_StaticObjectsRef[m_StaticObjIndices[i]]; - if (obj.Checked) { - ++numDuplicates; - } else { - obj.Checked = true; - outBoxes[startIndex + i - numDuplicates] = obj.Box; - } - } - for (size_t i = 0; i < m_DynamicObjIndices.size(); ++i) { - ContainedObject& obj = m_DynamicObjectsRef[m_DynamicObjIndices[i]]; - if (obj.Checked) { - ++numDuplicates; - } else { - obj.Checked = true; - outBoxes[startIndex + i - numDuplicates] = obj.Box; - } - } - for (size_t i = 0; i < numDuplicates; ++i) { - outBoxes.pop_back(); - } - } -} - -void Octree::Child::ClearObjects() +void Child::ClearObjects() { if (hasChildren()) { for (Child*& c : m_Children) { @@ -300,11 +205,11 @@ void Octree::Child::ClearObjects() } } -void Octree::Child::ClearDynamicObjects() +void Child::ClearDynamicObjects() { if (hasChildren()) { for (Child*& c : m_Children) { - c->ClearObjects(); + c->ClearDynamicObjects(); } } else { m_DynamicObjIndices.clear(); @@ -323,13 +228,13 @@ void Octree::Child::ClearDynamicObjects() // x : - - - - + + + + // y : - - + + - - + + // z : - + - + - + - + -int Octree::Child::childIndexContainingPoint(const glm::vec3& point) const +int Child::childIndexContainingPoint(const glm::vec3& point) const { const glm::vec3& c = m_Box.Origin(); return (1 << 2) * (point.x >= c.x) | (1 << 1) * (point.y >= c.y) | (point.z >= c.z); } -std::vector Octree::Child::childIndicesContainingBox(const AABB& box) const +std::vector Child::childIndicesContainingBox(const AABB& box) const { int minInd = childIndexContainingPoint(box.MinCorner()); int maxInd = childIndexContainingPoint(box.MaxCorner()); @@ -371,7 +276,9 @@ std::vector Octree::Child::childIndicesContainingBox(const AABB& box) const } } -inline bool Octree::Child::hasChildren() const +inline bool Child::hasChildren() const { return m_Children[0] != nullptr; +} + } \ No newline at end of file diff --git a/src/Game/Game.cpp b/src/Game/Game.cpp index 54f7b69d..6da3ff5c 100644 --- a/src/Game/Game.cpp +++ b/src/Game/Game.cpp @@ -68,8 +68,8 @@ Game::Game(int argc, char* argv[]) m_Renderer->m_World = m_World; // Create Octrees - m_OctreeCollision = new Octree(AABB(glm::vec3(-100), glm::vec3(100)), 4); - m_OctreeFrustrumCulling = new Octree(AABB(glm::vec3(-100), glm::vec3(100)), 4); + m_OctreeCollision = new Octree(AABB(glm::vec3(-100), glm::vec3(100)), 4); + m_OctreeFrustrumCulling = new Octree(AABB(glm::vec3(-100), glm::vec3(100)), 4); // Create system pipeline m_SystemPipeline = new SystemPipeline(m_EventBroker); From ad9bb5fba49a0c3127e586145e681894b115bc92 Mon Sep 17 00:00:00 2001 From: stiffly Date: Tue, 19 Jan 2016 15:03:10 +0100 Subject: [PATCH 19/27] Added an extra interpolation point. --- include/Game/Systems/InterpolationSystem.h | 4 +-- src/Game/Systems/InterpolationSystem.cpp | 37 ++++++++++++---------- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/include/Game/Systems/InterpolationSystem.h b/include/Game/Systems/InterpolationSystem.h index 15b8d167..fb7654b2 100644 --- a/include/Game/Systems/InterpolationSystem.h +++ b/include/Game/Systems/InterpolationSystem.h @@ -34,8 +34,8 @@ public: ~InterpolationSystem() { } virtual void UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& transform, double dt) override; private: - //std::unordered_map> m_InterpolationPoints; - std::unordered_map m_InterpolationPoints; + std::unordered_map m_NextTransform; + std::unordered_map m_LastReceivedTransform; //glm::vec3 vectorInterpolation(glm::vec3 prev, glm::vec3 next, double currentTime); template diff --git a/src/Game/Systems/InterpolationSystem.cpp b/src/Game/Systems/InterpolationSystem.cpp index 7676491f..f6d5989d 100644 --- a/src/Game/Systems/InterpolationSystem.cpp +++ b/src/Game/Systems/InterpolationSystem.cpp @@ -22,9 +22,20 @@ void InterpolationSystem::UpdateComponent(World * world, EntityWrapper& entity, ComponentWrapper & transform, double dt) { - if (m_InterpolationPoints.find(transform.EntityID) != m_InterpolationPoints.end()) { // Exists in map - Transform& sTransform = m_InterpolationPoints[transform.EntityID]; - sTransform.interpolationTime += dt; + if (m_NextTransform.find(transform.EntityID) != m_NextTransform.end()) { // Exists in map + m_NextTransform[transform.EntityID].interpolationTime += dt; + Transform sTransform = m_NextTransform[transform.EntityID]; + double time = sTransform.interpolationTime; + if (time > SNAPSHOTINTERVAL) { + if (m_LastReceivedTransform.find(transform.EntityID) != m_LastReceivedTransform.end()) { + m_NextTransform[transform.EntityID] = m_LastReceivedTransform[transform.EntityID]; + m_NextTransform[transform.EntityID].interpolationTime = time - SNAPSHOTINTERVAL; + sTransform = m_NextTransform[transform.EntityID]; + m_LastReceivedTransform.erase(transform.EntityID); + } else { + m_NextTransform.erase(transform.EntityID); + } + } if (transform.Info.Name == "Transform") { // Position glm::vec3 nextPosition = sTransform.Position; @@ -38,23 +49,10 @@ void InterpolationSystem::UpdateComponent(World * world, EntityWrapper& entity, glm::vec3 nextScale = sTransform.Scale; glm::vec3 currentScale = static_cast(transform["Scale"]); (glm::vec3&)transform["Scale"] += vectorInterpolation(currentScale, nextScale, sTransform.interpolationTime); - int testVar = 0; - if (glm::isnan(resize.r) || glm::isnan(resize.g) || glm::isnan(resize.b)) { - //(glm::vec3&)transform["Scale"] = currentScale; - return; - } - += resize; } } } -//glm::vec3 InterpolationSystem::vectorInterpolation(glm::vec3 prev, glm::vec3 next, double currentTime) -//{ -// glm::vec3 difference = next - prev; -// glm::vec3 position = difference / SNAPSHOTINTERVAL * static_cast(currentTime); -// return position; -//} - bool InterpolationSystem::OnInterpolate(const Events::Interpolate & e) { Transform transform; @@ -68,7 +66,12 @@ bool InterpolationSystem::OnInterpolate(const Events::Interpolate & e) offset += sizeof(glm::vec3); memcpy(&transform.Scale, e.DataArray.get() + offset, sizeof(glm::vec3)); transform.interpolationTime = 0.0f; - m_InterpolationPoints[e.Entity] = transform; + + if (m_NextTransform.find(e.Entity) != m_NextTransform.end()) { // Did exist + m_LastReceivedTransform[e.Entity] = transform; + } else { // Did not + m_NextTransform[e.Entity] = transform; + } // Check if queue already exists //if (m_InterpolationPoints.find(e.Entity) != m_InterpolationPoints.end()) { // Did exist, push to queue // m_InterpolationPoints[e.Entity].push(transform); From 017ad96bbe3d92c5b5da4a8642c27604cbcff35d Mon Sep 17 00:00:00 2001 From: William Moberg Date: Tue, 19 Jan 2016 15:20:29 +0100 Subject: [PATCH 20/27] Fixed some errors in Tests. --- src/Tests/CollisionTest.cpp | 4 ++-- src/Tests/OctTreeTest.cpp | 30 ++++++++++++++++++++---------- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/Tests/CollisionTest.cpp b/src/Tests/CollisionTest.cpp index 9f400330..78d5bdb7 100644 --- a/src/Tests/CollisionTest.cpp +++ b/src/Tests/CollisionTest.cpp @@ -205,9 +205,9 @@ BOOST_AUTO_TEST_CASE(octTest) { glm::vec3 mini = glm::vec3(-1, -1, -1); glm::vec3 maxi = glm::vec3(1, 1, 1); - Octree tree(AABB(mini, maxi), 2); + Octree tree(AABB(mini, maxi), 2); tree.AddDynamicObject(AABB(mini, -0.9f*maxi)); - Octree::Output data; + OctSpace::Output data; glm::vec3 origin = 3.0f * mini; bool rayIntersected = tree.RayCollides(Ray(origin , mini - origin), data); BOOST_CHECK(rayIntersected); diff --git a/src/Tests/OctTreeTest.cpp b/src/Tests/OctTreeTest.cpp index 3a130354..2fdfe681 100644 --- a/src/Tests/OctTreeTest.cpp +++ b/src/Tests/OctTreeTest.cpp @@ -13,12 +13,12 @@ BOOST_AUTO_TEST_CASE(octSameRegionTest) { glm::vec3 mini = glm::vec3(-1, -1, -1); glm::vec3 maxi = glm::vec3(1, 1, 1); - Octree tree(AABB(mini, maxi), 2); + Octree tree(AABB(mini, maxi), 2); AABB firstQuadrant(mini, 0.8f*mini); tree.AddStaticObject(firstQuadrant); AABB testBox(0.9f*mini, 0.8f*mini); std::vector region; - tree.BoxesInSameRegion(testBox, region); + tree.ObjectsInSameRegion(testBox, region); BOOST_REQUIRE(region.size() == 1); AABB& box = region[0]; BOOST_CHECK_CLOSE_FRACTION(box.Origin().x, firstQuadrant.Origin().x, 0.00001f); @@ -40,7 +40,7 @@ const int NUM_FUNCTION_LOOPS = 25; const int TESTS = 0; //10 template -void RegionTest(Tree& tree) +void RegionTestOld(Tree& tree) { AABB aabb; aabb.CreateFromCenter(glm::vec3(rand() % LEVEL_BOUNDS, rand() % LEVEL_BOUNDS, rand() % LEVEL_BOUNDS), @@ -50,9 +50,19 @@ void RegionTest(Tree& tree) } template +void RegionTest(Tree& tree) +{ + AABB aabb; + aabb.CreateFromCenter(glm::vec3(rand() % LEVEL_BOUNDS, rand() % LEVEL_BOUNDS, rand() % LEVEL_BOUNDS), + glm::vec3(rand() % MAXSIZE, rand() % MAXSIZE, rand() % MAXSIZE)); + std::vector outVec; + tree.ObjectsInSameRegion(aabb, outVec); +} + +template void RayTest(Tree& tree) { - Tree::Output data; + Output data; glm::vec3 rayStart = glm::vec3(rand() % LEVEL_BOUNDS, rand() % LEVEL_BOUNDS, rand() % LEVEL_BOUNDS); glm::vec3 rayEnd = glm::vec3(rand() % LEVEL_BOUNDS, rand() % LEVEL_BOUNDS, rand() % LEVEL_BOUNDS); tree.RayCollides({ rayStart , glm::normalize(rayEnd - rayStart) }, data); @@ -111,13 +121,13 @@ void TestLoop(TestFunction xTest) BOOST_AUTO_TEST_CASE(octRegionPerfTestWithDuplicates) { - TestLoop(RegionTest); + TestLoop(RegionTestOld); BOOST_CHECK(true); } BOOST_AUTO_TEST_CASE(octRegionPerfTestNoDuplicates) { - TestLoop(RegionTest); + TestLoop>(RegionTest>); BOOST_CHECK(true); } @@ -129,19 +139,19 @@ BOOST_AUTO_TEST_CASE(octBoxPerfTestWithDuplicates) BOOST_AUTO_TEST_CASE(octBoxPerfTestNoDuplicates) { - TestLoop(BoxTest); + TestLoop>(BoxTest>); BOOST_CHECK(true); } BOOST_AUTO_TEST_CASE(octRayPerfTestWithDuplicates) { - TestLoop(RayTest); + TestLoop(RayTest); BOOST_CHECK(true); } BOOST_AUTO_TEST_CASE(octRayPerfTestNoDuplicates) { - TestLoop(RayTest); + TestLoop>(RayTest, OctSpace::Output>); BOOST_CHECK(true); } @@ -153,7 +163,7 @@ BOOST_AUTO_TEST_CASE(octNopPerfTestWithDuplicates) BOOST_AUTO_TEST_CASE(octNopPerfTestNoDuplicates) { - TestLoop(NopTest); + TestLoop>(NopTest>); BOOST_CHECK(true); } From d1b6fb125916baf9bc20ae1656a7fdc269069159 Mon Sep 17 00:00:00 2001 From: William Moberg Date: Tue, 19 Jan 2016 16:59:02 +0100 Subject: [PATCH 21/27] Tiny logic alteration so we don't get false warnings in debug. --- src/Engine/Collision/TriggerSystem.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Engine/Collision/TriggerSystem.cpp b/src/Engine/Collision/TriggerSystem.cpp index 0ff4345e..b398b091 100644 --- a/src/Engine/Collision/TriggerSystem.cpp +++ b/src/Engine/Collision/TriggerSystem.cpp @@ -34,9 +34,12 @@ void TriggerSystem::UpdateComponent(World* world, EntityWrapper& entity, Compone throwLeaveIfWasInTrigger(m_EntitiesCompletelyInTrigger[tId], pId, tId); } else { //Entity is at least touching the trigger. - AABB completelyInsideBox = AABB::FromOriginSize((*triggerBox).Origin(), (*triggerBox).Size() - 2.0f * (*playerBox).Size()); - if (Collision::AABBVsAABB(completelyInsideBox, *playerBox) && - glm::all(glm::greaterThan((*triggerBox).Size(), (*playerBox).Size()))) { + AABB completelyInsideBox; + bool playerFitsInTrigger = glm::all(glm::greaterThan((*triggerBox).Size(), (*playerBox).Size())); + if (playerFitsInTrigger) { + completelyInsideBox = AABB::FromOriginSize((*triggerBox).Origin(), (*triggerBox).Size() - 2.0f * (*playerBox).Size()); + } + if (playerFitsInTrigger && Collision::AABBVsAABB(completelyInsideBox, *playerBox)) { //Entity is completely inside the trigger. //If it was only touching before, it is erased. m_EntitiesTouchingTrigger[tId].erase(pId); From f52cddb44592d64dabfa0133efbebb777f5594e9 Mon Sep 17 00:00:00 2001 From: Jocke Date: Wed, 20 Jan 2016 13:43:11 +0100 Subject: [PATCH 22/27] 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); From e9a576341e4a8f3a1d8e203b4192b3b99198c970 Mon Sep 17 00:00:00 2001 From: Jocke Date: Wed, 20 Jan 2016 14:31:50 +0100 Subject: [PATCH 23/27] Started on server disconnect logic. --- src/Engine/Network/Server.cpp | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/Engine/Network/Server.cpp b/src/Engine/Network/Server.cpp index ce3a735c..c598f1f1 100644 --- a/src/Engine/Network/Server.cpp +++ b/src/Engine/Network/Server.cpp @@ -189,7 +189,7 @@ 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_PlayerDefinitions[i].StopTime / - static_cast(CLOCKS_PER_SEC); + static_cast(CLOCKS_PER_SEC); if (startPing > stopPing + timeOutTimeMs) { LOG_INFO("Player %i timed out!", i); disconnect(i); @@ -201,7 +201,7 @@ void Server::checkForTimeOuts() void Server::disconnect(int i) { //broadcast("A player disconnected"); - LOG_INFO("Player %i disconnected/timed out", i); + LOG_INFO("Player %s disconnected/timed out", m_PlayerDefinitions[i].Name.c_str()); // Remove enteties and stuff m_PlayerDefinitions[i].Endpoint = boost::asio::ip::udp::endpoint(); @@ -216,7 +216,7 @@ void Server::parseOnInputCommand(Packet& packet) // Check which player it was who sent the message for (int i = 0; i < MAXCONNECTIONS; i++) { // if the player is connected set playerID to the correct PlayerID - if (m_PlayerDefinitions[i].Endpoint.address() == m_ReceiverEndpoint.address() + if (m_PlayerDefinitions[i].Endpoint.address() == m_ReceiverEndpoint.address() && m_PlayerDefinitions[i].Endpoint.port() == m_ReceiverEndpoint.port()) { playerID = i; break; @@ -248,13 +248,11 @@ void Server::parseConnect(Packet& packet) { LOG_INFO("Parsing connections"); // Check if player is already connected - for (int i = 0; i < MAXCONNECTIONS; i++) { - if (m_PlayerDefinitions[i].Endpoint.address() == m_ReceiverEndpoint.address() && - m_PlayerDefinitions[i].Endpoint.port() == m_ReceiverEndpoint.port()) { - return; - } + if (GetPlayerIDFromEndpoint(m_ReceiverEndpoint) != -1) { + return; } + // Find an empty spot to put the player in for (int i = 0; i < MAXCONNECTIONS; i++) { if (m_PlayerDefinitions[i].Endpoint.address() == boost::asio::ip::address()) { // Create new player @@ -298,13 +296,13 @@ void Server::parseClientPing() { LOG_INFO("%i: Parsing ping", m_PacketID); int playerID = GetPlayerIDFromEndpoint(m_ReceiverEndpoint); - if (playerID == -1) { + if (playerID == -1) { return; } // Return ping Packet packet(MessageType::ClientPing, m_PlayerDefinitions[playerID].PacketID); packet.WriteString("Ping received"); - send(packet); + send(packet); } void Server::parseServerPing() @@ -351,6 +349,6 @@ int Server::GetPlayerIDFromEndpoint(boost::asio::ip::udp::endpoint endpoint) 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); + //LOG_DEBUG("Server::OnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID); return true; } From 7e7ca7edcf79529c6afaed534eb544f493b782f2 Mon Sep 17 00:00:00 2001 From: stiffly Date: Wed, 20 Jan 2016 14:32:04 +0100 Subject: [PATCH 24/27] Listening to "DisconnectFromServer" --- src/Engine/Network/Client.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/Engine/Network/Client.cpp b/src/Engine/Network/Client.cpp index ae71d0ae..83e0d886 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: @@ -240,8 +238,7 @@ void Client::connect() void Client::disconnect() { - Packet packet(MessageType::Connect, m_SendPacketID); - packet.WriteString("+Disconnect"); + Packet packet(MessageType::Disconnect, m_SendPacketID); send(packet); } @@ -256,9 +253,16 @@ void Client::ping() bool Client::OnInputCommand(const Events::InputCommand & e) { if (e.Command == "ConnectToServer") { // Connect for now - connect(); + if (e.Value > 0) { + connect(); + } //LOG_DEBUG("Client::OnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID); return true; + } else if (e.Command == "DisconnectFromServer") { + if (e.Value > 0) { + disconnect(); + } + return true; } else { m_InputCommandBuffer.push_back(e); //LOG_DEBUG("Client::OnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID); @@ -282,7 +286,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); } } From 25d2aa34644b50d9ae23169e75616eba06523267 Mon Sep 17 00:00:00 2001 From: Jocke Date: Wed, 20 Jan 2016 16:27:23 +0100 Subject: [PATCH 25/27] =?UTF-8?q?"Supporting"=20spectators.=20Using=20a=20?= =?UTF-8?q?vector=20for=20connected=20units=20as=20we=20do=20not=20interpr?= =?UTF-8?q?et=20as=20players.=20=E2=80=9C=E2=80=9C=E2=80=9D=CC=BF=20=CC=BF?= =?UTF-8?q?=20=CC=BF=20=CC=BF=20=CC=BF=E2=80=99=CC=BF=E2=80=99=CC=B5=CD=87?= =?UTF-8?q?=CC=BF=CC=BF=D0=B7=3D(=E2=80=A2=CC=AA=E2=97=8F)=3D=CE=B5/=CC=B5?= =?UTF-8?q?=CD=87=CC=BF=CC=BF/=CC=BF=20=CC=BF=20=CC=BF=20=CC=BF=20=CC=BF?= =?UTF-8?q?=E2=80=99=E2=80=9C=E2=80=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/Engine/Network/Server.h | 3 +- src/Engine/Network/Client.cpp | 5 +- src/Engine/Network/Server.cpp | 90 ++++++++++++++++----------------- 3 files changed, 46 insertions(+), 52 deletions(-) diff --git a/include/Engine/Network/Server.h b/include/Engine/Network/Server.h index 3b871e43..ec1a173a 100644 --- a/include/Engine/Network/Server.h +++ b/include/Engine/Network/Server.h @@ -27,9 +27,10 @@ private: boost::asio::ip::udp::endpoint m_ReceiverEndpoint; boost::asio::io_service m_IOService; boost::asio::ip::udp::socket m_Socket; - PlayerDefinition m_PlayerDefinitions[MAXCONNECTIONS]; // Sending messages to client logic + PlayerDefinition m_PlayerDefinitions[MAXCONNECTIONS]; + std::vector m_ConnectedUsers; char readBuffer[INPUTSIZE] = { 0 }; int bytesRead = 0; // time for previouse message diff --git a/src/Engine/Network/Client.cpp b/src/Engine/Network/Client.cpp index 83e0d886..b6dea8e3 100644 --- a/src/Engine/Network/Client.cpp +++ b/src/Engine/Network/Client.cpp @@ -85,11 +85,8 @@ void Client::parseMessageType(Packet& packet) void Client::parseConnect(Packet& packet) { - // Set your own player id - m_PlayerID = packet.ReadPrimitive(); - m_ServerEntityID = packet.ReadPrimitive(); // Map ServerEntityID and your PlayerID - LOG_INFO("%i: I am player: %i", m_PacketID, m_PlayerID); + LOG_INFO("I be connected PogChamp"); } void Client::parsePlayerConnected(Packet & packet) diff --git a/src/Engine/Network/Server.cpp b/src/Engine/Network/Server.cpp index c598f1f1..4a2dcf96 100644 --- a/src/Engine/Network/Server.cpp +++ b/src/Engine/Network/Server.cpp @@ -8,7 +8,6 @@ Server::~Server() } - void Server::Start(World* world, EventBroker* eventBroker) { m_World = world; @@ -104,11 +103,11 @@ int Server::receive(char * data, size_t length) return length; } -void Server::send(Packet& packet, int playerID) +void Server::send(Packet& packet, int userID) { int bytesSent = m_Socket.send_to( boost::asio::buffer(packet.Data(), packet.Size()), - m_PlayerDefinitions[playerID].Endpoint, + m_ConnectedUsers[userID].Endpoint, 0); } @@ -124,9 +123,9 @@ void Server::send(Packet & packet) 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); + for (int i = 0; i < m_ConnectedUsers.size(); i++) { + if (m_ConnectedUsers[i].Endpoint.address() != boost::asio::ip::address()) { + packet.ChangePacketID(m_ConnectedUsers[i].PacketID); send(packet, i); } } @@ -165,10 +164,10 @@ void Server::sendSnapshot() 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_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); + for (int i = 0; i < m_ConnectedUsers.size(); i++) { + if (m_ConnectedUsers[i].Endpoint.address() != boost::asio::ip::address()) { + int ping = 1000 * (m_ConnectedUsers[i].StopTime - m_StartPingTime) / static_cast(CLOCKS_PER_SEC); + LOG_INFO("Last packetID received %i: User %i's ping: %i", m_ConnectedUsers[i].PacketID, i, ping); } } // Create ping message @@ -186,12 +185,12 @@ void Server::checkForTimeOuts() int startPing = 1000 * m_StartPingTime / static_cast(CLOCKS_PER_SEC); - for (size_t i = 0; i < MAXCONNECTIONS; i++) { - if (m_PlayerDefinitions[i].Endpoint.address() != boost::asio::ip::address()) { - int stopPing = 1000 * m_PlayerDefinitions[i].StopTime / + for (int i = 0; i < m_ConnectedUsers.size(); i++) { + if (m_ConnectedUsers[i].Endpoint.address() != boost::asio::ip::address()) { + int stopPing = 1000 * m_ConnectedUsers[i].StopTime / static_cast(CLOCKS_PER_SEC); if (startPing > stopPing + timeOutTimeMs) { - LOG_INFO("Player %i timed out!", i); + LOG_INFO("User %i timed out!", i); disconnect(i); } } @@ -201,13 +200,13 @@ void Server::checkForTimeOuts() void Server::disconnect(int i) { //broadcast("A player disconnected"); - LOG_INFO("Player %s disconnected/timed out", m_PlayerDefinitions[i].Name.c_str()); - - // Remove enteties and stuff + LOG_INFO("User %s disconnected/timed out", m_PlayerDefinitions[i].Name.c_str()); + // Remove enteties and stuff (When we can remove entity, remove it and tell clients to remove the copy they have) m_PlayerDefinitions[i].Endpoint = boost::asio::ip::udp::endpoint(); m_PlayerDefinitions[i].EntityID = -1; m_PlayerDefinitions[i].Name = ""; m_PlayerDefinitions[i].PacketID = 0; + m_ConnectedUsers.erase(m_ConnectedUsers.begin() + i); } void Server::parseOnInputCommand(Packet& packet) @@ -251,41 +250,38 @@ void Server::parseConnect(Packet& packet) if (GetPlayerIDFromEndpoint(m_ReceiverEndpoint) != -1) { return; } - - // Find an empty spot to put the player in - for (int i = 0; i < MAXCONNECTIONS; i++) { - if (m_PlayerDefinitions[i].Endpoint.address() == boost::asio::ip::address()) { - // Create new player - m_PlayerDefinitions[i].EntityID = createPlayer(); - m_PlayerDefinitions[i].Endpoint = m_ReceiverEndpoint; - m_PlayerDefinitions[i].Name = packet.ReadString(); - m_PlayerDefinitions[i].PacketID = 0; - - 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_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); - broadcast(notificationPacket); - - break; + for (int i = 0; i < m_ConnectedUsers.size(); i++) { + if (m_ConnectedUsers[i].Endpoint.address() == m_ReceiverEndpoint.address() && + m_ConnectedUsers[i].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_ConnectedUsers.push_back(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, m_ConnectedUsers[m_ConnectedUsers.size() - 1].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 (int i = 0; i < MAXCONNECTIONS; i++) { - if (m_PlayerDefinitions[i].Endpoint.address() == m_ReceiverEndpoint.address()) { + for (int i = 0; i < m_ConnectedUsers.size(); i++) { + if (m_ConnectedUsers[i].Endpoint.address() == m_ReceiverEndpoint.address()) { disconnect(i); break; } @@ -307,9 +303,9 @@ void Server::parseClientPing() void Server::parseServerPing() { - for (int i = 0; i < MAXCONNECTIONS; i++) { - if (m_PlayerDefinitions[i].Endpoint.address() == m_ReceiverEndpoint.address()) { - m_PlayerDefinitions[i].StopTime = std::clock(); + for (int i = 0; i < m_ConnectedUsers.size(); i++) { + if (m_ConnectedUsers[i].Endpoint.address() == m_ReceiverEndpoint.address()) { + m_ConnectedUsers[i].StopTime = std::clock(); break; } } From 3376f4a16ee10fbe5ea6d11b44d12a086ea061bf Mon Sep 17 00:00:00 2001 From: stiffly Date: Wed, 20 Jan 2016 16:27:53 +0100 Subject: [PATCH 26/27] Added server has timed out logic to client. (>'')> --- include/Engine/Network/Client.h | 5 ++-- include/Engine/Network/Network.h | 1 + include/Engine/Network/Server.h | 2 +- src/Engine/Network/Client.cpp | 40 +++++++++++++++++++++----------- src/Engine/Network/Server.cpp | 3 +-- 5 files changed, 32 insertions(+), 19 deletions(-) diff --git a/include/Engine/Network/Client.h b/include/Engine/Network/Client.h index 73f0eb50..511ce5f7 100644 --- a/include/Engine/Network/Client.h +++ b/include/Engine/Network/Client.h @@ -48,6 +48,7 @@ private: std::string m_PlayerName; int m_PlayerID = -1; EntityID m_ServerEntityID = std::numeric_limits::max(); + bool m_IsConnected = false; // Server Client Lookup map // Assumes that root node for client and server is EntityID 0. @@ -71,14 +72,14 @@ private: void ping(); void parseMessageType(Packet& packet); void updateFields(Packet& packet, const ComponentInfo& componentInfo, const EntityID& entityID, const std::string& componentType); - void parseConnect(Packet& packet); + void parseConnect(Packet& packet); void parsePlayerConnected(Packet& packet); void parsePing(); void parseServerPing(); void InterpolateFields(Packet & packet, const ComponentInfo & componentInfo, const EntityID & entityID, const std::string & componentType); void parseSnapshot(Packet& packet); void identifyPacketLoss(); - bool isConnected(); + bool hasServerTimedOut(); EntityID createPlayer(); void sendInputCommands(); // Mapping Logic diff --git a/include/Engine/Network/Network.h b/include/Engine/Network/Network.h index cb86b941..1464a96f 100644 --- a/include/Engine/Network/Network.h +++ b/include/Engine/Network/Network.h @@ -7,6 +7,7 @@ #define MAXCONNECTIONS 8 #define INPUTSIZE 4097 +#define TIMEOUTMS 15000 class Network { diff --git a/include/Engine/Network/Server.h b/include/Engine/Network/Server.h index 3b871e43..2f21816a 100644 --- a/include/Engine/Network/Server.h +++ b/include/Engine/Network/Server.h @@ -11,7 +11,7 @@ #include "Network/PlayerDefinition.h" #include "Core/World.h" #include "Core/EventBroker.h" -#include "Network/Network.h" +#include "../Network/Network.h" #include "Input/EInputCommand.h" #include "Core/EPlayerDamage.h" diff --git a/src/Engine/Network/Client.cpp b/src/Engine/Network/Client.cpp index 83e0d886..a5c34963 100644 --- a/src/Engine/Network/Client.cpp +++ b/src/Engine/Network/Client.cpp @@ -35,6 +35,9 @@ void Client::Update() { m_EventBroker->Process(); readFromServer(); + if (m_IsConnected) { + hasServerTimedOut(); + } } void Client::readFromServer() @@ -86,10 +89,8 @@ void Client::parseMessageType(Packet& packet) void Client::parseConnect(Packet& packet) { // Set your own player id - m_PlayerID = packet.ReadPrimitive(); - m_ServerEntityID = packet.ReadPrimitive(); // Map ServerEntityID and your PlayerID - LOG_INFO("%i: I am player: %i", m_PacketID, m_PlayerID); + LOG_INFO("I are connected PogChamp"); } void Client::parsePlayerConnected(Packet & packet) @@ -100,12 +101,18 @@ void Client::parsePlayerConnected(Packet & packet) void Client::parsePing() { - m_DurationOfPingTime = 1000 * (std::clock() - m_StartPingTime) / static_cast(CLOCKS_PER_SEC); - LOG_INFO("%i: response time with ctime(ms): %f", m_PacketID, m_DurationOfPingTime); + } void Client::parseServerPing() { + // Might miss connect message so set it here instead. + m_IsConnected = true; + // Time since last ping was received + m_DurationOfPingTime = 1000 * (std::clock() - m_StartPingTime) / static_cast(CLOCKS_PER_SEC); + LOG_INFO("%i: response time with ctime(ms): %f", m_PacketID, m_DurationOfPingTime); + m_StartPingTime = std::clock(); + Packet packet(MessageType::ServerPing, m_SendPacketID); packet.WriteString("Ping recieved"); send(packet); @@ -238,16 +245,18 @@ void Client::connect() void Client::disconnect() { + m_PreviousPacketID = 0; + m_PacketID = 0; Packet packet(MessageType::Disconnect, m_SendPacketID); send(packet); } void Client::ping() { - Packet packet(MessageType::Connect, m_SendPacketID); - packet.WriteString("Ping"); - m_StartPingTime = std::clock(); - send(packet); + //Packet packet(MessageType::Connect, m_SendPacketID); + //packet.WriteString("Ping"); + //m_StartPingTime = std::clock(); + //send(packet); } bool Client::OnInputCommand(const Events::InputCommand & e) @@ -290,12 +299,15 @@ void Client::identifyPacketLoss() } } -bool Client::isConnected() +bool Client::hasServerTimedOut() { - if (m_PlayerID != -1) { - if (m_PlayerDefinitions[m_PlayerID].EntityID != -1) { - return true; - } + // Time in ms + float timeSincePing = 1000 * (std::clock() - m_StartPingTime) / static_cast(CLOCKS_PER_SEC); + if (timeSincePing > TIMEOUTMS) { + // Clear everything and go to menu. + LOG_INFO("Server has timed out, returning to menu, Beep Boop."); + m_IsConnected = false; + return true; } return false; } diff --git a/src/Engine/Network/Server.cpp b/src/Engine/Network/Server.cpp index c598f1f1..ec593cb7 100644 --- a/src/Engine/Network/Server.cpp +++ b/src/Engine/Network/Server.cpp @@ -182,7 +182,6 @@ void Server::sendPing() void Server::checkForTimeOuts() { - int timeOutTimeMs = 5000; int startPing = 1000 * m_StartPingTime / static_cast(CLOCKS_PER_SEC); @@ -190,7 +189,7 @@ void Server::checkForTimeOuts() if (m_PlayerDefinitions[i].Endpoint.address() != boost::asio::ip::address()) { int stopPing = 1000 * m_PlayerDefinitions[i].StopTime / static_cast(CLOCKS_PER_SEC); - if (startPing > stopPing + timeOutTimeMs) { + if (startPing > stopPing + TIMEOUTMS) { LOG_INFO("Player %i timed out!", i); disconnect(i); } From cd6725317325f3616e90a0bea1325160a4a52587 Mon Sep 17 00:00:00 2001 From: Jocke Date: Wed, 20 Jan 2016 17:41:16 +0100 Subject: [PATCH 27/27] Added logic to go from spectator to player. --- include/Engine/Network/Client.h | 1 + include/Engine/Network/MessageType.h | 3 +- include/Engine/Network/Server.h | 2 +- src/Engine/Network/Client.cpp | 12 ++++++- src/Engine/Network/Server.cpp | 52 +++++++++++++++++++++------- 5 files changed, 55 insertions(+), 15 deletions(-) diff --git a/include/Engine/Network/Client.h b/include/Engine/Network/Client.h index 511ce5f7..96511baa 100644 --- a/include/Engine/Network/Client.h +++ b/include/Engine/Network/Client.h @@ -82,6 +82,7 @@ private: bool hasServerTimedOut(); EntityID createPlayer(); void sendInputCommands(); + void becomePlayer(); // Mapping Logic // Returns if local EntityID exist in map bool clientServerMapsHasEntity(EntityID clientEntityID); diff --git a/include/Engine/Network/MessageType.h b/include/Engine/Network/MessageType.h index ba9684d9..f0026190 100644 --- a/include/Engine/Network/MessageType.h +++ b/include/Engine/Network/MessageType.h @@ -13,7 +13,8 @@ enum class MessageType Snapshot, OnInputCommand, OnPlayerDamage, - PlayerConnected + PlayerConnected, + BecomePlayer }; #endif diff --git a/include/Engine/Network/Server.h b/include/Engine/Network/Server.h index e4d11334..8aabceba 100644 --- a/include/Engine/Network/Server.h +++ b/include/Engine/Network/Server.h @@ -71,7 +71,7 @@ private: void parseClientPing(); void parseServerPing(); void identifyPacketLoss(); - EntityID createPlayer(); + void createPlayer(); int 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 5aec3145..8eee335e 100644 --- a/src/Engine/Network/Client.cpp +++ b/src/Engine/Network/Client.cpp @@ -35,7 +35,7 @@ void Client::Update() { m_EventBroker->Process(); readFromServer(); - if (m_IsConnected) { + if (m_IsConnected) { hasServerTimedOut(); } } @@ -271,6 +271,10 @@ bool Client::OnInputCommand(const Events::InputCommand & e) disconnect(); } return true; + } else if (e.Command == "SwitchToPlayer") { + if (e.Value > 0) { + becomePlayer(); + } } else { m_InputCommandBuffer.push_back(e); //LOG_DEBUG("Client::OnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID); @@ -334,6 +338,12 @@ void Client::sendInputCommands() } } +void Client::becomePlayer() +{ + Packet packet = Packet(MessageType::BecomePlayer, m_SendPacketID); + send(packet); +} + bool Client::clientServerMapsHasEntity(EntityID clientEntityID) { return m_ClientIDToServerID.find(clientEntityID) != m_ClientIDToServerID.end(); diff --git a/src/Engine/Network/Server.cpp b/src/Engine/Network/Server.cpp index 71ca7252..8a194c0e 100644 --- a/src/Engine/Network/Server.cpp +++ b/src/Engine/Network/Server.cpp @@ -89,6 +89,9 @@ void Server::parseMessageType(Packet& packet) case MessageType::OnPlayerDamage: parseOnPlayerDamage(packet); break; + case MessageType::BecomePlayer: + createPlayer(); + break; default: break; } @@ -123,8 +126,8 @@ void Server::send(Packet & packet) void Server::broadcast(Packet& packet) { - for (int i = 0; i < m_ConnectedUsers.size(); i++) { - if (m_ConnectedUsers[i].Endpoint.address() != boost::asio::ip::address()) { + for (int i = 0; i < m_ConnectedUsers.size(); i++) { + if (m_ConnectedUsers[i].Endpoint.address() != boost::asio::ip::address()) { packet.ChangePacketID(m_ConnectedUsers[i].PacketID); send(packet, i); } @@ -167,7 +170,7 @@ void Server::sendPing() for (int i = 0; i < m_ConnectedUsers.size(); i++) { if (m_ConnectedUsers[i].Endpoint.address() != boost::asio::ip::address()) { int ping = 1000 * (m_ConnectedUsers[i].StopTime - m_StartPingTime) / static_cast(CLOCKS_PER_SEC); - LOG_INFO("Last packetID received %i: User %i's ping: %i", m_ConnectedUsers[i].PacketID, i, ping); + LOG_INFO("Last packetID received %i: User %i's ping: %i", m_ConnectedUsers[i].PacketID, i, std::abs(ping)); } } // Create ping message @@ -319,16 +322,41 @@ void Server::identifyPacketLoss() } } -EntityID Server::createPlayer() +void Server::createPlayer() { - EntityID entityID = m_World->CreateEntity(); - ComponentWrapper transform = m_World->AttachComponent(entityID, "Transform"); - transform["Position"] = glm::vec3(-1.5f, 0.f, 0.f); - ComponentWrapper model = m_World->AttachComponent(entityID, "Model"); - model["Resource"] = "Models/Core/UnitSphere.obj"; - model["Color"] = glm::vec4(rand()%255 / 255.f, rand()%255 / 255.f, rand() %255 / 255.f, 1.f); - ComponentWrapper player = m_World->AttachComponent(entityID, "Player"); - return entityID; + if (GetPlayerIDFromEndpoint(m_ReceiverEndpoint) != -1) { + // Already connected as player + LOG_WARNING("Already connected!"); + return; + } + int userIndex; + for (userIndex = 0; userIndex < m_ConnectedUsers.size(); userIndex++) { + if (m_ConnectedUsers[userIndex].Endpoint.address() == m_ReceiverEndpoint.address() && + m_ConnectedUsers[userIndex].Endpoint.port() == m_ReceiverEndpoint.port()) { + // Found user + break; + } + } + if (userIndex == m_ConnectedUsers.size()) { + LOG_WARNING("Not a recognized user!"); + return; + } + for (int playerIndex = 0; playerIndex < MAXCONNECTIONS; playerIndex++) { + if (m_PlayerDefinitions[playerIndex].Endpoint.address() == boost::asio::ip::address()) { + m_PlayerDefinitions[playerIndex] = m_ConnectedUsers[userIndex]; + EntityID entityID = m_World->CreateEntity(); + ComponentWrapper transform = m_World->AttachComponent(entityID, "Transform"); + transform["Position"] = glm::vec3(-1.5f, 0.f, 0.f); + ComponentWrapper model = m_World->AttachComponent(entityID, "Model"); + model["Resource"] = "Models/Core/UnitSphere.obj"; + model["Color"] = glm::vec4(rand()%255 / 255.f, rand()%255 / 255.f, rand() %255 / 255.f, 1.f); + ComponentWrapper player = m_World->AttachComponent(entityID, "Player"); + m_PlayerDefinitions[playerIndex].EntityID = entityID; + return; + } + } + LOG_WARNING("Server is full!"); + } int Server::GetPlayerIDFromEndpoint(boost::asio::ip::udp::endpoint endpoint)