From d5647ce89ca445a09f608ff81048e5ade1346d9e Mon Sep 17 00:00:00 2001 From: sippeangelo Date: Tue, 9 Feb 2016 16:08:28 +0100 Subject: [PATCH] Working 1-snapshot interpolation --- include/Game/Systems/InterpolationSystem.h | 39 +++--- src/Engine/Network/Server.cpp | 2 +- src/Game/Game.cpp | 3 +- .../Network/MultiplayerSnapshotFilter.cpp | 6 +- src/Game/Systems/InterpolationSystem.cpp | 122 +++++++++++------- 5 files changed, 103 insertions(+), 69 deletions(-) diff --git a/include/Game/Systems/InterpolationSystem.h b/include/Game/Systems/InterpolationSystem.h index 5077ad92..758609c8 100644 --- a/include/Game/Systems/InterpolationSystem.h +++ b/include/Game/Systems/InterpolationSystem.h @@ -16,26 +16,39 @@ #include "Network/EInterpolate.h" -class InterpolationSystem : public PureSystem +class InterpolationSystem : public ImpureSystem { public: InterpolationSystem(SystemParams params); ~InterpolationSystem() { } - virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& transform, double dt) override; + virtual void Update(double dt) override; private: - struct Transform + template + struct Interpolation { - glm::vec3 Position; - glm::vec3 Scale; - glm::quat Orientation; - float interpolationTime; + Interpolation(const ComponentWrapper& Component, const std::string& Field, const T& Start, const T& Goal) + : Component(Component) + , Field(Field) + , Start(Start) + , Goal(Goal) + { } + + ComponentWrapper Component; + std::string Field; + T Start; + T Goal; + double Alpha = 0.0; }; - std::unordered_map m_NextTransform; - std::unordered_map m_LastReceivedTransform; - EntityWrapper m_LocalPlayer = EntityWrapper::Invalid; + float m_SnapshotInterval; + std::unordered_map> m_InterpolatePosition; + std::unordered_map> m_InterpolateOrientation; + std::unordered_map> m_InterpolateVelocity; + + EventRelay m_EInterpolate; + bool InterpolationSystem::OnInterpolate(Events::Interpolate& e); template T vectorInterpolation(T prev, T next, double currentTime) @@ -44,12 +57,6 @@ private: T vector = difference * (static_cast(currentTime) / m_SnapshotInterval); return vector; } - float m_SnapshotInterval; - - EventRelay m_EInterpolate; - bool InterpolationSystem::OnInterpolate(Events::Interpolate& e); - EventRelay m_EPlayerSpawned; - bool OnPlayerSpawned(Events::PlayerSpawned& e); }; #endif diff --git a/src/Engine/Network/Server.cpp b/src/Engine/Network/Server.cpp index 9502c01d..b0003539 100644 --- a/src/Engine/Network/Server.cpp +++ b/src/Engine/Network/Server.cpp @@ -240,7 +240,7 @@ void Server::checkForTimeOuts() double stopPing = 1000 * m_ConnectedPlayers[i].StopTime / static_cast(CLOCKS_PER_SEC); if (startPing > stopPing + m_TimeoutMs) { - LOG_INFO("User %i timed out!", i); + //LOG_INFO("User %i timed out!", i); //disconnect(i); } } diff --git a/src/Game/Game.cpp b/src/Game/Game.cpp index 982ce647..38468e47 100644 --- a/src/Game/Game.cpp +++ b/src/Game/Game.cpp @@ -95,11 +95,12 @@ Game::Game(int argc, char* argv[]) // All systems with orderlevel 0 will be updated first. unsigned int updateOrderLevel = 0; + m_SystemPipeline->AddSystem(updateOrderLevel); + ++updateOrderLevel; m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); - m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel, m_Renderer); diff --git a/src/Game/Network/MultiplayerSnapshotFilter.cpp b/src/Game/Network/MultiplayerSnapshotFilter.cpp index 426b24d2..709ce6b1 100644 --- a/src/Game/Network/MultiplayerSnapshotFilter.cpp +++ b/src/Game/Network/MultiplayerSnapshotFilter.cpp @@ -12,7 +12,11 @@ bool MultiplayerSnapshotFilter::FilterComponent(EntityWrapper entity, SharedComp return false; } - if (component.Info.Name == "Transform") { + if (component.Info.Name == "Physics") { + return false; + } + + if (component.Info.Name == "Transform" || component.Info.Name == "Physics") { m_EventBroker->Publish(Events::Interpolate(entity, component)); return false; } diff --git a/src/Game/Systems/InterpolationSystem.cpp b/src/Game/Systems/InterpolationSystem.cpp index 6c57c2b6..430c01c1 100644 --- a/src/Game/Systems/InterpolationSystem.cpp +++ b/src/Game/Systems/InterpolationSystem.cpp @@ -2,74 +2,96 @@ InterpolationSystem::InterpolationSystem(SystemParams params) : System(params) - , PureSystem("Transform") { ConfigFile* config = ResourceManager::Load("Config.ini"); m_SnapshotInterval = config->Get("Networking.SnapshotInterval", 0.05f); EVENT_SUBSCRIBE_MEMBER(m_EInterpolate, &InterpolationSystem::OnInterpolate); - EVENT_SUBSCRIBE_MEMBER(m_EPlayerSpawned, &InterpolationSystem::OnPlayerSpawned); } -void InterpolationSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& transform, double dt) +void InterpolationSystem::Update(double dt) { - // Don't interpolate entities that might already have been removed - if (!entity.Valid()) { - return; + // Position + for (auto& kv : m_InterpolatePosition) { + EntityWrapper entity = kv.first; + if (!entity.Valid()) { + continue; + } + auto& iPosition = kv.second; + glm::vec3& position = iPosition.Component[iPosition.Field]; + + iPosition.Alpha += dt; + float alpha = glm::min(iPosition.Alpha / m_SnapshotInterval, 1.0); + position = iPosition.Start + ((iPosition.Goal - iPosition.Start) * alpha); } - //return; - if (m_NextTransform.find(transform.EntityID) != m_NextTransform.end()) { // Exists in map - m_NextTransform[transform.EntityID].interpolationTime += static_cast(dt); - Transform sTransform = m_NextTransform[transform.EntityID]; - float time = sTransform.interpolationTime; - if (time > m_SnapshotInterval) { - if (m_LastReceivedTransform.find(transform.EntityID) != m_LastReceivedTransform.end()) { - m_NextTransform[transform.EntityID] = m_LastReceivedTransform[transform.EntityID]; - m_NextTransform[transform.EntityID].interpolationTime = time - m_SnapshotInterval; - sTransform = m_NextTransform[transform.EntityID]; - m_LastReceivedTransform.erase(transform.EntityID); - } else { - m_NextTransform.erase(transform.EntityID); - } + // Orientation + for (auto& kv : m_InterpolateOrientation) { + EntityWrapper entity = kv.first; + if (!entity.Valid()) { + continue; } - 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, glm::max(sTransform.interpolationTime / m_SnapshotInterval, 1.f))); - // Scale - glm::vec3 nextScale = sTransform.Scale; - glm::vec3 currentScale = static_cast(transform["Scale"]); - (glm::vec3&)transform["Scale"] += vectorInterpolation(currentScale, nextScale, sTransform.interpolationTime); - } - } -} + auto& iOrientation = kv.second; + glm::vec3& orientation = iOrientation.Component[iOrientation.Field]; -bool InterpolationSystem::OnPlayerSpawned(Events::PlayerSpawned& e) -{ - m_LocalPlayer = e.Player; - return true; + iOrientation.Alpha += dt / m_SnapshotInterval; + iOrientation.Alpha = glm::min(iOrientation.Alpha, 1.0); + orientation = glm::eulerAngles(glm::slerp(iOrientation.Start, iOrientation.Goal, (float)iOrientation.Alpha)); + } + + // Velocity + for (auto& kv : m_InterpolateVelocity) { + EntityWrapper entity = kv.first; + if (!entity.Valid()) { + continue; + } + auto& iVelocity = kv.second; + glm::vec3& position = iVelocity.Component[iVelocity.Field]; + + iVelocity.Alpha += dt; + float alpha = glm::min(iVelocity.Alpha / m_SnapshotInterval, 1.0); + position = iVelocity.Start + ((iVelocity.Goal - iVelocity.Start) * alpha); + } } bool InterpolationSystem::OnInterpolate(Events::Interpolate& e) { - // TODO: Make this work for arbitrary component types if (e.Component.Info.Name == "Transform") { - Transform transform; - transform.Position = e.Component["Position"]; - transform.Orientation = glm::quat((glm::vec3)e.Component["Orientation"]); - transform.Scale = e.Component["Scale"]; - transform.interpolationTime = 0.0f; + auto cTransform = e.Entity["Transform"]; - if (m_NextTransform.find(e.Entity.ID) != m_NextTransform.end()) { // Did exist - m_LastReceivedTransform[e.Entity.ID] = transform; - } else { // Did not - m_NextTransform[e.Entity.ID] = transform; + // Position + Interpolation iPosition( + cTransform, + "Position", + cTransform["Position"], + e.Component["Position"] + ); + m_InterpolatePosition.erase(e.Entity); + m_InterpolatePosition.insert(std::make_pair(e.Entity, iPosition)); + + // Orientation + Interpolation iOrientation( + cTransform, + "Orientation", + glm::quat((glm::vec3&)cTransform["Orientation"]), + glm::quat((glm::vec3&)e.Component["Orientation"]) + ); + m_InterpolateOrientation.erase(e.Entity); + m_InterpolateOrientation.insert(std::make_pair(e.Entity, iOrientation)); + } else if (e.Component.Info.Name == "Physics") { + auto cPhysics = e.Entity["Physics"]; + if (!e.Entity.HasComponent("Player")) { + return false; } + + // Velocity + Interpolation iVelocity( + cPhysics, + "Velocity", + cPhysics["Velocity"], + e.Component["Velocity"] + ); + m_InterpolateVelocity.erase(e.Entity); + m_InterpolateVelocity.insert(std::make_pair(e.Entity, iVelocity)); } return true;