diff --git a/include/Engine/Core/World.h b/include/Engine/Core/World.h index 0a121728..c066933a 100644 --- a/include/Engine/Core/World.h +++ b/include/Engine/Core/World.h @@ -22,6 +22,8 @@ public: void RegisterComponent(ComponentInfo& ci); // Attach a component to an entity and fill it with default values ComponentWrapper AttachComponent(EntityID entity, std::string componentType); + // Check if world has an entity + bool HasEntity(EntityID entity); // Check if an entity has a component bool HasComponent(EntityID entity, std::string componentType) const; // Get a component of an entity diff --git a/include/Engine/Network/Packet.h b/include/Engine/Network/Packet.h index daf39962..76cf2cba 100644 --- a/include/Engine/Network/Packet.h +++ b/include/Engine/Network/Packet.h @@ -14,8 +14,9 @@ public: Packet(MessageType type, unsigned int& packetID); // Used to create packet from already existing data buffer. Packet(char* data, const int sizeOfPacket); - ~Packet(); + void Init(MessageType type, unsigned int& packetID); + // Add primitive types like int, float, char... template void WritePrimitive(T val) @@ -23,6 +24,7 @@ public: // Check if we are trying to add more than the package can fit. if (m_MaxPacketSize < m_Offset + sizeof(T)) { LOG_WARNING("Packet AddPrimitive(): You are trying to add more than we have allocated for!"); + return; } memcpy(m_Data + m_Offset, &val, sizeof(T)); m_Offset += sizeof(T); @@ -50,6 +52,8 @@ public: int Size() { return m_Offset; }; char* Data() { return m_Data; }; + unsigned int DataReadSize() { return m_ReturnDataOffset; } + unsigned int MaxSize() { return m_MaxPacketSize; } private: char* m_Data; diff --git a/include/Engine/Network/Server.h b/include/Engine/Network/Server.h index 5c1ac1fb..af454bc1 100644 --- a/include/Engine/Network/Server.h +++ b/include/Engine/Network/Server.h @@ -67,6 +67,7 @@ private: void moveMessageHead(char*& data, size_t& length, size_t stepSize); void broadcast(std::string message); void broadcast(Packet& packet); + //void parseShitTest(Packet& packet); // Remove this when network is working void sendSnapshot(); void sendPing(); void checkForTimeOuts(); diff --git a/src/Engine/Collision/Collision.cpp b/src/Engine/Collision/Collision.cpp index c4af6258..a767ee95 100644 --- a/src/Engine/Collision/Collision.cpp +++ b/src/Engine/Collision/Collision.cpp @@ -245,23 +245,29 @@ bool attachAABBComponentFromModel(World* world, EntityID id) bool GetEntityBox(World* world, ComponentWrapper& AABBComponent, AABB& outBox) { - ComponentWrapper& cTrans = world->GetComponent(AABBComponent.EntityID, "Transform"); - ComponentWrapper model = world->GetComponent(AABBComponent.EntityID, "Model"); - Model* modelRes = ResourceManager::Load(model["Resource"]); - outBox.CreateFromCenter(AABBComponent["BoxCenter"], AABBComponent["BoxSize"]); - glm::vec3 mini = outBox.MinCorner(); - glm::vec3 maxi = outBox.MaxCorner(); + if (world->HasComponent(AABBComponent.EntityID, "Transform") && world->HasComponent(AABBComponent.EntityID, "Model")) + { + ComponentWrapper& cTrans = world->GetComponent(AABBComponent.EntityID, "Transform"); + ComponentWrapper model = world->GetComponent(AABBComponent.EntityID, "Model"); + if(AABBComponent.EntityID == 3); + std::string checkPath = model["Resource"]; + Model* modelRes = ResourceManager::Load(model["Resource"]); + outBox.CreateFromCenter(AABBComponent["BoxCenter"], AABBComponent["BoxSize"]); + glm::vec3 mini = outBox.MinCorner(); + glm::vec3 maxi = outBox.MaxCorner(); - if (modelRes == nullptr) { - return false; + if (modelRes == nullptr) { + return false; + } + glm::mat4 modelMatrix = modelRes->m_Matrix * + glm::translate(glm::mat4(), (glm::vec3)cTrans["Position"]) * + glm::scale((glm::vec3)cTrans["Scale"]); + + outBox = AABB(modelMatrix * glm::vec4(mini.x, mini.y, mini.z, 1), + modelMatrix * glm::vec4(maxi.x, maxi.y, maxi.z, 1)); + return true; } - glm::mat4 modelMatrix = modelRes->m_Matrix * - glm::translate(glm::mat4(), (glm::vec3)cTrans["Position"]) * - glm::scale((glm::vec3)cTrans["Scale"]); - - outBox = AABB(modelMatrix * glm::vec4(mini.x, mini.y, mini.z, 1), - modelMatrix * glm::vec4(maxi.x, maxi.y, maxi.z, 1)); - return true; + return false; } bool GetEntityBox(World* world, EntityID entity, AABB& outBox, bool forceBoxFromModel) diff --git a/src/Engine/Core/World.cpp b/src/Engine/Core/World.cpp index c94cb8b3..faddeb83 100644 --- a/src/Engine/Core/World.cpp +++ b/src/Engine/Core/World.cpp @@ -80,7 +80,13 @@ ComponentWrapper World::AttachComponent(EntityID entity, std::string componentTy return c; } -bool World::HasComponent(EntityID entity, std::string componentType) const +bool World::HasEntity(EntityID entity) +{ + return m_EntityParents.find(entity) != m_EntityParents.end(); +} + + +bool World::HasComponent(EntityID entity, std::string componentType) { ComponentPool* pool = m_ComponentPools.at(componentType); return pool->KnowsEntity(entity); diff --git a/src/Engine/Network/Client.cpp b/src/Engine/Network/Client.cpp index f01509b4..08f68f98 100644 --- a/src/Engine/Network/Client.cpp +++ b/src/Engine/Network/Client.cpp @@ -50,7 +50,7 @@ void Client::Close() void Client::readFromServer() { - if (m_Socket.available()) { + while (m_Socket.available()) { bytesRead = receive(readBuf, INPUTSIZE); if (bytesRead > 0) { Packet packet(readBuf, bytesRead); @@ -60,7 +60,7 @@ void Client::readFromServer() std::clock_t currentTime = std::clock(); if (snapshotInterval < (1000 * (currentTime - previousSnapshotMessage) / (double)CLOCKS_PER_SEC)) { if (isConnected()) { - sendSnapshotToServer(); + //sendSnapshotToServer(); } previousSnapshotMessage = currentTime; } @@ -120,6 +120,8 @@ 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(); switch (static_cast(messageType)) { @@ -181,33 +183,45 @@ void Client::parseEventMessage(Packet& packet) void Client::parseSnapshot(Packet& packet) { - std::string tempName; - for (size_t i = 0; i < MAXCONNECTIONS; i++) { - // We're checking for empty name for now. This might not be the best way, - // but it is to avoid sending redundant data. - tempName = packet.ReadString(); - - - // Apply the position data read to the player entity - // New player connected on the server side - if (m_PlayerDefinitions[i].Name == "" && tempName != "") { - m_PlayerDefinitions[i].Name = tempName; - m_PlayerDefinitions[i].EntityID = createPlayer(); - } else if (m_PlayerDefinitions[i].Name != "" && tempName == "") { - // Someone disconnected - // TODO: Insert code here - break; - } else if (m_PlayerDefinitions[i].Name == "" && tempName == "") { - // Not a connected player - break; - } - if (m_PlayerDefinitions[i].EntityID != -1) { - - // Move player to server position - int dataSize = m_World->GetComponent(m_PlayerDefinitions[i].EntityID, "Transform").Info.Meta.Stride; - memcpy(m_World->GetComponent(m_PlayerDefinitions[i].EntityID, "Transform").Data, packet.ReadData(dataSize), dataSize); + std::string componentType = packet.ReadString(); + //LOG_INFO("A snapshot was parsed. first component type is: %s", componentType.c_str()); + int stride = packet.ReadPrimitive(); + int nrOfComponents = (packet.Size() - packet.DataReadSize()) / (stride + sizeof(EntityID)); + if (componentType == "Model") + return; + for (size_t i = 0; i < nrOfComponents; i++) { + EntityID entityID = packet.ReadPrimitive(); + //ComponentWrapper model = m_World->GetComponent(entityID, "Model"); + //std::string checkPath = model["Resource"]; + // Check if entity exists + if (m_World->HasEntity(entityID)) { + // check if component exists + if (m_World->HasComponent(entityID, componentType)) { + //Copy data to component + memcpy(m_World->GetComponent(entityID, componentType).Data, packet.ReadData(stride), stride); + } else { + // If component doesen't exist + // Create component + m_World->AttachComponent(entityID, componentType); + // Copy data to newly created component + memcpy(m_World->GetComponent(entityID, componentType).Data, packet.ReadData(stride), stride); + } + } else { + // If entity dosen't exist + EntityID newEntityID = m_World->CreateEntity(); + // Check if EntityIDs are out of sync + if (newEntityID != entityID) { + LOG_INFO("Client::parseSnapshot(Packet& packet): Newly created EntityID is not the same as the one sent by server \ + EntityIDs are out of sync"); + } + m_World->AttachComponent(newEntityID, componentType); + // Copy data to newly created component + memcpy(m_World->GetComponent(entityID, componentType).Data, packet.ReadData(stride), stride); } + //ComponentWrapper model2 = m_World->GetComponent(entityID, "Model"); + //std::string checkPath2 = model2["Resource"]; } + } int Client::receive(char* data, size_t length) diff --git a/src/Engine/Network/Packet.cpp b/src/Engine/Network/Packet.cpp index 52b15065..86a91f5d 100644 --- a/src/Engine/Network/Packet.cpp +++ b/src/Engine/Network/Packet.cpp @@ -3,13 +3,7 @@ Packet::Packet(MessageType type, unsigned int& packetID) { m_Data = new char[m_MaxPacketSize]; - // Create message header - // Add message type - int messageType = static_cast(type); - Packet::WritePrimitive(messageType); - packetID = packetID % 1000; // Packet id modulos - Packet::WritePrimitive(packetID); - packetID++; + Init(type, packetID); } // Create message @@ -28,12 +22,26 @@ 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++; +} + void Packet::WriteString(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.\n"); + return; } memcpy(m_Data + m_Offset, str.data(), sizeOfString * sizeof(char)); m_Offset += sizeOfString * sizeof(char); @@ -43,6 +51,7 @@ 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.\n"); + return; } memcpy(m_Data + m_Offset, data, sizeOfData); m_Offset += sizeOfData; diff --git a/src/Engine/Network/Server.cpp b/src/Engine/Network/Server.cpp index bedbf954..791f5a42 100644 --- a/src/Engine/Network/Server.cpp +++ b/src/Engine/Network/Server.cpp @@ -4,7 +4,7 @@ Server::Server() : m_Socket(m_IOService, boost::asio::ip::udp::endpoint(boost::a { } Server::~Server() -{ +{ } @@ -36,7 +36,7 @@ void Server::readFromClients() // program crashed if it executed m_Socket.available() // when closing the program. - if (m_Socket.available()) { + while (m_Socket.available()) { try { bytesRead = receive(readBuffer, INPUTSIZE); Packet packet(readBuffer, bytesRead); @@ -61,7 +61,7 @@ void Server::readFromClients() // Time out logic if (checkTimeOutInterval < (1000 * (currentTime - timOutTimer) / (double)CLOCKS_PER_SEC)) { - checkForTimeOuts(); + //checkForTimeOuts(); timOutTimer = currentTime; } } @@ -152,32 +152,127 @@ void Server::broadcast(Packet& packet) } } } +// +//void Server::parseShitTest(Packet& packet) +//{ +// packet.ReadPrimitive(); // MessageType +// packet.ReadPrimitive(); // Packet ID +// +// std::string componentType = packet.ReadString(); +// //LOG_INFO("A snapshot was parsed. first component type is: %s", componentType.c_str()); +// int stride = packet.ReadPrimitive(); +// int nrOfComponents = (packet.Size() - packet.DataReadSize()) / (stride + sizeof(EntityID)); +// //if (componentType == "Model") +// // return; +// for (size_t i = 0; i < nrOfComponents; i++) { +// EntityID entityID = packet.ReadPrimitive(); +// ComponentWrapper model = m_World->GetComponent(entityID, "Model"); +// std::string checkPath = model["Resource"]; +// // Check if entity exists +// if (m_World->HasEntity(entityID)) { +// // check if component exists +// if (m_World->HasComponent(entityID, componentType)) { +// //Copy data to component +// memcpy(m_World->GetComponent(entityID, componentType).Data, packet.ReadData(stride), stride); +// } else { +// // If component doesen't exist +// // Create component +// m_World->AttachComponent(entityID, componentType); +// // Copy data to newly created component +// memcpy(m_World->GetComponent(entityID, componentType).Data, packet.ReadData(stride), stride); +// } +// } else { +// // If entity dosen't exist +// EntityID newEntityID = m_World->CreateEntity(); +// // Check if EntityIDs are out of sync +// if (newEntityID != entityID) { +// LOG_INFO("Client::parseSnapshot(Packet& packet): Newly created EntityID is not the same as the one sent by server \ +// EntityIDs are out of sync"); +// } +// m_World->AttachComponent(newEntityID, componentType); +// // Copy data to newly created component +// memcpy(m_World->GetComponent(entityID, componentType).Data, packet.ReadData(stride), stride); +// } +// ComponentWrapper model2 = m_World->GetComponent(entityID, "Model"); +// std::string checkPath2 = model2["Resource"]; +// } +//} void Server::sendSnapshot() { - Packet packet(MessageType::Snapshot, m_SendPacketID); - for (size_t i = 0; i < MAXCONNECTIONS; i++) { - - // Send an empty name if there is no player connected on this position. - packet.WriteString(m_PlayerDefinitions[i].Name); - - if (m_PlayerDefinitions[i].EntityID == -1) { - continue; + // 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; + //if (componentType != "Model") + // continue; + ComponentPool* componentPool = it.second; + ComponentInfo componentInfo = componentPool->ComponentInfo(); + packet.WriteString(componentInfo.Name); + packet.WritePrimitive(componentInfo.Meta.Stride); + for (auto componentWrapper : *componentPool) { + if (packet.Size() + componentInfo.Meta.Stride >= packet.MaxSize()) { + broadcast(packet); + //parseShitTest(packet); + // Packet destructor is called (which is what we want). + packet.Init(MessageType::Snapshot, m_SendPacketID); + // Add Component header + packet.WriteString(componentInfo.Name); + packet.WritePrimitive(componentInfo.Meta.Stride); + } + // Component data + packet.WritePrimitive(componentWrapper.EntityID); + packet.WriteData(componentWrapper.Data, componentWrapper.Info.Meta.Stride); } - // Pack transfrom component into data packet - auto transform = m_World->GetComponent(m_PlayerDefinitions[i].EntityID, "Transform"); - packet.WriteData(transform.Data, transform.Info.Meta.Stride); + broadcast(packet); } - broadcast(packet); } +//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; +// ComponentPool* componentPool = it.second; +// ComponentInfo componentInfo = componentPool->ComponentInfo(); +// if (componentInfo.Name != "Transform") +// continue; +// packet.WriteString(componentInfo.Name); +// packet.WritePrimitive(componentInfo.Meta.Stride); +// auto componentWrapper = *componentPool->begin(); +// packet.WritePrimitive(componentWrapper.EntityID); +// packet.WriteData(componentWrapper.Data, componentWrapper.Info.Meta.Stride); +// +// for (auto componentWrapper : *componentPool) { +// //// When packet is full send it +// //if (packet.Size() + componentInfo.Meta.Stride >= packet.MaxSize()) { +// // broadcast(packet); +// // // Packet destructor is called (which is what we want). +// // packet.Init(MessageType::Snapshot, m_SendPacketID); +// // // Add Component header +// // packet.WriteString(componentInfo.Name); +// // packet.WritePrimitive(componentInfo.Meta.Stride); +// +// //} +// //// Component data +// //packet.WritePrimitive(componentWrapper.EntityID); +// //packet.WriteData(componentWrapper.Data, componentWrapper.Info.Meta.Stride); +// broadcast(packet); +// } +// broadcast(packet); +// } +//} + 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("%i: Player %i's ping: %i", m_PacketID, i, ping); + LOG_INFO("Last packetID received %i: Player %i's ping: %i", m_PacketID, i, ping); } }