Working 1-snapshot interpolation
This commit is contained in:
@@ -16,26 +16,39 @@
|
|||||||
|
|
||||||
#include "Network/EInterpolate.h"
|
#include "Network/EInterpolate.h"
|
||||||
|
|
||||||
class InterpolationSystem : public PureSystem
|
class InterpolationSystem : public ImpureSystem
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
InterpolationSystem(SystemParams params);
|
InterpolationSystem(SystemParams params);
|
||||||
~InterpolationSystem() { }
|
~InterpolationSystem() { }
|
||||||
|
|
||||||
virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& transform, double dt) override;
|
virtual void Update(double dt) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Transform
|
template <typename T>
|
||||||
|
struct Interpolation
|
||||||
{
|
{
|
||||||
glm::vec3 Position;
|
Interpolation(const ComponentWrapper& Component, const std::string& Field, const T& Start, const T& Goal)
|
||||||
glm::vec3 Scale;
|
: Component(Component)
|
||||||
glm::quat Orientation;
|
, Field(Field)
|
||||||
float interpolationTime;
|
, Start(Start)
|
||||||
|
, Goal(Goal)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
ComponentWrapper Component;
|
||||||
|
std::string Field;
|
||||||
|
T Start;
|
||||||
|
T Goal;
|
||||||
|
double Alpha = 0.0;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unordered_map<EntityID, Transform> m_NextTransform;
|
float m_SnapshotInterval;
|
||||||
std::unordered_map<EntityID, Transform> m_LastReceivedTransform;
|
std::unordered_map<EntityWrapper, Interpolation<glm::vec3>> m_InterpolatePosition;
|
||||||
EntityWrapper m_LocalPlayer = EntityWrapper::Invalid;
|
std::unordered_map<EntityWrapper, Interpolation<glm::quat>> m_InterpolateOrientation;
|
||||||
|
std::unordered_map<EntityWrapper, Interpolation<glm::vec3>> m_InterpolateVelocity;
|
||||||
|
|
||||||
|
EventRelay<InterpolationSystem, Events::Interpolate> m_EInterpolate;
|
||||||
|
bool InterpolationSystem::OnInterpolate(Events::Interpolate& e);
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T vectorInterpolation(T prev, T next, double currentTime)
|
T vectorInterpolation(T prev, T next, double currentTime)
|
||||||
@@ -44,12 +57,6 @@ private:
|
|||||||
T vector = difference * (static_cast<float>(currentTime) / m_SnapshotInterval);
|
T vector = difference * (static_cast<float>(currentTime) / m_SnapshotInterval);
|
||||||
return vector;
|
return vector;
|
||||||
}
|
}
|
||||||
float m_SnapshotInterval;
|
|
||||||
|
|
||||||
EventRelay<InterpolationSystem, Events::Interpolate> m_EInterpolate;
|
|
||||||
bool InterpolationSystem::OnInterpolate(Events::Interpolate& e);
|
|
||||||
EventRelay<InterpolationSystem, Events::PlayerSpawned> m_EPlayerSpawned;
|
|
||||||
bool OnPlayerSpawned(Events::PlayerSpawned& e);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -240,7 +240,7 @@ void Server::checkForTimeOuts()
|
|||||||
double stopPing = 1000 * m_ConnectedPlayers[i].StopTime /
|
double stopPing = 1000 * m_ConnectedPlayers[i].StopTime /
|
||||||
static_cast<double>(CLOCKS_PER_SEC);
|
static_cast<double>(CLOCKS_PER_SEC);
|
||||||
if (startPing > stopPing + m_TimeoutMs) {
|
if (startPing > stopPing + m_TimeoutMs) {
|
||||||
LOG_INFO("User %i timed out!", i);
|
//LOG_INFO("User %i timed out!", i);
|
||||||
//disconnect(i);
|
//disconnect(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -95,11 +95,12 @@ Game::Game(int argc, char* argv[])
|
|||||||
|
|
||||||
// All systems with orderlevel 0 will be updated first.
|
// All systems with orderlevel 0 will be updated first.
|
||||||
unsigned int updateOrderLevel = 0;
|
unsigned int updateOrderLevel = 0;
|
||||||
|
m_SystemPipeline->AddSystem<InterpolationSystem>(updateOrderLevel);
|
||||||
|
++updateOrderLevel;
|
||||||
m_SystemPipeline->AddSystem<RaptorCopterSystem>(updateOrderLevel);
|
m_SystemPipeline->AddSystem<RaptorCopterSystem>(updateOrderLevel);
|
||||||
m_SystemPipeline->AddSystem<ExplosionEffectSystem>(updateOrderLevel);
|
m_SystemPipeline->AddSystem<ExplosionEffectSystem>(updateOrderLevel);
|
||||||
m_SystemPipeline->AddSystem<HealthSystem>(updateOrderLevel);
|
m_SystemPipeline->AddSystem<HealthSystem>(updateOrderLevel);
|
||||||
m_SystemPipeline->AddSystem<PlayerMovementSystem>(updateOrderLevel);
|
m_SystemPipeline->AddSystem<PlayerMovementSystem>(updateOrderLevel);
|
||||||
m_SystemPipeline->AddSystem<InterpolationSystem>(updateOrderLevel);
|
|
||||||
m_SystemPipeline->AddSystem<SpawnerSystem>(updateOrderLevel);
|
m_SystemPipeline->AddSystem<SpawnerSystem>(updateOrderLevel);
|
||||||
m_SystemPipeline->AddSystem<PlayerSpawnSystem>(updateOrderLevel);
|
m_SystemPipeline->AddSystem<PlayerSpawnSystem>(updateOrderLevel);
|
||||||
m_SystemPipeline->AddSystem<WeaponSystem>(updateOrderLevel, m_Renderer);
|
m_SystemPipeline->AddSystem<WeaponSystem>(updateOrderLevel, m_Renderer);
|
||||||
|
|||||||
@@ -12,7 +12,11 @@ bool MultiplayerSnapshotFilter::FilterComponent(EntityWrapper entity, SharedComp
|
|||||||
return false;
|
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));
|
m_EventBroker->Publish(Events::Interpolate(entity, component));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,74 +2,96 @@
|
|||||||
|
|
||||||
InterpolationSystem::InterpolationSystem(SystemParams params)
|
InterpolationSystem::InterpolationSystem(SystemParams params)
|
||||||
: System(params)
|
: System(params)
|
||||||
, PureSystem("Transform")
|
|
||||||
{
|
{
|
||||||
ConfigFile* config = ResourceManager::Load<ConfigFile>("Config.ini");
|
ConfigFile* config = ResourceManager::Load<ConfigFile>("Config.ini");
|
||||||
m_SnapshotInterval = config->Get<float>("Networking.SnapshotInterval", 0.05f);
|
m_SnapshotInterval = config->Get<float>("Networking.SnapshotInterval", 0.05f);
|
||||||
EVENT_SUBSCRIBE_MEMBER(m_EInterpolate, &InterpolationSystem::OnInterpolate);
|
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
|
// Position
|
||||||
if (!entity.Valid()) {
|
for (auto& kv : m_InterpolatePosition) {
|
||||||
return;
|
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;
|
// Orientation
|
||||||
if (m_NextTransform.find(transform.EntityID) != m_NextTransform.end()) { // Exists in map
|
for (auto& kv : m_InterpolateOrientation) {
|
||||||
m_NextTransform[transform.EntityID].interpolationTime += static_cast<float>(dt);
|
EntityWrapper entity = kv.first;
|
||||||
Transform sTransform = m_NextTransform[transform.EntityID];
|
if (!entity.Valid()) {
|
||||||
float time = sTransform.interpolationTime;
|
continue;
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (transform.Info.Name == "Transform") {
|
auto& iOrientation = kv.second;
|
||||||
// Position
|
glm::vec3& orientation = iOrientation.Component[iOrientation.Field];
|
||||||
glm::vec3 nextPosition = sTransform.Position;
|
|
||||||
glm::vec3 currentPosition = static_cast<glm::vec3>(transform["Position"]);
|
|
||||||
(glm::vec3&)transform["Position"] += vectorInterpolation<glm::vec3>(currentPosition, nextPosition, sTransform.interpolationTime);
|
|
||||||
// Orientation
|
|
||||||
glm::quat nextOrientation = sTransform.Orientation;
|
|
||||||
glm::quat currentOrientation = glm::quat(static_cast<glm::vec3>(transform["Orientation"]));
|
|
||||||
(glm::vec3&)transform["Orientation"] = glm::eulerAngles(glm::slerp<float>(currentOrientation, nextOrientation, glm::max(sTransform.interpolationTime / m_SnapshotInterval, 1.f)));
|
|
||||||
// Scale
|
|
||||||
glm::vec3 nextScale = sTransform.Scale;
|
|
||||||
glm::vec3 currentScale = static_cast<glm::vec3>(transform["Scale"]);
|
|
||||||
(glm::vec3&)transform["Scale"] += vectorInterpolation<glm::vec3>(currentScale, nextScale, sTransform.interpolationTime);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool InterpolationSystem::OnPlayerSpawned(Events::PlayerSpawned& e)
|
iOrientation.Alpha += dt / m_SnapshotInterval;
|
||||||
{
|
iOrientation.Alpha = glm::min(iOrientation.Alpha, 1.0);
|
||||||
m_LocalPlayer = e.Player;
|
orientation = glm::eulerAngles(glm::slerp(iOrientation.Start, iOrientation.Goal, (float)iOrientation.Alpha));
|
||||||
return true;
|
}
|
||||||
|
|
||||||
|
// 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)
|
bool InterpolationSystem::OnInterpolate(Events::Interpolate& e)
|
||||||
{
|
{
|
||||||
// TODO: Make this work for arbitrary component types
|
|
||||||
if (e.Component.Info.Name == "Transform") {
|
if (e.Component.Info.Name == "Transform") {
|
||||||
Transform transform;
|
auto cTransform = e.Entity["Transform"];
|
||||||
transform.Position = e.Component["Position"];
|
|
||||||
transform.Orientation = glm::quat((glm::vec3)e.Component["Orientation"]);
|
|
||||||
transform.Scale = e.Component["Scale"];
|
|
||||||
transform.interpolationTime = 0.0f;
|
|
||||||
|
|
||||||
if (m_NextTransform.find(e.Entity.ID) != m_NextTransform.end()) { // Did exist
|
// Position
|
||||||
m_LastReceivedTransform[e.Entity.ID] = transform;
|
Interpolation<glm::vec3> iPosition(
|
||||||
} else { // Did not
|
cTransform,
|
||||||
m_NextTransform[e.Entity.ID] = transform;
|
"Position",
|
||||||
|
cTransform["Position"],
|
||||||
|
e.Component["Position"]
|
||||||
|
);
|
||||||
|
m_InterpolatePosition.erase(e.Entity);
|
||||||
|
m_InterpolatePosition.insert(std::make_pair(e.Entity, iPosition));
|
||||||
|
|
||||||
|
// Orientation
|
||||||
|
Interpolation<glm::quat> 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<glm::vec3> iVelocity(
|
||||||
|
cPhysics,
|
||||||
|
"Velocity",
|
||||||
|
cPhysics["Velocity"],
|
||||||
|
e.Component["Velocity"]
|
||||||
|
);
|
||||||
|
m_InterpolateVelocity.erase(e.Entity);
|
||||||
|
m_InterpolateVelocity.insert(std::make_pair(e.Entity, iVelocity));
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
Reference in New Issue
Block a user