From 2bf0434bcbff625d19a55bc2bc7cb1f5d2a7ff0b Mon Sep 17 00:00:00 2001 From: Jocke Date: Sat, 23 Jan 2016 16:40:38 +0100 Subject: [PATCH 01/12] Remade Snapshot logic from component based to entity based. --- include/Engine/Network/Server.h | 1 + src/Engine/Network/Client.cpp | 102 ++++++++++++++------------------ src/Engine/Network/Server.cpp | 66 +++++++++++++-------- 3 files changed, 85 insertions(+), 84 deletions(-) diff --git a/include/Engine/Network/Server.h b/include/Engine/Network/Server.h index 91ea5d21..87c8d944 100644 --- a/include/Engine/Network/Server.h +++ b/include/Engine/Network/Server.h @@ -64,6 +64,7 @@ private: void send(Packet& packet); void broadcast(Packet& packet); void sendSnapshot(); + void addChildrenToPacket(Packet& packet, EntityID entityID); void sendPing(); void checkForTimeOuts(); void disconnect(UserID user); diff --git a/src/Engine/Network/Client.cpp b/src/Engine/Network/Client.cpp index 1dd2bd04..387961ef 100644 --- a/src/Engine/Network/Client.cpp +++ b/src/Engine/Network/Client.cpp @@ -7,13 +7,13 @@ Client::Client(ConfigFile* config) : m_Socket(m_IOService) { Network::initialize(); - // Asumes root node is EntityID 0 - insertIntoServerClientMaps(0, 0); + // Asumes root node is EntityID_Invalid + insertIntoServerClientMaps(EntityID_Invalid, EntityID_Invalid); // Init timer m_TimeSinceSentInputs = std::clock(); // Default is local host std::string address = config->Get("Networking.Address", "127.0.0.1"); - int port = config->Get("Networking.Port", 13); + int port = config->Get("Networking.Port", 27666); m_ReceiverEndpoint = udp::endpoint(boost::asio::ip::address::from_string(address), port); // Set up network stream m_PlayerName = config->Get("Networking.Name", "Raptorcopter"); @@ -128,13 +128,13 @@ void Client::parsePing() } void Client::parseKick() -{ +{ LOG_WARNING("You have been kicked from the server."); m_IsConnected = false; } void Client::parsePlayersSpawned(Packet& packet) -{ +{ Events::PlayerSpawned e; e.Player = EntityWrapper(m_World, m_ServerIDToClientID[packet.ReadPrimitive()]); e.Spawner = EntityWrapper(m_World, m_ServerIDToClientID[packet.ReadPrimitive()]); @@ -176,66 +176,50 @@ void Client::updateFields(Packet& packet, const ComponentInfo& componentInfo, co void Client::parseSnapshot(Packet& packet) { - std::string componentType = packet.ReadString(); while (packet.DataReadSize() < packet.Size()) { - // HACK - std::string entityName = packet.ReadString(); - // Components EntityID - EntityID receivedEntityID = packet.ReadPrimitive(); - // HACK - m_World->SetName(receivedEntityID, entityName); - // Parents EntityID - 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 (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 - if (componentType == "Transform") { - InterpolateFields(packet, componentInfo, entityID, componentType); + EntityID serverEntityID = packet.ReadPrimitive(); + EntityID serverParentID = packet.ReadPrimitive(); + std::string serverEntityName = packet.ReadString(); + int ammountOfComponents = packet.ReadPrimitive(); + for (int i = 0; i < ammountOfComponents; i++) { + std::string componentType = packet.ReadString(); + ComponentInfo componentInfo = m_World->GetComponents(componentType)->ComponentInfo(); + if (serverClientMapsHasEntity(serverEntityID)) { + EntityID localEntityID = m_ServerIDToClientID.at(serverEntityID); + // Update entity + if (m_World->HasComponent(localEntityID, componentType)) { + // Update component + if (componentType == "Transform") { + // Interpolate only transform components + InterpolateFields(packet, componentInfo, localEntityID, componentType); + } else { + // Set component values + updateFields(packet, componentInfo, localEntityID, componentType); + } } else { - updateFields(packet, componentInfo, entityID, componentType); + // Has entity but no component + m_World->AttachComponent(localEntityID, componentType); + updateFields(packet, componentInfo, localEntityID, componentType); } - // if entity exists but not the component } else { - // Create component - m_World->AttachComponent(entityID, componentType); - // Copy data to newly created component - updateFields(packet, componentInfo, entityID, componentType); + // Create Entity and component + EntityID newLocalEntityID; + if (serverParentID == EntityID_Invalid) { + newLocalEntityID = m_World->CreateEntity(EntityID_Invalid); + } else { + newLocalEntityID = m_World->CreateEntity(m_ServerIDToClientID.at(serverParentID)); + } + m_World->SetName(newLocalEntityID, serverEntityName); + insertIntoServerClientMaps(serverEntityID, newLocalEntityID); + m_World->AttachComponent(newLocalEntityID, componentType); + updateFields(packet, componentInfo, newLocalEntityID, componentType); } - // If the entity dosent exist nor the component - } else { - // Create Entity - // If entity dosen't exist - EntityID newEntityID = m_World->CreateEntity(); - 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 \ - same as the one sent by server (EntityIDs are out of sync)"); - } - // Create component - m_World->AttachComponent(newEntityID, componentType); - // 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); - } + // Parent logic + // This should be enough beacause we know that the entities arives in pre-order (there will always be a parent) + if (serverParentID != EntityID_Invalid) { + EntityID localEntityID = m_ServerIDToClientID.at(serverEntityID); + m_World->SetParent(localEntityID, m_ServerIDToClientID.at(serverParentID)); } } } diff --git a/src/Engine/Network/Server.cpp b/src/Engine/Network/Server.cpp index 9d0a83d9..98774b99 100644 --- a/src/Engine/Network/Server.cpp +++ b/src/Engine/Network/Server.cpp @@ -175,35 +175,51 @@ void Server::broadcast(Packet& packet) // Send snapshot fields void Server::sendSnapshot() { - // Should time this - std::unordered_map worldComponentPools = m_World->GetComponentPools(); - for (auto& it : worldComponentPools) { - Packet packet(MessageType::Snapshot); - ComponentPool* componentPool = it.second; - ComponentInfo componentInfo = componentPool->ComponentInfo(); + Packet packet(MessageType::Snapshot); + addChildrenToPacket(packet, EntityID_Invalid); + broadcast(packet); +} - // Component Type - packet.WriteString(componentInfo.Name); - for (auto& componentWrapper : *componentPool) { - // HACK: Send entity name - packet.WriteString(m_World->GetName(componentWrapper.EntityID)); - // 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") { - std::string& value = componentWrapper[componentField]; - packet.WriteString(value); - } else { - packet.WriteData(componentWrapper.Data + fieldInfo.Offset, fieldInfo.Stride); +void Server::addChildrenToPacket(Packet & packet, EntityID entityID) +{ + auto itPair = m_World->GetChildren(entityID); + std::unordered_map worldComponentPools = m_World->GetComponentPools(); + // Loop through every child + for (auto it = itPair.first; it != itPair.second; it++) { + EntityID childEntityID = it->second; + // Write EntityID and parentsID and Entity name + packet.WritePrimitive(childEntityID); + packet.WritePrimitive(entityID); + packet.WriteString(m_World->GetName(childEntityID)); + // Write components to child + int numberOfComponents = 0; + for (auto& i : worldComponentPools) { + if (i.second->KnowsEntity(childEntityID)) { + numberOfComponents++; + } + } + // Write how many components should be read + packet.WritePrimitive(numberOfComponents); + for (auto& i : worldComponentPools) { + // If the entity exist in the pool + if (i.second->KnowsEntity(childEntityID)) { + ComponentWrapper componentWrapper = i.second->GetByEntity(childEntityID); + // ComponentType + packet.WriteString(componentWrapper.Info.Name); + // Loop through fields + for (auto& componentField : componentWrapper.Info.FieldsInOrder) { + ComponentInfo::Field_t fieldInfo = componentWrapper.Info.Fields.at(componentField); + if (fieldInfo.Type == "string") { + std::string& value = componentWrapper[componentField]; + packet.WriteString(value); + } else { + packet.WriteData(componentWrapper.Data + fieldInfo.Offset, fieldInfo.Stride); + } } } } - if (packet.Size() > packet.HeaderSize() + componentInfo.Name.size()) { - broadcast(packet); - } + // Go to to your children + addChildrenToPacket(packet, childEntityID); } } From 97d70f8e32917396a6396a0b87aafded4fe6969e Mon Sep 17 00:00:00 2001 From: Jocke Date: Sun, 24 Jan 2016 11:36:01 +0100 Subject: [PATCH 02/12] Fixed in client for shoot event. Weapon system now damages health on any target not only players. --- resources/DefaultInput.ini | 3 ++- src/Engine/Network/Client.cpp | 4 ++-- src/Game/Systems/HealthSystem.cpp | 1 - src/Game/Systems/WeaponSystem.cpp | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/resources/DefaultInput.ini b/resources/DefaultInput.ini index 5ed46241..d07ed6a3 100644 --- a/resources/DefaultInput.ini +++ b/resources/DefaultInput.ini @@ -21,4 +21,5 @@ F1=ToggleEditor X=EditorToggleTransformSpace C=ConnectToServer N=SwitchToServer -M=SwitchToClient \ No newline at end of file +M=SwitchToClient +P=SwitchToPlayer \ No newline at end of file diff --git a/src/Engine/Network/Client.cpp b/src/Engine/Network/Client.cpp index 387961ef..2a4f531e 100644 --- a/src/Engine/Network/Client.cpp +++ b/src/Engine/Network/Client.cpp @@ -310,9 +310,9 @@ bool Client::OnInputCommand(const Events::InputCommand & e) bool Client::OnPlayerDamage(const Events::PlayerDamage & e) { - Packet packet(MessageType::OnInputCommand, m_SendPacketID); + Packet packet(MessageType::OnPlayerDamage, m_SendPacketID); packet.WritePrimitive(e.DamageAmount); - packet.WritePrimitive(e.PlayerDamagedID); + packet.WritePrimitive(m_ClientIDToServerID.at(e.PlayerDamagedID)); send(packet); return false; } diff --git a/src/Game/Systems/HealthSystem.cpp b/src/Game/Systems/HealthSystem.cpp index 5e5be33e..4190e04f 100644 --- a/src/Game/Systems/HealthSystem.cpp +++ b/src/Game/Systems/HealthSystem.cpp @@ -12,7 +12,6 @@ HealthSystem::HealthSystem(World* m_World, EventBroker* eventBroker) void HealthSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt) { //if entityID of health is 9 then the players ID is also 9 (player,health are connected to the same entity) - ComponentWrapper player = m_World->GetComponent(component.EntityID, "Player"); double maxHealth = (double)component["MaxHealth"]; //process the DeltaHealthVector and change the entitys health accordingly diff --git a/src/Game/Systems/WeaponSystem.cpp b/src/Game/Systems/WeaponSystem.cpp index 11f76490..da5b057b 100644 --- a/src/Game/Systems/WeaponSystem.cpp +++ b/src/Game/Systems/WeaponSystem.cpp @@ -22,8 +22,8 @@ void WeaponSystem::Update(double dt) continue; } //if its a player, do PlayerDamage event - const bool hasPlayerComponent = m_World->HasComponent(pickDataFromShot.Entity, "Player"); - if (hasPlayerComponent) { + const bool hasHealthComponent = m_World->HasComponent(pickDataFromShot.Entity, "Health"); + if (hasHealthComponent) { Events::PlayerDamage ePlayerDamage; //TODO: damage based on weapontype/class? //TODO: multiple shots at the same time? (shotgunner) From 7567f47a68afdfff10e0bafabe3ef2fa36289db8 Mon Sep 17 00:00:00 2001 From: Jocke Date: Sun, 24 Jan 2016 11:56:46 +0100 Subject: [PATCH 03/12] Weapon system now searches parents for health component (stops at first health component). --- src/Game/Systems/WeaponSystem.cpp | 36 +++++++++++++++---------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/Game/Systems/WeaponSystem.cpp b/src/Game/Systems/WeaponSystem.cpp index da5b057b..8ee55c76 100644 --- a/src/Game/Systems/WeaponSystem.cpp +++ b/src/Game/Systems/WeaponSystem.cpp @@ -11,25 +11,23 @@ WeaponSystem::WeaponSystem(World* world, EventBroker* eventBroker, IRenderer* re void WeaponSystem::Update(double dt) { - for (int i = m_EShootVector.size(); i > 0; i--) - { - //TODO: check if player has enough ammo and if weapon has a cooldown or not - + for (int i = m_EShootVector.size(); i > 0; i--) { //pick the object PickData pickDataFromShot = m_Renderer->Pick(std::get<1>(m_EShootVector[i - 1])); - if (pickDataFromShot.Entity == EntityID_Invalid) { - m_EShootVector.erase(m_EShootVector.begin() + i - 1); - continue; - } - //if its a player, do PlayerDamage event - const bool hasHealthComponent = m_World->HasComponent(pickDataFromShot.Entity, "Health"); - if (hasHealthComponent) { - Events::PlayerDamage ePlayerDamage; - //TODO: damage based on weapontype/class? - //TODO: multiple shots at the same time? (shotgunner) - ePlayerDamage.DamageAmount = 25; - ePlayerDamage.PlayerDamagedID = pickDataFromShot.Entity; - m_EventBroker->Publish(ePlayerDamage); + EntityID entityID = pickDataFromShot.Entity; + while (entityID != EntityID_Invalid) { + // If has health + if (m_World->HasComponent(entityID, "Health")) { + Events::PlayerDamage ePlayerDamage; + //TODO: damage based on weapontype/class? + //TODO: multiple shots at the same time? (shotgunner) + ePlayerDamage.DamageAmount = 25; + ePlayerDamage.PlayerDamagedID = entityID; + m_EventBroker->Publish(ePlayerDamage); + break; + } else { + entityID = m_World->GetParent(entityID); + } } m_EShootVector.erase(m_EShootVector.begin() + i - 1); } @@ -44,8 +42,10 @@ bool WeaponSystem::OnInputCommand(const Events::InputCommand& e) } return true; } -bool WeaponSystem::OnShoot(const Events::Shoot& e) { +bool WeaponSystem::OnShoot(const Events::Shoot& e) +{ //screen center, based on current resolution! + //TODO: check if player has enough ammo and if weapon has a cooldown or not Rectangle screenResolution = m_Renderer->Resolution(); glm::vec2 centerScreen = glm::vec2(screenResolution.Width / 2, screenResolution.Height / 2); m_EShootVector.push_back(std::make_pair(e.shooter, centerScreen)); From 67477ff3ae02fd5907d049418b6a380812aed91c Mon Sep 17 00:00:00 2001 From: sippeangelo Date: Sun, 24 Jan 2016 13:49:45 +0100 Subject: [PATCH 04/12] EEntityDeleted and EComponentDeleted events published by World --- include/Engine/Core/EComponentDeleted.h | 21 ++++++ include/Engine/Core/EEntityDeleted.h | 19 +++++ include/Engine/Core/World.h | 6 ++ src/Engine/Core/World.cpp | 93 ++++++++++++++++--------- src/Game/Game.cpp | 2 +- 5 files changed, 108 insertions(+), 33 deletions(-) create mode 100644 include/Engine/Core/EComponentDeleted.h create mode 100644 include/Engine/Core/EEntityDeleted.h diff --git a/include/Engine/Core/EComponentDeleted.h b/include/Engine/Core/EComponentDeleted.h new file mode 100644 index 00000000..6d9c468d --- /dev/null +++ b/include/Engine/Core/EComponentDeleted.h @@ -0,0 +1,21 @@ +#ifndef EComponentDeleted_h__ +#define EComponentDeleted_h__ + +#include "../Common.h" +#include "Event.h" +#include "Entity.h" + +namespace Events +{ + +struct ComponentDeleted : Event +{ + EntityID Entity; + std::string ComponentType; + // True if the component was deleted as a result of the entity it was attached to being deleted + bool Cascaded; +}; + +} + +#endif \ No newline at end of file diff --git a/include/Engine/Core/EEntityDeleted.h b/include/Engine/Core/EEntityDeleted.h new file mode 100644 index 00000000..80e20e17 --- /dev/null +++ b/include/Engine/Core/EEntityDeleted.h @@ -0,0 +1,19 @@ +#ifndef EEntityDeleted_h__ +#define EEntityDeleted_h__ + +#include "Event.h" +#include "Entity.h" + +namespace Events +{ + +struct EntityDeleted : Event +{ + EntityID DeletedEntity; + // True if the entity deletion was triggered because the entity's parent was deleted before it + bool Cascaded; +}; + +} + +#endif \ No newline at end of file diff --git a/include/Engine/Core/World.h b/include/Engine/Core/World.h index b201d4ac..35394b9f 100644 --- a/include/Engine/Core/World.h +++ b/include/Engine/Core/World.h @@ -5,11 +5,15 @@ #include "Entity.h" #include "ObjectPool.h" #include "ComponentPool.h" +#include "EventBroker.h" class World { public: World() = default; + World(EventBroker* eventBroker) + : m_EventBroker(eventBroker) + { } ~World(); // Create empty entity @@ -46,6 +50,7 @@ public: std::string GetName(EntityID entity) const; private: + EventBroker* m_EventBroker = nullptr; EntityID m_CurrentEntityID = 0; std::unordered_map m_EntityParents; @@ -55,6 +60,7 @@ private: std::unordered_map m_EntityNames; EntityID generateEntityID(); + void deleteEntityRecursive(EntityID entity, bool cascaded = false); }; #endif \ No newline at end of file diff --git a/src/Engine/Core/World.cpp b/src/Engine/Core/World.cpp index 477e2ab2..97e3ba9f 100644 --- a/src/Engine/Core/World.cpp +++ b/src/Engine/Core/World.cpp @@ -1,4 +1,6 @@ #include "Core/World.h" +#include "Core/EEntityDeleted.h" +#include "Core/EComponentDeleted.h" World::~World() { @@ -21,37 +23,7 @@ EntityID World::CreateEntity(EntityID parent /*= 0*/) void World::DeleteEntity(EntityID entity) { - // Delete components - for (auto& pair : m_ComponentPools) { - auto& pool = pair.second; - if (pool->KnowsEntity(entity)) { - auto& c = pool->GetByEntity(entity); - pool->Delete(c); - } - } - - // Loop through children - std::vector childrenToDelete; - auto children = m_EntityChildren.equal_range(entity); - for (auto it = children.first; it != children.second; ++it) { - childrenToDelete.push_back(it->second); - } - for (auto& child : childrenToDelete) { - DeleteEntity(child); - } - - EntityID parent = m_EntityParents.at(entity); - m_EntityParents.erase(entity); - auto parentChildren = m_EntityChildren.equal_range(parent); - for (auto it = parentChildren.first; it != parentChildren.second; ++it) { - if (it->second == entity) { - m_EntityChildren.erase(it); - break; - } - } - - // Erase potential name - m_EntityNames.erase(entity); + deleteEntityRecursive(entity, false); } bool World::ValidEntity(EntityID entity) const @@ -96,7 +68,15 @@ void World::DeleteComponent(EntityID entity, const std::string& componentType) { ComponentPool* pool = m_ComponentPools.at(componentType); ComponentWrapper c = pool->GetByEntity(entity); - return pool->Delete(c); + pool->Delete(c); + + if (m_EventBroker != nullptr) { + Events::ComponentDeleted e; + e.Entity = entity; + e.ComponentType = componentType; + e.Cascaded = false; + m_EventBroker->Publish(e); + } } const ComponentPool* World::GetComponents(const std::string& componentType) @@ -155,3 +135,52 @@ EntityID World::generateEntityID() return m_CurrentEntityID++; } +void World::deleteEntityRecursive(EntityID entity, bool cascaded /*= false*/) +{ + if (m_EventBroker != nullptr) { + Events::EntityDeleted e; + e.DeletedEntity = entity; + e.Cascaded = cascaded; + m_EventBroker->Publish(e); + } + + // Delete components + for (auto& pair : m_ComponentPools) { + auto& pool = pair.second; + if (pool->KnowsEntity(entity)) { + auto& c = pool->GetByEntity(entity); + pool->Delete(c); + if (m_EventBroker != nullptr) { + Events::ComponentDeleted e; + e.Entity = entity; + e.ComponentType = pair.first; + e.Cascaded = true; + m_EventBroker->Publish(e); + } + } + } + + // Loop through children + std::vector childrenToDelete; + auto children = m_EntityChildren.equal_range(entity); + for (auto it = children.first; it != children.second; ++it) { + childrenToDelete.push_back(it->second); + } + for (auto& child : childrenToDelete) { + deleteEntityRecursive(child, true); + } + + EntityID parent = m_EntityParents.at(entity); + m_EntityParents.erase(entity); + auto parentChildren = m_EntityChildren.equal_range(parent); + for (auto it = parentChildren.first; it != parentChildren.second; ++it) { + if (it->second == entity) { + m_EntityChildren.erase(it); + break; + } + } + + // Erase potential name + m_EntityNames.erase(entity); +} + diff --git a/src/Game/Game.cpp b/src/Game/Game.cpp index 384c4a5b..5de61b8c 100644 --- a/src/Game/Game.cpp +++ b/src/Game/Game.cpp @@ -57,7 +57,7 @@ Game::Game(int argc, char* argv[]) m_FrameStack->Height = m_Renderer->Resolution().Height; // Create a world - m_World = new World(); + m_World = new World(m_EventBroker); std::string mapToLoad = m_Config->Get("Debug.LoadMap", ""); if (!mapToLoad.empty()) { auto file = ResourceManager::Load(mapToLoad); From 235b26ad616ada2ce3e4292b81499d19fa532acc Mon Sep 17 00:00:00 2001 From: sippeangelo Date: Sun, 24 Jan 2016 17:16:18 +0100 Subject: [PATCH 05/12] WIP shoot --- include/Engine/Core/EPlayerDamage.h | 6 +-- include/Engine/Core/EShoot.h | 6 +-- include/Engine/Core/EntityWrapper.h | 3 +- include/Game/Systems/WeaponSystem.h | 19 ++++--- resources/Schema/Entities/Player.xml | 5 +- src/Engine/Core/EntityWrapper.cpp | 12 +++++ src/Engine/Network/Client.cpp | 4 +- src/Engine/Network/Server.cpp | 4 +- src/Game/Systems/HealthSystem.cpp | 2 +- src/Game/Systems/WeaponSystem.cpp | 80 +++++++++++++++++++--------- 10 files changed, 93 insertions(+), 48 deletions(-) diff --git a/include/Engine/Core/EPlayerDamage.h b/include/Engine/Core/EPlayerDamage.h index e0f2acd7..a7e135ce 100644 --- a/include/Engine/Core/EPlayerDamage.h +++ b/include/Engine/Core/EPlayerDamage.h @@ -2,15 +2,15 @@ #define EPlayerDamage_h__ #include "EventBroker.h" -#include "../Core/Entity.h" +#include "../Core/EntityWrapper.h" namespace Events { struct PlayerDamage : Event { - double DamageAmount; - EntityID PlayerDamagedID; + EntityWrapper Player; + double Damage; }; } diff --git a/include/Engine/Core/EShoot.h b/include/Engine/Core/EShoot.h index fd54122f..76821a24 100644 --- a/include/Engine/Core/EShoot.h +++ b/include/Engine/Core/EShoot.h @@ -2,16 +2,14 @@ #define EShoot_h__ #include "EventBroker.h" -#include "../Core/Entity.h" -#include "Engine/GLM.h" +#include "../Core/EntityWrapper.h" namespace Events { struct Shoot : Event { - //ID for who made the shot - EntityID shooter; + EntityWrapper Player; }; } diff --git a/include/Engine/Core/EntityWrapper.h b/include/Engine/Core/EntityWrapper.h index 711f5045..79bae9ed 100644 --- a/include/Engine/Core/EntityWrapper.h +++ b/include/Engine/Core/EntityWrapper.h @@ -23,9 +23,10 @@ struct EntityWrapper static const EntityWrapper Invalid; - bool HasComponent(const std::string& componentName); + bool HasComponent(const std::string& componentType); EntityWrapper Parent(); EntityWrapper FirstChildByName(const std::string& name); + EntityWrapper FirstParentWithComponent(const std::string& componentType); bool IsChildOf(EntityWrapper potentialParent); bool Valid(); diff --git a/include/Game/Systems/WeaponSystem.h b/include/Game/Systems/WeaponSystem.h index 5acf72b3..0397b1a3 100644 --- a/include/Game/Systems/WeaponSystem.h +++ b/include/Game/Systems/WeaponSystem.h @@ -9,6 +9,7 @@ #include "Core/System.h" #include "Core/EPlayerDamage.h" #include "Core/EShoot.h" +#include "Core/EPlayerSpawned.h" #include "Input/EInputCommand.h" #include @@ -23,16 +24,18 @@ public: virtual void Update(double dt) override; private: - //methods which will take care of specific events - EventRelay m_EShoot; - bool WeaponSystem::OnShoot(const Events::Shoot& e); - - EventRelay m_EInputCommand; - bool WeaponSystem::OnInputCommand(const Events::InputCommand& e); - IRenderer* m_Renderer; - std::vector> m_EShootVector; + // State + EntityWrapper m_LocalPlayer = EntityWrapper::Invalid; + + // Events + EventRelay m_EPlayerSpawned; + bool WeaponSystem::OnPlayerSpawned(const Events::PlayerSpawned& e); + EventRelay m_EShoot; + bool WeaponSystem::OnShoot(const Events::Shoot& e); + EventRelay m_EInputCommand; + bool WeaponSystem::OnInputCommand(const Events::InputCommand& e); }; #endif \ No newline at end of file diff --git a/resources/Schema/Entities/Player.xml b/resources/Schema/Entities/Player.xml index 00d2e295..4ac1d205 100644 --- a/resources/Schema/Entities/Player.xml +++ b/resources/Schema/Entities/Player.xml @@ -9,7 +9,7 @@ - + false 5 @@ -20,7 +20,7 @@ - + @@ -82,6 +82,7 @@ Models/AssaultHeadless.obj + diff --git a/src/Engine/Core/EntityWrapper.cpp b/src/Engine/Core/EntityWrapper.cpp index 55d341e1..02d9246a 100644 --- a/src/Engine/Core/EntityWrapper.cpp +++ b/src/Engine/Core/EntityWrapper.cpp @@ -36,6 +36,18 @@ EntityWrapper EntityWrapper::FirstChildByName(const std::string& name) return EntityWrapper::Invalid; } +EntityWrapper EntityWrapper::FirstParentWithComponent(const std::string& componentType) +{ + EntityWrapper entity = *this; + while (entity.Parent().Valid()) { + entity = entity.Parent(); + if (entity.HasComponent(componentType)) { + return entity; + } + } + return EntityWrapper::Invalid; +} + bool EntityWrapper::IsChildOf(EntityWrapper potentialParent) { EntityWrapper entity = *this; diff --git a/src/Engine/Network/Client.cpp b/src/Engine/Network/Client.cpp index 1dd2bd04..5ddba631 100644 --- a/src/Engine/Network/Client.cpp +++ b/src/Engine/Network/Client.cpp @@ -327,8 +327,8 @@ bool Client::OnInputCommand(const Events::InputCommand & e) bool Client::OnPlayerDamage(const Events::PlayerDamage & e) { Packet packet(MessageType::OnInputCommand, m_SendPacketID); - packet.WritePrimitive(e.DamageAmount); - packet.WritePrimitive(e.PlayerDamagedID); + packet.WritePrimitive(e.Damage); + packet.WritePrimitive(e.Player.ID); send(packet); return false; } diff --git a/src/Engine/Network/Server.cpp b/src/Engine/Network/Server.cpp index 9d0a83d9..77702960 100644 --- a/src/Engine/Network/Server.cpp +++ b/src/Engine/Network/Server.cpp @@ -286,8 +286,8 @@ void Server::parseOnInputCommand(Packet& packet) void Server::parseOnPlayerDamage(Packet & packet) { Events::PlayerDamage e; - e.DamageAmount = packet.ReadPrimitive(); - e.PlayerDamagedID = packet.ReadPrimitive(); + e.Damage = packet.ReadPrimitive(); + e.Player = EntityWrapper(m_World, packet.ReadPrimitive()); 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()); } diff --git a/src/Game/Systems/HealthSystem.cpp b/src/Game/Systems/HealthSystem.cpp index 5e5be33e..64b8e51b 100644 --- a/src/Game/Systems/HealthSystem.cpp +++ b/src/Game/Systems/HealthSystem.cpp @@ -49,7 +49,7 @@ void HealthSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& comp bool HealthSystem::OnPlayerDamaged(const Events::PlayerDamage& e) { //save the changed HP to a vector. it will be taken care of in UpdateComponent - m_DeltaHealthVector.push_back(std::make_tuple(e.PlayerDamagedID, -e.DamageAmount)); + //m_DeltaHealthVector.push_back(std::make_tuple(e.PlayerDamagedID, -e.DamageAmount)); return true; } diff --git a/src/Game/Systems/WeaponSystem.cpp b/src/Game/Systems/WeaponSystem.cpp index 11f76490..8a88eb13 100644 --- a/src/Game/Systems/WeaponSystem.cpp +++ b/src/Game/Systems/WeaponSystem.cpp @@ -5,49 +5,79 @@ WeaponSystem::WeaponSystem(World* world, EventBroker* eventBroker, IRenderer* re , ImpureSystem() , m_Renderer(renderer) { + EVENT_SUBSCRIBE_MEMBER(m_EPlayerSpawned, &WeaponSystem::OnPlayerSpawned); EVENT_SUBSCRIBE_MEMBER(m_EInputCommand, &WeaponSystem::OnInputCommand); EVENT_SUBSCRIBE_MEMBER(m_EShoot, &WeaponSystem::OnShoot); } void WeaponSystem::Update(double dt) { - for (int i = m_EShootVector.size(); i > 0; i--) - { - //TODO: check if player has enough ammo and if weapon has a cooldown or not - //pick the object - PickData pickDataFromShot = m_Renderer->Pick(std::get<1>(m_EShootVector[i - 1])); - if (pickDataFromShot.Entity == EntityID_Invalid) { - m_EShootVector.erase(m_EShootVector.begin() + i - 1); - continue; - } - //if its a player, do PlayerDamage event - const bool hasPlayerComponent = m_World->HasComponent(pickDataFromShot.Entity, "Player"); - if (hasPlayerComponent) { - Events::PlayerDamage ePlayerDamage; - //TODO: damage based on weapontype/class? - //TODO: multiple shots at the same time? (shotgunner) - ePlayerDamage.DamageAmount = 25; - ePlayerDamage.PlayerDamagedID = pickDataFromShot.Entity; - m_EventBroker->Publish(ePlayerDamage); - } - m_EShootVector.erase(m_EShootVector.begin() + i - 1); +} + +bool WeaponSystem::OnPlayerSpawned(const Events::PlayerSpawned& e) +{ + if (e.PlayerID == -1) { + m_LocalPlayer = e.Player; } + return true; } bool WeaponSystem::OnInputCommand(const Events::InputCommand& e) { + // Only shoot client-side! + if (e.PlayerID != -1) { + return false; + } + + // Only shoot if the player is alive + if (!m_LocalPlayer.Valid()) { + return false; + } + if (e.Command == "PrimaryFire" && e.Value > 0) { Events::Shoot eShoot; - eShoot.shooter = e.PlayerID; + eShoot.Player = m_LocalPlayer; m_EventBroker->Publish(eShoot); } + return true; } -bool WeaponSystem::OnShoot(const Events::Shoot& e) { - //screen center, based on current resolution! + +bool WeaponSystem::OnShoot(const Events::Shoot& eShoot) { + // Screen center, based on current resolution! Rectangle screenResolution = m_Renderer->Resolution(); glm::vec2 centerScreen = glm::vec2(screenResolution.Width / 2, screenResolution.Height / 2); - m_EShootVector.push_back(std::make_pair(e.shooter, centerScreen)); + + // TODO: check if player has enough ammo and if weapon has a cooldown or not + + // Pick middle of screen + PickData pickData = m_Renderer->Pick(centerScreen); + if (pickData.Entity == EntityID_Invalid) { + return false; + } + + EntityWrapper player(m_World, pickData.Entity); + + // Only care about players being hit + if (!player.HasComponent("Player")) { + player = player.FirstParentWithComponent("Player"); + } + if (!player.Valid()) { + return false; + } + + // Check for friendly fire + EntityWrapper shooter = eShoot.Player; + if ((ComponentInfo::EnumType)player["Team"]["Team"] == (ComponentInfo::EnumType)shooter["Team"]["Team"]) { + return false; + } + + // TODO: Weapon damage calculations etc + Events::PlayerDamage ePlayerDamage; + ePlayerDamage.Player = player; + ePlayerDamage.Damage = 100; + m_EventBroker->Publish(ePlayerDamage); + return true; -} \ No newline at end of file +} From 2eaad2aa00c62607e8a963e995a72451d2c62dd0 Mon Sep 17 00:00:00 2001 From: stiffly Date: Sun, 24 Jan 2016 17:15:26 +0100 Subject: [PATCH 06/12] Client now responds to deleted entity and component in server --- include/Engine/Network/Client.h | 3 ++ include/Engine/Network/MessageType.h | 4 ++- include/Engine/Network/Server.h | 6 ++++ src/Engine/Network/Client.cpp | 49 ++++++++++++++++++++++++++-- src/Engine/Network/Server.cpp | 23 +++++++++++++ src/Game/Game.cpp | 2 +- 6 files changed, 83 insertions(+), 4 deletions(-) diff --git a/include/Engine/Network/Client.h b/include/Engine/Network/Client.h index 92d78f4a..e2ba8bc2 100644 --- a/include/Engine/Network/Client.h +++ b/include/Engine/Network/Client.h @@ -79,6 +79,8 @@ private: void parsePing(); void parseKick(); void parsePlayersSpawned(Packet& packet); + void parseEntityDeletion(Packet& packet); + void parseComponentDeletion(Packet& packet); void InterpolateFields(Packet & packet, const ComponentInfo & componentInfo, const EntityID & entityID, const std::string & componentType); void parseSnapshot(Packet& packet); void identifyPacketLoss(); @@ -92,6 +94,7 @@ private: // Returns if server EntityID exist in map bool serverClientMapsHasEntity(EntityID serverEntityID); void insertIntoServerClientMaps(EntityID serverEntityID, EntityID clientEntityID); + void deleteFromServerClientMaps(EntityID serverEntityID, EntityID clientEntityID); // Events EventBroker* m_EventBroker; diff --git a/include/Engine/Network/MessageType.h b/include/Engine/Network/MessageType.h index 13ac5e9d..894feea0 100644 --- a/include/Engine/Network/MessageType.h +++ b/include/Engine/Network/MessageType.h @@ -15,7 +15,9 @@ enum class MessageType PlayerConnected, BecomePlayer, Kick, - OnPlayerSpawned + OnPlayerSpawned, + EntityDeleted, + ComponentDeleted }; #endif diff --git a/include/Engine/Network/Server.h b/include/Engine/Network/Server.h index 35e6d855..00de3444 100644 --- a/include/Engine/Network/Server.h +++ b/include/Engine/Network/Server.h @@ -16,6 +16,8 @@ #include "Core/EPlayerDamage.h" #include "Network/EPlayerDisconnected.h" #include "Core/EPlayerSpawned.h" +#include "Core/EEntityDeleted.h" +#include "Core/EComponentDeleted.h" class Server : public Network { @@ -83,6 +85,10 @@ private: bool OnInputCommand(const Events::InputCommand& e); EventRelay m_EPlayerSpawned; bool OnPlayerSpawned(const Events::PlayerSpawned& e); + EventRelay m_EEntityDeleted; + bool OnEntityDeleted(const Events::EntityDeleted& e); + EventRelay m_EComponentDeleted; + bool OnComponentDeleted(const Events::ComponentDeleted& e); }; #endif diff --git a/src/Engine/Network/Client.cpp b/src/Engine/Network/Client.cpp index 2a4f531e..699a82aa 100644 --- a/src/Engine/Network/Client.cpp +++ b/src/Engine/Network/Client.cpp @@ -96,6 +96,12 @@ void Client::parseMessageType(Packet& packet) case MessageType::OnPlayerSpawned: parsePlayersSpawned(packet); break; + case MessageType::EntityDeleted: + parseEntityDeletion(packet); + break; + case MessageType::ComponentDeleted: + parseComponentDeletion(packet); + break; default: break; } @@ -142,6 +148,25 @@ void Client::parsePlayersSpawned(Packet& packet) m_EventBroker->Publish(e); } +void Client::parseEntityDeletion(Packet & packet) +{ + EntityID entityToDelete = packet.ReadPrimitive(); + EntityID localEntity = m_ServerIDToClientID.at(entityToDelete); + if (m_World->ValidEntity(localEntity)) { + m_World->DeleteEntity(localEntity); + deleteFromServerClientMaps(entityToDelete, localEntity); + } +} + +void Client::parseComponentDeletion(Packet & packet) +{ + EntityID entity = packet.ReadPrimitive(); + std::string componentType = packet.ReadString(); + if (m_World->HasComponent(entity, componentType)) { + m_World->DeleteComponent(m_ServerIDToClientID.at(entity), componentType); + } +} + // Fields with strings will not work right now void Client::InterpolateFields(Packet& packet, const ComponentInfo& componentInfo, const EntityID& entityID, const std::string& componentType) { @@ -370,12 +395,26 @@ void Client::becomePlayer() bool Client::clientServerMapsHasEntity(EntityID clientEntityID) { - return m_ClientIDToServerID.find(clientEntityID) != m_ClientIDToServerID.end(); + if (m_ClientIDToServerID.find(clientEntityID) != m_ClientIDToServerID.end()) { + if (m_World->ValidEntity(clientEntityID)) { + return true; + } + EntityID serverEntityID = m_ClientIDToServerID.at(clientEntityID); + deleteFromServerClientMaps(serverEntityID, clientEntityID); + } + return false; } bool Client::serverClientMapsHasEntity(EntityID serverEntityID) { - return m_ServerIDToClientID.find(serverEntityID) != m_ServerIDToClientID.end(); + if (m_ServerIDToClientID.find(serverEntityID) != m_ServerIDToClientID.end()) { + EntityID localEntityID = m_ServerIDToClientID.at(serverEntityID); + if (m_World->ValidEntity(localEntityID)) { + return true; + } + deleteFromServerClientMaps(serverEntityID, localEntityID); + } + return false; } void Client::insertIntoServerClientMaps(EntityID serverEntityID, EntityID clientEntityID) @@ -384,3 +423,9 @@ void Client::insertIntoServerClientMaps(EntityID serverEntityID, EntityID client m_ClientIDToServerID.insert(std::make_pair(clientEntityID, serverEntityID)); } + +void Client::deleteFromServerClientMaps(EntityID serverEntityID, EntityID clientEntityID) +{ + m_ServerIDToClientID.erase(serverEntityID); + m_ClientIDToServerID.erase(clientEntityID); +} diff --git a/src/Engine/Network/Server.cpp b/src/Engine/Network/Server.cpp index 98774b99..d8064c3a 100644 --- a/src/Engine/Network/Server.cpp +++ b/src/Engine/Network/Server.cpp @@ -21,6 +21,8 @@ void Server::Start(World* world, EventBroker* eventBroker) // Subscribe to events EVENT_SUBSCRIBE_MEMBER(m_EInputCommand, &Server::OnInputCommand); EVENT_SUBSCRIBE_MEMBER(m_EPlayerSpawned, &Server::OnPlayerSpawned); + EVENT_SUBSCRIBE_MEMBER(m_EEntityDeleted, &Server::OnEntityDeleted); + EVENT_SUBSCRIBE_MEMBER(m_EComponentDeleted, &Server::OnComponentDeleted); for (size_t i = 0; i < m_MaxConnections; i++) { m_PlayerDefinitions[i].StopTime = std::clock(); } @@ -465,3 +467,24 @@ bool Server::OnPlayerSpawned(const Events::PlayerSpawned & e) send(e.PlayerID, packet); return false; } + +bool Server::OnEntityDeleted(const Events::EntityDeleted & e) +{ + if (!e.Cascaded) { + Packet packet = Packet(MessageType::EntityDeleted); + packet.WritePrimitive(e.DeletedEntity); + broadcast(packet); + } + return false; +} + +bool Server::OnComponentDeleted(const Events::ComponentDeleted & e) +{ + if (!e.Cascaded) { + Packet packet = Packet(MessageType::ComponentDeleted); + packet.WritePrimitive(e.Entity); + packet.WriteString(e.ComponentType); + broadcast(packet); + } + return false; +} diff --git a/src/Game/Game.cpp b/src/Game/Game.cpp index 5de61b8c..ef51aca6 100644 --- a/src/Game/Game.cpp +++ b/src/Game/Game.cpp @@ -77,7 +77,7 @@ Game::Game(int argc, char* argv[]) // All systems with orderlevel 0 will be updated first. unsigned int updateOrderLevel = 0; m_SystemPipeline->AddSystem(updateOrderLevel); - m_SystemPipeline->AddSystem(updateOrderLevel); + //m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); From 8d61632c26d3f3df578bea005cd019e3f3824ea7 Mon Sep 17 00:00:00 2001 From: stiffly Date: Sun, 24 Jan 2016 17:40:43 +0100 Subject: [PATCH 07/12] No longer spawns a f**king sphere. --- src/Engine/Network/Server.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/Engine/Network/Server.cpp b/src/Engine/Network/Server.cpp index d8064c3a..325ff845 100644 --- a/src/Engine/Network/Server.cpp +++ b/src/Engine/Network/Server.cpp @@ -409,14 +409,6 @@ void Server::createPlayer() for (PlayerID playerIndex = 0; playerIndex < m_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; } } From 9f3d887ac4e83e79ac19811bd8fbddd14a3feaf3 Mon Sep 17 00:00:00 2001 From: sippeangelo Date: Sun, 24 Jan 2016 18:37:36 +0100 Subject: [PATCH 08/12] Networking bugfixes --- resources/Schema/Entities/Player.xml | 7 ++----- src/Engine/Core/World.cpp | 5 +++++ src/Game/Systems/InterpolationSystem.cpp | 12 ++++++++---- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/resources/Schema/Entities/Player.xml b/resources/Schema/Entities/Player.xml index 4ac1d205..8d6b16a4 100644 --- a/resources/Schema/Entities/Player.xml +++ b/resources/Schema/Entities/Player.xml @@ -8,9 +8,7 @@ - - false - + 5 @@ -20,7 +18,7 @@ - + @@ -31,7 +29,6 @@ - diff --git a/src/Engine/Core/World.cpp b/src/Engine/Core/World.cpp index 97e3ba9f..0c4c9ce4 100644 --- a/src/Engine/Core/World.cpp +++ b/src/Engine/Core/World.cpp @@ -137,6 +137,11 @@ EntityID World::generateEntityID() void World::deleteEntityRecursive(EntityID entity, bool cascaded /*= false*/) { + // Don't attempt to delete entities that don't exist anyway + if (!ValidEntity(entity)) { + return; + } + if (m_EventBroker != nullptr) { Events::EntityDeleted e; e.DeletedEntity = entity; diff --git a/src/Game/Systems/InterpolationSystem.cpp b/src/Game/Systems/InterpolationSystem.cpp index 2b6e82f2..bfb6952a 100644 --- a/src/Game/Systems/InterpolationSystem.cpp +++ b/src/Game/Systems/InterpolationSystem.cpp @@ -12,6 +12,11 @@ InterpolationSystem::InterpolationSystem(World* world, EventBroker* eventBroker) void InterpolationSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& transform, double dt) { + // Don't interpolate entities that might already have been removed + if (!entity.Valid()) { + return; + } + if (m_NextTransform.find(transform.EntityID) != m_NextTransform.end()) { // Exists in map m_NextTransform[transform.EntityID].interpolationTime += dt; Transform sTransform = m_NextTransform[transform.EntityID]; @@ -31,11 +36,10 @@ void InterpolationSystem::UpdateComponent(EntityWrapper& entity, ComponentWrappe // Position glm::vec3 nextPosition = sTransform.Position; glm::vec3 currentPosition = static_cast(transform["Position"]); - // HACK: Hardcoded tolerance value for player position desync = 1 - if (isLocalPlayer && glm::length(nextPosition - currentPosition) < 1.f) { - return; + // HACK: Don't force position for players + if (!isLocalPlayer) { + (glm::vec3&)transform["Position"] += vectorInterpolation(currentPosition, nextPosition, sTransform.interpolationTime); } - (glm::vec3&)transform["Position"] += vectorInterpolation(currentPosition, nextPosition, sTransform.interpolationTime); // Orientation // Don't force orientation for players if (!isLocalPlayer) { From 0fb1dbcae1a7ca75b34e445432e82238cf8d3c7d Mon Sep 17 00:00:00 2001 From: sippeangelo Date: Sun, 24 Jan 2016 19:00:50 +0100 Subject: [PATCH 09/12] Client now has authority over its own absolute position and orientation until we have reliable input messaging --- include/Engine/Network/Client.h | 6 +++++- include/Engine/Network/MessageType.h | 3 ++- include/Engine/Network/Server.h | 1 + src/Engine/Network/Client.cpp | 31 +++++++++++++++++++++++++++- src/Engine/Network/Server.cpp | 23 +++++++++++++++++++++ 5 files changed, 61 insertions(+), 3 deletions(-) diff --git a/include/Engine/Network/Client.h b/include/Engine/Network/Client.h index e2ba8bc2..4f1baa67 100644 --- a/include/Engine/Network/Client.h +++ b/include/Engine/Network/Client.h @@ -50,6 +50,7 @@ private: PlayerID m_PlayerID = -1; EntityID m_ServerEntityID = std::numeric_limits::max(); bool m_IsConnected = false; + EntityWrapper m_LocalPlayer = EntityWrapper::Invalid; // Server Client Lookup map // Assumes that root node for client and server is EntityID 0. @@ -87,6 +88,7 @@ private: bool hasServerTimedOut(); EntityID createPlayer(); void sendInputCommands(); + void sendLocalPlayerTransform(); void becomePlayer(); // Mapping Logic // Returns if local EntityID exist in map @@ -100,8 +102,10 @@ private: EventBroker* m_EventBroker; EventRelay m_EInputCommand; bool OnInputCommand(const Events::InputCommand& e); - EventRelay m_EPlayeDamage; + EventRelay m_EPlayerDamage; bool OnPlayerDamage(const Events::PlayerDamage& e); + EventRelay m_EPlayerSpawned; + bool OnPlayerSpawned(const Events::PlayerSpawned& e); }; #endif diff --git a/include/Engine/Network/MessageType.h b/include/Engine/Network/MessageType.h index 894feea0..85f22649 100644 --- a/include/Engine/Network/MessageType.h +++ b/include/Engine/Network/MessageType.h @@ -17,7 +17,8 @@ enum class MessageType Kick, OnPlayerSpawned, EntityDeleted, - ComponentDeleted + ComponentDeleted, + PlayerTransform }; #endif diff --git a/include/Engine/Network/Server.h b/include/Engine/Network/Server.h index 00de3444..3ef0a0aa 100644 --- a/include/Engine/Network/Server.h +++ b/include/Engine/Network/Server.h @@ -89,6 +89,7 @@ private: bool OnEntityDeleted(const Events::EntityDeleted& e); EventRelay m_EComponentDeleted; bool OnComponentDeleted(const Events::ComponentDeleted& e); + void parsePlayerTransform(Packet& packet); }; #endif diff --git a/src/Engine/Network/Client.cpp b/src/Engine/Network/Client.cpp index 9b20ef00..3fd9217b 100644 --- a/src/Engine/Network/Client.cpp +++ b/src/Engine/Network/Client.cpp @@ -31,7 +31,8 @@ void Client::Start(World* world, EventBroker* eventBroker) // Subscribe to events EVENT_SUBSCRIBE_MEMBER(m_EInputCommand, &Client::OnInputCommand); - EVENT_SUBSCRIBE_MEMBER(m_EPlayeDamage, &Client::OnPlayerDamage); + EVENT_SUBSCRIBE_MEMBER(m_EPlayerDamage, &Client::OnPlayerDamage); + EVENT_SUBSCRIBE_MEMBER(m_EPlayerSpawned, &Client::OnPlayerSpawned); m_Socket.connect(m_ReceiverEndpoint); LOG_INFO("I am client. BIP BOP"); @@ -48,6 +49,7 @@ void Client::Update() sendInputCommands(); m_TimeSinceSentInputs = std::clock(); } + sendLocalPlayerTransform(); } Network::Update(); } @@ -342,6 +344,33 @@ bool Client::OnPlayerDamage(const Events::PlayerDamage & e) return false; } +bool Client::OnPlayerSpawned(const Events::PlayerSpawned& e) +{ + if (e.PlayerID == -1) { + m_LocalPlayer = e.Player; + } + return true; +} + +void Client::sendLocalPlayerTransform() +{ + if (!m_LocalPlayer.Valid()) { + return; + } + + ComponentWrapper cTransform = m_LocalPlayer["Transform"]; + glm::vec3& position = cTransform["Position"]; + glm::vec3& orientation = cTransform["Orientation"]; + Packet packet(MessageType::PlayerTransform, m_SendPacketID); + packet.WritePrimitive(position.x); + packet.WritePrimitive(position.y); + packet.WritePrimitive(position.z); + packet.WritePrimitive(orientation.x); + packet.WritePrimitive(orientation.y); + packet.WritePrimitive(orientation.z); + send(packet); +} + 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 ff3ca6d0..ff57efed 100644 --- a/src/Engine/Network/Server.cpp +++ b/src/Engine/Network/Server.cpp @@ -101,6 +101,9 @@ void Server::parseMessageType(Packet& packet) case MessageType::BecomePlayer: createPlayer(); break; + case MessageType::PlayerTransform: + parsePlayerTransform(packet); + break; default: break; } @@ -488,3 +491,23 @@ bool Server::OnComponentDeleted(const Events::ComponentDeleted & e) } return false; } + +void Server::parsePlayerTransform(Packet& packet) +{ + glm::vec3 position; + glm::vec3 orientation; + position.x = packet.ReadPrimitive(); + position.y = packet.ReadPrimitive(); + position.z = packet.ReadPrimitive(); + orientation.x = packet.ReadPrimitive(); + orientation.y = packet.ReadPrimitive(); + orientation.z = packet.ReadPrimitive(); + + PlayerID playerID = GetPlayerIDFromEndpoint(m_ReceiverEndpoint); + EntityWrapper player(m_World, m_PlayerDefinitions[playerID].EntityID); + + if (player.Valid()) { + player["Transform"]["Position"] = position; + player["Transform"]["Orientation"] = orientation; + } +} From d4797b0808cfc6ae98353d3f4451d9fc7c5b755a Mon Sep 17 00:00:00 2001 From: Tleety Date: Sun, 24 Jan 2016 21:08:01 +0100 Subject: [PATCH 10/12] Some entity files --- resources/Schema/Entities/CollidableCube.xml | 2 +- resources/Schema/Entities/GameMap.xml | 128 +++++++++++++++++++ resources/Schema/Entities/PointLight.xml | 16 +++ 3 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 resources/Schema/Entities/GameMap.xml create mode 100644 resources/Schema/Entities/PointLight.xml diff --git a/resources/Schema/Entities/CollidableCube.xml b/resources/Schema/Entities/CollidableCube.xml index ebba54be..fd800a8b 100644 --- a/resources/Schema/Entities/CollidableCube.xml +++ b/resources/Schema/Entities/CollidableCube.xml @@ -5,7 +5,7 @@ - Models/Core/UnitCube.obj + Models/Core/UnitCube.mesh diff --git a/resources/Schema/Entities/GameMap.xml b/resources/Schema/Entities/GameMap.xml new file mode 100644 index 00000000..8841e3c9 --- /dev/null +++ b/resources/Schema/Entities/GameMap.xml @@ -0,0 +1,128 @@ + + + + + + + + + + + + Models\MapVersion1.mesh + + + + + + + + + 2 + + + Models/DirectionalLightWidget.mesh + false + + + + + + + + + + + + + 8 + 2.7999999523162842 + + + + + + + + + + + 8 + 2.7999999523162842 + + + + + + + + + + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + diff --git a/resources/Schema/Entities/PointLight.xml b/resources/Schema/Entities/PointLight.xml new file mode 100644 index 00000000..64c02753 --- /dev/null +++ b/resources/Schema/Entities/PointLight.xml @@ -0,0 +1,16 @@ + + + + + + 8 + 2.7999999523162842 + + + + + + + + + From 382eff169fd20e2b562a7d1431f55bf65e008abd Mon Sep 17 00:00:00 2001 From: sippeangelo Date: Sun, 24 Jan 2016 21:20:43 +0100 Subject: [PATCH 11/12] Server refactoring to remove player dependency and lots of fixes. --- include/Engine/Network/Network.h | 1 - include/Engine/Network/PlayerDefinition.h | 3 +- include/Engine/Network/Server.h | 8 +- src/Engine/Network/Client.cpp | 14 +- src/Engine/Network/Server.cpp | 158 +++++++--------------- 5 files changed, 67 insertions(+), 117 deletions(-) diff --git a/include/Engine/Network/Network.h b/include/Engine/Network/Network.h index 480ac602..03fcc0f3 100644 --- a/include/Engine/Network/Network.h +++ b/include/Engine/Network/Network.h @@ -15,7 +15,6 @@ #define INPUTSIZE 4097 typedef unsigned int PlayerID; typedef unsigned int PacketID; -typedef unsigned int UserID; class Network { diff --git a/include/Engine/Network/PlayerDefinition.h b/include/Engine/Network/PlayerDefinition.h index 4b8b8e6e..863948b3 100644 --- a/include/Engine/Network/PlayerDefinition.h +++ b/include/Engine/Network/PlayerDefinition.h @@ -1,9 +1,10 @@ #ifndef PlayerDefinition_h__ #define PlayerDefinition_h__ #include +#include "../Core/Entity.h" struct PlayerDefinition { - int EntityID = -1; + ::EntityID EntityID = EntityID_Invalid; std::string Name = ""; boost::asio::ip::udp::endpoint Endpoint; unsigned int PacketID; diff --git a/include/Engine/Network/Server.h b/include/Engine/Network/Server.h index 3ef0a0aa..17029809 100644 --- a/include/Engine/Network/Server.h +++ b/include/Engine/Network/Server.h @@ -33,8 +33,7 @@ private: boost::asio::ip::udp::socket m_Socket; // Sending messages to client logic - PlayerDefinition m_PlayerDefinitions[8]; // - std::vector m_ConnectedUsers; + std::map m_ConnectedPlayers; char readBuffer[INPUTSIZE] = { 0 }; int bytesRead = 0; // time for previouse message @@ -45,6 +44,7 @@ private: int pingIntervalMs; int snapshotInterval; int checkTimeOutInterval = 100; + int m_NextPlayerID = 0; //Timers std::clock_t m_StartPingTime; @@ -60,7 +60,6 @@ private: // Private member functions int receive(char* data); void readFromClients(); - void send(Packet& packet, UserID user); void send(PlayerID player, Packet& packet); void send(Packet& packet); void broadcast(Packet& packet); @@ -68,7 +67,7 @@ private: void addChildrenToPacket(Packet& packet, EntityID entityID); void sendPing(); void checkForTimeOuts(); - void disconnect(UserID user); + void disconnect(PlayerID playerID); void parseMessageType(Packet& packet); void parseOnInputCommand(Packet& packet); void parseOnPlayerDamage(Packet& packet); @@ -77,7 +76,6 @@ private: void parseClientPing(); void parsePing(); void identifyPacketLoss(); - void createPlayer(); void kick(PlayerID player); PlayerID GetPlayerIDFromEndpoint(boost::asio::ip::udp::endpoint endpoint); // Debug event diff --git a/src/Engine/Network/Client.cpp b/src/Engine/Network/Client.cpp index 3fd9217b..e32afd57 100644 --- a/src/Engine/Network/Client.cpp +++ b/src/Engine/Network/Client.cpp @@ -153,10 +153,13 @@ void Client::parsePlayersSpawned(Packet& packet) void Client::parseEntityDeletion(Packet & packet) { EntityID entityToDelete = packet.ReadPrimitive(); - EntityID localEntity = m_ServerIDToClientID.at(entityToDelete); - if (m_World->ValidEntity(localEntity)) { - m_World->DeleteEntity(localEntity); - deleteFromServerClientMaps(entityToDelete, localEntity); + // TODO: What if an entity that didn't previously exist comes as a delete request and later comes in a delayed snapshot? + if (m_ServerIDToClientID.find(entityToDelete) != m_ServerIDToClientID.end()) { + EntityID localEntity = m_ServerIDToClientID.at(entityToDelete); + if (m_World->ValidEntity(localEntity)) { + m_World->DeleteEntity(localEntity); + deleteFromServerClientMaps(entityToDelete, localEntity); + } } } @@ -219,6 +222,9 @@ void Client::parseSnapshot(Packet& packet) if (componentType == "Transform") { // Interpolate only transform components InterpolateFields(packet, componentInfo, localEntityID, componentType); + } else if (componentType == "Physics" && m_World->HasComponent(localEntityID, "Player")) { + // HACK: Ignore velocity of physics + packet.ReadData(componentInfo.Stride); } else { // Set component values updateFields(packet, componentInfo, localEntityID, componentType); diff --git a/src/Engine/Network/Server.cpp b/src/Engine/Network/Server.cpp index 74e4a15c..a29f4f02 100644 --- a/src/Engine/Network/Server.cpp +++ b/src/Engine/Network/Server.cpp @@ -23,9 +23,6 @@ void Server::Start(World* world, EventBroker* eventBroker) EVENT_SUBSCRIBE_MEMBER(m_EPlayerSpawned, &Server::OnPlayerSpawned); EVENT_SUBSCRIBE_MEMBER(m_EEntityDeleted, &Server::OnEntityDeleted); EVENT_SUBSCRIBE_MEMBER(m_EComponentDeleted, &Server::OnComponentDeleted); - for (size_t i = 0; i < m_MaxConnections; i++) { - m_PlayerDefinitions[i].StopTime = std::clock(); - } LOG_INFO("I am Server. BIP BOP\n"); } @@ -98,9 +95,6 @@ void Server::parseMessageType(Packet& packet) case MessageType::OnPlayerDamage: parseOnPlayerDamage(packet); break; - case MessageType::BecomePlayer: - createPlayer(); - break; case MessageType::PlayerTransform: parsePlayerTransform(packet); break; @@ -124,31 +118,22 @@ int Server::receive(char * data) return length; } -void Server::send(Packet& packet, UserID user) -{ - int bytesSent = m_Socket.send_to( - boost::asio::buffer(packet.Data(), packet.Size()), - m_ConnectedUsers[user].Endpoint, - 0); - // Network Debug data - if (isReadingData) { - m_NetworkData.TotalDataSent += packet.Size(); - m_NetworkData.DataSentThisInterval += packet.Size(); - m_NetworkData.AmountOfMessagesSent++; - } -} - void Server::send(PlayerID player, Packet& packet) { - int bytesSent = m_Socket.send_to( - boost::asio::buffer(packet.Data(), packet.Size()), - m_PlayerDefinitions[player].Endpoint, - 0); - // Network Debug data - if (isReadingData) { - m_NetworkData.TotalDataSent += packet.Size(); - m_NetworkData.DataSentThisInterval += packet.Size(); - m_NetworkData.AmountOfMessagesSent++; + try { + int bytesSent = m_Socket.send_to( + boost::asio::buffer(packet.Data(), packet.Size()), + m_ConnectedPlayers[player].Endpoint, + 0); + // Network Debug data + if (isReadingData) { + m_NetworkData.TotalDataSent += packet.Size(); + m_NetworkData.DataSentThisInterval += packet.Size(); + m_NetworkData.AmountOfMessagesSent++; + } + } catch (const boost::system::system_error& e) { + // TODO: Clean up invalid endpoints out of m_ConnectedPlayers later + m_ConnectedPlayers[player].Endpoint = boost::asio::ip::udp::endpoint(); } } @@ -169,11 +154,9 @@ 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()) { - packet.ChangePacketID(m_ConnectedUsers[i].PacketID); - send(packet, i); - } + for (auto& kv : m_ConnectedPlayers) { + packet.ChangePacketID(kv.second.PacketID); + send(kv.first, packet); } } @@ -231,12 +214,12 @@ void Server::addChildrenToPacket(Packet & packet, EntityID entityID) void Server::sendPing() { // Prints connected players 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)); - } - } + //for (int i = 0; i < m_ConnectedPlayers.size(); i++) { + // if (m_ConnectedPlayers[i].Endpoint.address() != boost::asio::ip::address()) { + // int ping = 1000 * (m_ConnectedPlayers[i].StopTime - m_StartPingTime) / static_cast(CLOCKS_PER_SEC); + // LOG_INFO("Last packetID received %i: User %i's ping: %i", m_ConnectedPlayers[i].PacketID, i, std::abs(ping)); + // } + //} // Create ping message Packet packet(MessageType::Ping); packet.WriteString("Ping from server"); @@ -251,9 +234,9 @@ void Server::checkForTimeOuts() int startPing = 1000 * m_StartPingTime / static_cast(CLOCKS_PER_SEC); - 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 / + for (int i = 0; i < m_ConnectedPlayers.size(); i++) { + if (m_ConnectedPlayers[i].Endpoint.address() != boost::asio::ip::address()) { + int stopPing = 1000 * m_ConnectedPlayers[i].StopTime / static_cast(CLOCKS_PER_SEC); if (startPing > stopPing + m_TimeoutMs) { LOG_INFO("User %i timed out!", i); @@ -263,35 +246,24 @@ void Server::checkForTimeOuts() } } -void Server::disconnect(UserID user) +void Server::disconnect(PlayerID playerID) { //broadcast("A player disconnected"); - LOG_INFO("User %s disconnected/timed out", m_PlayerDefinitions[user].Name.c_str()); + LOG_INFO("User %s disconnected/timed out", m_ConnectedPlayers[playerID].Name.c_str()); // Remove enteties and stuff (When we can remove entity, remove it and tell clients to remove the copy they have) Events::PlayerDisconnected e; - e.Entity = m_PlayerDefinitions[user].EntityID; - e.PlayerID = user; + e.Entity = m_ConnectedPlayers[playerID].EntityID; + e.PlayerID = playerID; m_EventBroker->Publish(e); - m_PlayerDefinitions[user].Endpoint = boost::asio::ip::udp::endpoint(); - m_PlayerDefinitions[user].EntityID = -1; - m_PlayerDefinitions[user].Name = ""; - m_PlayerDefinitions[user].PacketID = 0; - m_ConnectedUsers.erase(m_ConnectedUsers.begin() + user); + m_ConnectedPlayers.erase(playerID); } void Server::parseOnInputCommand(Packet& packet) { PlayerID player = -1; // Check which player it was who sent the message - for (int i = 0; i < m_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()) { - player = i; - break; - } - } + player = GetPlayerIDFromEndpoint(m_ReceiverEndpoint); if (player != -1) { while (packet.DataReadSize() < packet.Size()) { Events::InputCommand e; @@ -320,9 +292,9 @@ void Server::parseConnect(Packet& packet) 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()) { + for (auto& kv : m_ConnectedPlayers) { + if (kv.second.Endpoint.address() == m_ReceiverEndpoint.address() && + kv.second.Endpoint.port() == m_ReceiverEndpoint.port()) { // Already connected return; } @@ -334,11 +306,11 @@ void Server::parseConnect(Packet& packet) pd.Name = packet.ReadString(); pd.PacketID = 0; pd.StopTime = std::clock(); - m_ConnectedUsers.push_back(pd); + m_ConnectedPlayers[m_NextPlayerID++] = pd; LOG_INFO("Spectator \"%s\" connected on IP: %s", pd.Name.c_str(), pd.Endpoint.address().to_string().c_str()); // Send a message to the player that connected - Packet connnectPacket(MessageType::Connect, m_ConnectedUsers[m_ConnectedUsers.size() - 1].PacketID); + Packet connnectPacket(MessageType::Connect, pd.PacketID); send(connnectPacket); // Send notification that a player has connected @@ -350,9 +322,10 @@ void Server::parseDisconnect() { LOG_INFO("%i: Parsing disconnect", m_PacketID); - for (int i = 0; i < m_ConnectedUsers.size(); i++) { - if (m_ConnectedUsers[i].Endpoint.address() == m_ReceiverEndpoint.address()) { - disconnect(i); + for (auto& kv : m_ConnectedPlayers) { + if (kv.second.Endpoint.address() == m_ReceiverEndpoint.address() && + kv.second.Endpoint.port() == m_ReceiverEndpoint.port()) { + disconnect(kv.first); break; } } @@ -366,16 +339,16 @@ void Server::parseClientPing() return; } // Return ping - Packet packet(MessageType::Ping, m_PlayerDefinitions[player].PacketID); + Packet packet(MessageType::Ping, m_ConnectedPlayers[player].PacketID); packet.WriteString("Ping received"); send(packet); } void Server::parsePing() { - for (int i = 0; i < m_ConnectedUsers.size(); i++) { - if (m_ConnectedUsers[i].Endpoint.address() == m_ReceiverEndpoint.address()) { - m_ConnectedUsers[i].StopTime = std::clock(); + for (int i = 0; i < m_ConnectedPlayers.size(); i++) { + if (m_ConnectedPlayers[i].Endpoint.address() == m_ReceiverEndpoint.address()) { + m_ConnectedPlayers[i].StopTime = std::clock(); break; } } @@ -390,35 +363,6 @@ void Server::identifyPacketLoss() } } -void Server::createPlayer() -{ - if (GetPlayerIDFromEndpoint(m_ReceiverEndpoint) != -1) { - // Already connected as player - LOG_WARNING("Already connected!"); - return; - } - UserID 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 (PlayerID playerIndex = 0; playerIndex < m_MaxConnections; playerIndex++) { - if (m_PlayerDefinitions[playerIndex].Endpoint.address() == boost::asio::ip::address()) { - m_PlayerDefinitions[playerIndex] = m_ConnectedUsers[userIndex]; - return; - } - } - LOG_WARNING("Server is full!"); - -} - void Server::kick(PlayerID player) { disconnect(player); @@ -428,10 +372,10 @@ void Server::kick(PlayerID player) PlayerID Server::GetPlayerIDFromEndpoint(boost::asio::ip::udp::endpoint endpoint) { - for (int i = 0; i < m_MaxConnections; i++) { - if (m_PlayerDefinitions[i].Endpoint.address() == endpoint.address() && - m_PlayerDefinitions[i].Endpoint.port() == endpoint.port()) { - return i; + for (auto& kv : m_ConnectedPlayers) { + if (kv.second.Endpoint.address() == endpoint.address() && + kv.second.Endpoint.port() == endpoint.port()) { + return kv.first; } } return -1; @@ -456,6 +400,8 @@ bool Server::OnInputCommand(const Events::InputCommand & e) bool Server::OnPlayerSpawned(const Events::PlayerSpawned & e) { + m_ConnectedPlayers[e.PlayerID].EntityID = e.Player.ID; + Packet packet = Packet(MessageType::OnPlayerSpawned); packet.WritePrimitive(e.Player.ID); packet.WritePrimitive(e.Spawner.ID); @@ -496,7 +442,7 @@ void Server::parsePlayerTransform(Packet& packet) orientation.z = packet.ReadPrimitive(); PlayerID playerID = GetPlayerIDFromEndpoint(m_ReceiverEndpoint); - EntityWrapper player(m_World, m_PlayerDefinitions[playerID].EntityID); + EntityWrapper player(m_World, m_ConnectedPlayers.at(playerID).EntityID); if (player.Valid()) { player["Transform"]["Position"] = position; From 47d2fb6a9bbb84a3dff41f29b662603b5c072e6e Mon Sep 17 00:00:00 2001 From: sippeangelo Date: Sun, 24 Jan 2016 22:20:42 +0100 Subject: [PATCH 12/12] Fixed wrong drawing function used in PickingPass --- src/Engine/Rendering/PickingPass.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Engine/Rendering/PickingPass.cpp b/src/Engine/Rendering/PickingPass.cpp index f063b344..350d471f 100644 --- a/src/Engine/Rendering/PickingPass.cpp +++ b/src/Engine/Rendering/PickingPass.cpp @@ -90,7 +90,7 @@ void PickingPass::Draw(RenderScene& scene) glBindVertexArray(modelJob->Model->VAO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, modelJob->Model->ElementBuffer); - glDrawElementsBaseVertex(GL_TRIANGLES, modelJob->EndIndex - modelJob->StartIndex + 1, GL_UNSIGNED_INT, nullptr, modelJob->StartIndex); + glDrawElements(GL_TRIANGLES, modelJob->EndIndex - modelJob->StartIndex + 1, GL_UNSIGNED_INT, (void*)(modelJob->StartIndex * sizeof(unsigned int))); } }