diff --git a/include/Engine/Network/Client.h b/include/Engine/Network/Client.h index a5488210..96511baa 100644 --- a/include/Engine/Network/Client.h +++ b/include/Engine/Network/Client.h @@ -3,9 +3,12 @@ #include #include +#include +#include #include #include +#include #include "Network/Network.h" #include "Network/MessageType.h" @@ -15,6 +18,8 @@ #include "Core/EventBroker.h" #include "Core/ConfigFile.h" #include "Input/EInputCommand.h" +#include "Core/EPlayerDamage.h" +#include "Network/EInterpolate.h" class Client : public Network { @@ -32,8 +37,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; @@ -44,40 +47,55 @@ private: World* m_World; 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. + + // 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; + std::vector m_InputCommandBuffer; // Private member functions void readFromServer(); - void sendSnapshotToServer(); 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 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(); + void becomePlayer(); + // 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; EventRelay m_EInputCommand; - bool OnInputCommand(const Events::InputCommand &e); + bool OnInputCommand(const Events::InputCommand& e); + EventRelay m_EPlayeDamage; + bool OnPlayerDamage(const Events::PlayerDamage& e); }; #endif diff --git a/include/Engine/Network/EInterpolate.h b/include/Engine/Network/EInterpolate.h new file mode 100644 index 00000000..93bf1a5c --- /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/Engine/Network/MessageType.h b/include/Engine/Network/MessageType.h index 8d09c7ee..f0026190 100644 --- a/include/Engine/Network/MessageType.h +++ b/include/Engine/Network/MessageType.h @@ -11,7 +11,10 @@ enum class MessageType ServerPing, Message, Snapshot, - Event, + OnInputCommand, + OnPlayerDamage, + PlayerConnected, + BecomePlayer }; #endif 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/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 893eed0b..8aabceba 100644 --- a/include/Engine/Network/Server.h +++ b/include/Engine/Network/Server.h @@ -11,7 +11,9 @@ #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" class Server : public Network { @@ -25,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 @@ -41,40 +44,38 @@ private: //Timers std::clock_t m_StartPingTime; - std::clock_t m_StopTimes[8]; // 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; - 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); 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(); void checkForTimeOuts(); void disconnect(int i); void parseMessageType(Packet& packet); - void parseEvent(Packet& packet); + void parseOnInputCommand(Packet& packet); + void parseOnPlayerDamage(Packet& packet); void parseConnect(Packet& packet); void parseDisconnect(); void parseClientPing(); void parseServerPing(); - void parseSnapshot(Packet& packet); void identifyPacketLoss(); - EntityID createPlayer(); + void createPlayer(); + int GetPlayerIDFromEndpoint(boost::asio::ip::udp::endpoint endpoint); + // Debug event + EventRelay m_EInputCommand; + bool OnInputCommand(const Events::InputCommand& e); }; #endif diff --git a/include/Game/Game.h b/include/Game/Game.h index d3a79328..6dd5e2cd 100644 --- a/include/Game/Game.h +++ b/include/Game/Game.h @@ -19,7 +19,7 @@ #include "Rendering/RenderSystem.h" #include "Core/EntityFileParser.h" #include "Core/Octree.h" - +#include "Systems/InterpolationSystem.h" // Network #include #include "Network/Network.h" diff --git a/include/Game/Systems/InterpolationSystem.h b/include/Game/Systems/InterpolationSystem.h new file mode 100644 index 00000000..fb7654b2 --- /dev/null +++ b/include/Game/Systems/InterpolationSystem.h @@ -0,0 +1,53 @@ +#ifndef Systems_InterpolationSystem_h__ +#define Systems_InterpolationSystem_h__ + +#include +#include +#include +#include +#include + +#include "Common.h" +#include "Core/System.h" +#include "Core/EventBroker.h" + +#include "Network/EInterpolate.h" + +#define SNAPSHOTINTERVAL 0.05f + +class InterpolationSystem : public PureSystem +{ + struct Transform + { + glm::vec3 Position; + glm::vec3 Scale; + glm::quat Orientation; + double interpolationTime; + }; +public: + InterpolationSystem(EventBroker* eventBroker) + : System(eventBroker) + , PureSystem("Transform") + { + EVENT_SUBSCRIBE_MEMBER(m_EInterpolate, &InterpolationSystem::OnInterpolate); + } + ~InterpolationSystem() { } + virtual void UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& transform, double dt) override; +private: + std::unordered_map m_NextTransform; + std::unordered_map m_LastReceivedTransform; + + //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); +}; + +#endif diff --git a/src/Engine/Network/Client.cpp b/src/Engine/Network/Client.cpp index b8849ed0..8eee335e 100644 --- a/src/Engine/Network/Client.cpp +++ b/src/Engine/Network/Client.cpp @@ -5,28 +5,27 @@ using namespace boost::asio::ip; Client::Client(ConfigFile* config) : m_Socket(m_IOService) { + // Asumes root node is EntityID 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() -{ -} +{ } void Client::Start(World* world, EventBroker* eventBroker) { - m_WasStarted = true; m_EventBroker = eventBroker; m_World = world; // 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"); @@ -34,7 +33,11 @@ void Client::Start(World* world, EventBroker* eventBroker) void Client::Update() { + m_EventBroker->Process(); readFromServer(); + if (m_IsConnected) { + hasServerTimedOut(); + } } void Client::readFromServer() @@ -46,58 +49,7 @@ 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::sendSnapshotToServer() -{ - // 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); - } + sendInputCommands(); } void Client::parseMessageType(Packet& packet) @@ -108,9 +60,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: @@ -129,9 +79,8 @@ void Client::parseMessageType(Packet& packet) break; case MessageType::Disconnect: break; - case MessageType::Event: - parseEventMessage(packet); - break; + case MessageType::PlayerConnected: + parsePlayerConnected(packet); default: break; } @@ -139,34 +88,52 @@ void Client::parseMessageType(Packet& packet) void Client::parseConnect(Packet& packet) { - m_PlayerID = packet.ReadPrimitive(); - LOG_INFO("%i: I am player: %i", m_PacketID, m_PlayerID); + // Map ServerEntityID and your PlayerID + LOG_INFO("I be connected PogChamp"); +} + +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); - 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); } -void Client::parseEventMessage(Packet& 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 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()); + 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.Stride]); + memcpy(eventData.get(), packet.ReadData(componentInfo.Stride), componentInfo.Stride); + //Send event to interpolat system + Events::Interpolate e; + e.Entity = entityID; + e.DataArray = eventData; + m_EventBroker->Publish(e); + } void Client::updateFields(Packet& packet, const ComponentInfo& componentInfo, const EntityID& entityID, const std::string& componentType) @@ -182,17 +149,27 @@ void Client::updateFields(Packet& packet, const ComponentInfo& componentInfo, co } } -// Field parse 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 (serverClientMapsHasEntity(receivedEntityID)) { + // Get the local EntityID + 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 - 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 @@ -202,11 +179,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(); + insertIntoServerClientMaps(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 +193,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 (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 { + // Create the new parent and add it to map + EntityID newParentEntityID = m_World->CreateEntity(); + insertIntoServerClientMaps(receivedParentEntityID, newParentEntityID); + // Set the newly created Entity as parent. + m_World->SetParent(m_ServerIDToClientID.at(receivedEntityID), newParentEntityID); + } + } } } @@ -228,9 +221,8 @@ 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; } @@ -252,76 +244,73 @@ void Client::connect() void Client::disconnect() { - Packet packet(MessageType::Connect, m_SendPacketID); - packet.WriteString("+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); -} - -void Client::moveMessageHead(char*& data, size_t& length, size_t stepSize) -{ - data += stepSize; - length -= stepSize; + //Packet packet(MessageType::Connect, m_SendPacketID); + //packet.WriteString("Ping"); + //m_StartPingTime = std::clock(); + //send(packet); } 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 - 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 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); + 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 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); } } -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; } @@ -335,3 +324,39 @@ EntityID Client::createPlayer() ComponentWrapper player = m_World->AttachComponent(entityID, "Player"); 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(); + } +} + +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(); +} + +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/Packet.cpp b/src/Engine/Network/Packet.cpp index 2b2c7938..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++; } @@ -40,7 +46,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 +56,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 +67,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 +78,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; @@ -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 07fed65b..8a194c0e 100644 --- a/src/Engine/Network/Server.cpp +++ b/src/Engine/Network/Server.cpp @@ -8,13 +8,14 @@ Server::~Server() } - 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(); + m_PlayerDefinitions[i].StopTime = std::clock(); } LOG_INFO("I am Server. BIP BOP\n"); } @@ -22,8 +23,10 @@ void Server::Start(World* world, EventBroker* eventBroker) void Server::Update() { readFromClients(); + m_EventBroker->Process(); } + void Server::readFromClients() { while (m_Socket.available()) { @@ -50,7 +53,7 @@ void Server::readFromClients() // Time out logic if (checkTimeOutInterval < (1000 * (currentTime - timOutTimer) / (double)CLOCKS_PER_SEC)) { - //checkForTimeOuts(); + checkForTimeOuts(); timOutTimer = currentTime; } } @@ -62,7 +65,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); @@ -76,13 +79,18 @@ void Server::parseMessageType(Packet& packet) case MessageType::Message: break; case MessageType::Snapshot: - parseSnapshot(packet); break; case MessageType::Disconnect: parseDisconnect(); break; - case MessageType::Event: - parseEvent(packet); + case MessageType::OnInputCommand: + parseOnInputCommand(packet); + break; + case MessageType::OnPlayerDamage: + parseOnPlayerDamage(packet); + break; + case MessageType::BecomePlayer: + createPlayer(); break; default: break; @@ -98,11 +106,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); } @@ -116,27 +124,11 @@ 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) { - if (m_PlayerDefinitions[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); } } @@ -148,14 +140,16 @@ void Server::sendSnapshot() // Should time this std::unordered_map worldComponentPools = m_World->GetComponentPools(); for (auto& it : worldComponentPools) { - Packet packet(MessageType::Snapshot, m_SendPacketID); - std::string componentType = it.first; + Packet packet(MessageType::Snapshot); 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") { @@ -173,14 +167,14 @@ 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_StopTimes[i] - m_StartPingTime) / static_cast(CLOCKS_PER_SEC); - LOG_INFO("Last packetID received %i: Player %i's ping: %i", m_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, std::abs(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(); @@ -190,16 +184,15 @@ void Server::sendPing() void Server::checkForTimeOuts() { - int timeOutTimeMs = 5000; 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_StopTimes[i] - / static_cast(CLOCKS_PER_SEC); - if (startPing > stopPing + timeOutTimeMs) { - LOG_INFO("Player %i timed out!", i); + 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 + TIMEOUTMS) { + LOG_INFO("User %i timed out!", i); disconnect(i); } } @@ -208,92 +201,89 @@ void Server::checkForTimeOuts() void Server::disconnect(int i) { - broadcast("A player disconnected"); - LOG_INFO("Player %i disconnected/timed out", i); - - // Remove enteties and stuff + //broadcast("A player disconnected"); + 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::parseEvent(Packet& packet) +void Server::parseOnInputCommand(Packet& packet) { - size_t i; - for (i = 0; i < MAXCONNECTIONS; i++) { - if (m_PlayerDefinitions[i].Endpoint.address() == m_ReceiverEndpoint.address()) { + 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 no player matches the address return. - if (i >= 8) - return; + 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_INFO("Server::parseOnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID); + } + } +} - 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; - } +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::parseOnPlayerDamage: Command is %s. Value is %f. PlayerID is %i.", e.DamageAmount, e.PlayerDamagedID, e.TypeOfDamage.c_str()); } void Server::parseConnect(Packet& packet) { LOG_INFO("Parsing connections"); // Check if player is already connected - for (int i = 0; i < MAXCONNECTIONS; i++) { - if (m_PlayerDefinitions[i].Endpoint.address() == m_ReceiverEndpoint.address()) { + if (GetPlayerIDFromEndpoint(m_ReceiverEndpoint) != -1) { + return; + } + 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()); - 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(); + // Send a message to the player that connected + Packet connnectPacket(MessageType::Connect, m_ConnectedUsers[m_ConnectedUsers.size() - 1].PacketID); + send(connnectPacket); - m_StopTimes[i] = 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()); - - Packet packet(MessageType::Connect, m_SendPacketID); - packet.WritePrimitive(i); // Player 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); - break; - } - } + // 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; } @@ -303,37 +293,26 @@ 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(); + 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; } } } -// 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 @@ -343,14 +322,56 @@ 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) +{ + 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_DEBUG("Server::OnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID); + return true; } diff --git a/src/Game/CMakeLists.txt b/src/Game/CMakeLists.txt index 4aaff273..157af23c 100644 --- a/src/Game/CMakeLists.txt +++ b/src/Game/CMakeLists.txt @@ -26,7 +26,9 @@ set(SOURCE_FILES ${SOURCE_FILES} "Game.cpp" ${SOURCE_FILES_Systems} - ${SOURCE_FILES_Events} + ${SOURCE_FILES_Events} + + ) set(LIBRARIES diff --git a/src/Game/Game.cpp b/src/Game/Game.cpp index 8ca3584d..0dd513b6 100644 --- a/src/Game/Game.cpp +++ b/src/Game/Game.cpp @@ -79,6 +79,7 @@ Game::Game(int argc, char* argv[]) m_SystemPipeline->AddSystem(updateOrderLevel, m_Renderer); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); + m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); // Populate Octree with collidables @@ -145,7 +146,6 @@ void Game::Tick() m_SystemPipeline->Update(m_World, dt); debugTick(dt); m_Renderer->Update(dt); - m_EventBroker->Process(); m_SoundSystem->Update(dt); GLERROR("Game::Tick m_RenderQueueFactory->Update"); m_Renderer->Draw(*m_RenderFrame); diff --git a/src/Game/Systems/InterpolationSystem.cpp b/src/Game/Systems/InterpolationSystem.cpp new file mode 100644 index 00000000..f6d5989d --- /dev/null +++ b/src/Game/Systems/InterpolationSystem.cpp @@ -0,0 +1,86 @@ +#include "Systems/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, EntityWrapper& entity, ComponentWrapper & transform, double 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; + glm::vec3 currentPosition = static_cast(transform["Position"]); + (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&)transform["Scale"] += vectorInterpolation(currentScale, nextScale, sTransform.interpolationTime); + } + } +} + +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); + 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)); + transform.interpolationTime = 0.0f; + + 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); + //} + + //else { // Did not exist, create queue + // std::queue transformQueue; + // transformQueue.push(transform); + // m_InterpolationPoints[e.Entity] = transformQueue; + //} + return false; +}