Merge remote-tracking branch 'origin/master' into ShootEvent
This commit is contained in:
@@ -8,7 +8,7 @@
|
|||||||
class CollidableOctreeSystem : public ImpureSystem, public PureSystem
|
class CollidableOctreeSystem : public ImpureSystem, public PureSystem
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CollidableOctreeSystem(EventBroker* eventBroker, Octree* octree)
|
CollidableOctreeSystem(EventBroker* eventBroker, Octree<AABB>* octree)
|
||||||
: System(eventBroker)
|
: System(eventBroker)
|
||||||
, PureSystem("Collidable")
|
, PureSystem("Collidable")
|
||||||
, m_Octree(octree)
|
, m_Octree(octree)
|
||||||
@@ -18,7 +18,7 @@ public:
|
|||||||
virtual void UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& component, double dt) override;
|
virtual void UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& component, double dt) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Octree* m_Octree;
|
Octree<AABB>* m_Octree;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
class CollisionSystem : public PureSystem
|
class CollisionSystem : public PureSystem
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CollisionSystem(EventBroker* eventBroker, Octree* octree)
|
CollisionSystem(EventBroker* eventBroker, Octree<AABB>* octree)
|
||||||
: System(eventBroker)
|
: System(eventBroker)
|
||||||
, PureSystem("Collidable")
|
, PureSystem("Collidable")
|
||||||
, m_Octree(octree)
|
, m_Octree(octree)
|
||||||
@@ -26,7 +26,7 @@ public:
|
|||||||
virtual void UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& component, double dt) override;
|
virtual void UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& component, double dt) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Octree* m_Octree;
|
Octree<AABB>* m_Octree;
|
||||||
bool zPress;
|
bool zPress;
|
||||||
|
|
||||||
EventRelay<CollisionSystem, Events::KeyUp> m_EKeyUp;
|
EventRelay<CollisionSystem, Events::KeyUp> m_EKeyUp;
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ class AABB;
|
|||||||
class TriggerSystem : public PureSystem
|
class TriggerSystem : public PureSystem
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TriggerSystem(EventBroker* eventBroker, Octree* octree)
|
TriggerSystem(EventBroker* eventBroker, Octree<AABB>* octree)
|
||||||
: System(eventBroker)
|
: System(eventBroker)
|
||||||
, PureSystem("Trigger")
|
, PureSystem("Trigger")
|
||||||
, m_Octree(octree)
|
, m_Octree(octree)
|
||||||
@@ -27,7 +27,7 @@ public:
|
|||||||
virtual void UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& component, double dt) override;
|
virtual void UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& component, double dt) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Octree* m_Octree;
|
Octree<AABB>* m_Octree;
|
||||||
std::unordered_map<EntityID, std::unordered_set<EntityID>> m_EntitiesTouchingTrigger;
|
std::unordered_map<EntityID, std::unordered_set<EntityID>> m_EntitiesTouchingTrigger;
|
||||||
std::unordered_map<EntityID, std::unordered_set<EntityID>> m_EntitiesCompletelyInTrigger;
|
std::unordered_map<EntityID, std::unordered_set<EntityID>> m_EntitiesCompletelyInTrigger;
|
||||||
|
|
||||||
|
|||||||
+193
-65
@@ -1,19 +1,27 @@
|
|||||||
#ifndef Octree_h__
|
#ifndef Octree_h__
|
||||||
#define Octree_h__
|
#define Octree_h__
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
#include "../Common.h"
|
#include "../Common.h"
|
||||||
#include "AABB.h"
|
#include "AABB.h"
|
||||||
|
|
||||||
|
//Fwd declarations.
|
||||||
class Ray;
|
class Ray;
|
||||||
|
|
||||||
|
namespace OctSpace
|
||||||
|
{
|
||||||
|
struct Output;
|
||||||
|
struct ContainedObject;
|
||||||
|
struct Child;
|
||||||
|
}
|
||||||
|
|
||||||
|
//T needs to be AABB, or inherit from AABB.
|
||||||
|
//T also needs to have a default constructor.
|
||||||
|
template<typename T>
|
||||||
class Octree
|
class Octree
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
struct Output
|
|
||||||
{
|
|
||||||
float CollideDistance;
|
|
||||||
};
|
|
||||||
|
|
||||||
Octree() = delete;
|
Octree() = delete;
|
||||||
~Octree();
|
~Octree();
|
||||||
//For the root Octree, [octreeBounds] should be a box containing the entire level.
|
//For the root Octree, [octreeBounds] should be a box containing the entire level.
|
||||||
@@ -25,81 +33,201 @@ public:
|
|||||||
Octree(const Octree&& other) = delete;
|
Octree(const Octree&& other) = delete;
|
||||||
Octree& operator= (const Octree& other) = delete;
|
Octree& operator= (const Octree& other) = delete;
|
||||||
//Add a dynamic object (one that moves around) into the tree.
|
//Add a dynamic object (one that moves around) into the tree.
|
||||||
void AddDynamicObject(const AABB& box);
|
void AddDynamicObject(const T& object);
|
||||||
//Add a static object (that does not move) into the tree.
|
//Add a static object (that does not move) into the tree.
|
||||||
void AddStaticObject(const AABB& box);
|
void AddStaticObject(const T& object);
|
||||||
//Get the boxes that are in the same area as the input [box], the boxes are put in [outBoxes].
|
//Get the objects that are in the same area as the input [box], the objects are put in [outObjects].
|
||||||
void BoxesInSameRegion(const AABB& box, std::vector<AABB>& outBoxes);
|
//The type Box must be AABB, or inherit from AABB.
|
||||||
|
template<typename Box>
|
||||||
|
void ObjectsInSameRegion(const Box& box, std::vector<T>& outObjects);
|
||||||
//Empty the tree of all objects, static and dynamic.
|
//Empty the tree of all objects, static and dynamic.
|
||||||
void ClearObjects();
|
void ClearObjects();
|
||||||
//Empty the tree of all dynamic objects. Static objects remain in the tree.
|
//Empty the tree of all dynamic objects. Static objects remain in the tree.
|
||||||
void ClearDynamicObjects();
|
void ClearDynamicObjects();
|
||||||
|
|
||||||
//Returns true if the ray collides with something in the tree. Result is written to [data].
|
//Returns true if the ray collides with something in the tree. Result is written to [data].
|
||||||
bool RayCollides(const Ray& ray, Output& data);
|
bool RayCollides(const Ray& ray, OctSpace::Output& data);
|
||||||
//Returns true if the box collides with something in the tree.
|
//Returns true if the box collides with something in the tree.
|
||||||
//On collision with a box, that box is written to [outBoxIntersected].
|
//On collision with a box, that box is written to [outBoxIntersected].
|
||||||
//Note: More efficient than calling BoxesInSameRegion from outside and testing there.
|
//Note: More efficient than calling ObjectsInSameRegion from outside and testing there.
|
||||||
bool BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected);
|
bool BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Child; //Fwd declaration;
|
OctSpace::Child* m_Root;
|
||||||
struct ContainedObject
|
std::vector<OctSpace::ContainedObject> m_StaticObjects;
|
||||||
{
|
std::vector<OctSpace::ContainedObject> m_DynamicObjects;
|
||||||
ContainedObject()
|
|
||||||
: Box(AABB())
|
|
||||||
, Checked(false)
|
|
||||||
{}
|
|
||||||
ContainedObject(AABB box)
|
|
||||||
: Box(box)
|
|
||||||
, Checked(false)
|
|
||||||
{}
|
|
||||||
AABB Box;
|
|
||||||
bool Checked;
|
|
||||||
};
|
|
||||||
Child* m_Root;
|
|
||||||
std::vector<ContainedObject> m_StaticObjects;
|
|
||||||
std::vector<ContainedObject> m_DynamicObjects;
|
|
||||||
|
|
||||||
bool m_UpdatedOnce;
|
|
||||||
unsigned int m_BoxID;
|
|
||||||
glm::vec3 m_PrevPos;
|
|
||||||
glm::quat m_PrevOri;
|
|
||||||
|
|
||||||
void falsifyObjectChecks();
|
void falsifyObjectChecks();
|
||||||
|
|
||||||
struct Child
|
|
||||||
{
|
|
||||||
~Child();
|
|
||||||
Child(const AABB& octTreeBounds,
|
|
||||||
int subDivisions,
|
|
||||||
std::vector<Octree::ContainedObject>& staticObjects,
|
|
||||||
std::vector<Octree::ContainedObject>& dynamicObjects);
|
|
||||||
Child(const Child& other) = delete;
|
|
||||||
Child(const Child&& other) = delete;
|
|
||||||
Child& operator= (const Child& other) = delete;
|
|
||||||
void AddDynamicObject(const AABB& box);
|
|
||||||
void AddStaticObject(const AABB& box);
|
|
||||||
void BoxesInSameRegion(const AABB& box, std::vector<AABB>& outBoxes) const;
|
|
||||||
void ClearObjects();
|
|
||||||
void ClearDynamicObjects();
|
|
||||||
bool RayCollides(const Ray& ray, Output& data) const;
|
|
||||||
bool BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected) const;
|
|
||||||
|
|
||||||
Child* m_Children[8];
|
|
||||||
//Indices into the lists in Octree.
|
|
||||||
std::vector<int> m_StaticObjIndices;
|
|
||||||
std::vector<int> m_DynamicObjIndices;
|
|
||||||
AABB m_Box;
|
|
||||||
//Reference to the lists in Octree.
|
|
||||||
std::vector<Octree::ContainedObject>& m_StaticObjectsRef;
|
|
||||||
std::vector<Octree::ContainedObject>& m_DynamicObjectsRef;
|
|
||||||
|
|
||||||
inline bool hasChildren() const;
|
|
||||||
int childIndexContainingPoint(const glm::vec3& point) const;
|
|
||||||
std::vector<int> childIndicesContainingBox(const AABB& box) const;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace OctSpace
|
||||||
|
{
|
||||||
|
|
||||||
|
struct Output
|
||||||
|
{
|
||||||
|
float CollideDistance;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ContainedObject
|
||||||
|
{
|
||||||
|
ContainedObject()
|
||||||
|
: Box(nullptr)
|
||||||
|
, Checked(false)
|
||||||
|
{}
|
||||||
|
template<typename BoxlikeObject>
|
||||||
|
ContainedObject(const BoxlikeObject& box)
|
||||||
|
: Box(new BoxlikeObject(box))
|
||||||
|
, Checked(false)
|
||||||
|
{}
|
||||||
|
std::unique_ptr<AABB> Box;
|
||||||
|
bool Checked;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Child
|
||||||
|
{
|
||||||
|
~Child();
|
||||||
|
Child(const AABB& octTreeBounds,
|
||||||
|
int subDivisions,
|
||||||
|
std::vector<ContainedObject>& staticObjects,
|
||||||
|
std::vector<ContainedObject>& dynamicObjects);
|
||||||
|
Child(const Child& other) = delete;
|
||||||
|
Child(const Child&& other) = delete;
|
||||||
|
Child& operator= (const Child& other) = delete;
|
||||||
|
void AddDynamicObject(const AABB& box);
|
||||||
|
void AddStaticObject(const AABB& box);
|
||||||
|
template<typename T, typename Box>
|
||||||
|
void ObjectsInSameRegion(const Box& box, std::vector<T>& outObjects) const;
|
||||||
|
void ClearObjects();
|
||||||
|
void ClearDynamicObjects();
|
||||||
|
bool RayCollides(const Ray& ray, Output& data) const;
|
||||||
|
bool BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected) const;
|
||||||
|
|
||||||
|
Child* m_Children[8];
|
||||||
|
//Indices into the lists in Octree.
|
||||||
|
std::vector<int> m_StaticObjIndices;
|
||||||
|
std::vector<int> m_DynamicObjIndices;
|
||||||
|
AABB m_Box;
|
||||||
|
//Reference to the lists in Octree.
|
||||||
|
std::vector<ContainedObject>& m_StaticObjectsRef;
|
||||||
|
std::vector<ContainedObject>& m_DynamicObjectsRef;
|
||||||
|
|
||||||
|
inline bool hasChildren() const;
|
||||||
|
int childIndexContainingPoint(const glm::vec3& point) const;
|
||||||
|
std::vector<int> childIndicesContainingBox(const AABB& box) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
Octree<T>::Octree(const AABB& octTreeBounds, int subDivisions)
|
||||||
|
: m_Root(new OctSpace::Child(octTreeBounds, subDivisions, m_StaticObjects, m_DynamicObjects))
|
||||||
|
{
|
||||||
|
static_assert(std::is_base_of<AABB, T>::value, "template argument type T in Octree must be a subclass of AABB.");
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
Octree<T>::~Octree()
|
||||||
|
{
|
||||||
|
delete m_Root;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void Octree<T>::AddDynamicObject(const T& object)
|
||||||
|
{
|
||||||
|
m_Root->AddDynamicObject(object);
|
||||||
|
m_DynamicObjects.emplace_back(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void Octree<T>::AddStaticObject(const T& object)
|
||||||
|
{
|
||||||
|
m_Root->AddStaticObject(object);
|
||||||
|
m_StaticObjects.emplace_back(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
template<typename Box>
|
||||||
|
void Octree<T>::ObjectsInSameRegion(const Box& box, std::vector<T>& outObjects)
|
||||||
|
{
|
||||||
|
static_assert(std::is_base_of<AABB, Box>::value, "template argument type Box in Octree<T>::ObjectsInSameRegion must be a subclass of AABB.");
|
||||||
|
falsifyObjectChecks();
|
||||||
|
m_Root->ObjectsInSameRegion(box, outObjects);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void Octree<T>::ClearObjects()
|
||||||
|
{
|
||||||
|
m_StaticObjects.clear();
|
||||||
|
m_DynamicObjects.clear();
|
||||||
|
m_Root->ClearObjects();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void Octree<T>::ClearDynamicObjects()
|
||||||
|
{
|
||||||
|
m_DynamicObjects.clear();
|
||||||
|
m_Root->ClearDynamicObjects();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
bool Octree<T>::RayCollides(const Ray& ray, OctSpace::Output& data)
|
||||||
|
{
|
||||||
|
falsifyObjectChecks();
|
||||||
|
data.CollideDistance = -1;
|
||||||
|
return m_Root->RayCollides(ray, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
bool Octree<T>::BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected)
|
||||||
|
{
|
||||||
|
falsifyObjectChecks();
|
||||||
|
return m_Root->BoxCollides(boxToTest, outBoxIntersected);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void Octree<T>::falsifyObjectChecks()
|
||||||
|
{
|
||||||
|
for (auto& obj : m_StaticObjects) {
|
||||||
|
obj.Checked = false;
|
||||||
|
}
|
||||||
|
for (auto& obj : m_DynamicObjects) {
|
||||||
|
obj.Checked = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, typename Box>
|
||||||
|
void OctSpace::Child::ObjectsInSameRegion(const Box& box, std::vector<T>& outObjects) const
|
||||||
|
{
|
||||||
|
if (hasChildren()) {
|
||||||
|
for (auto i : childIndicesContainingBox(box)) {
|
||||||
|
m_Children[i]->ObjectsInSameRegion(box, outObjects);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
size_t startIndex = outObjects.size();
|
||||||
|
int numDuplicates = 0;
|
||||||
|
outObjects.resize(outObjects.size() + m_StaticObjIndices.size() + m_DynamicObjIndices.size());
|
||||||
|
for (size_t i = 0; i < m_StaticObjIndices.size(); ++i) {
|
||||||
|
ContainedObject& obj = m_StaticObjectsRef[m_StaticObjIndices[i]];
|
||||||
|
if (obj.Checked) {
|
||||||
|
++numDuplicates;
|
||||||
|
} else {
|
||||||
|
obj.Checked = true;
|
||||||
|
outObjects[startIndex + i - numDuplicates] = *static_cast<T*>(obj.Box.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < m_DynamicObjIndices.size(); ++i) {
|
||||||
|
ContainedObject& obj = m_DynamicObjectsRef[m_DynamicObjIndices[i]];
|
||||||
|
if (obj.Checked) {
|
||||||
|
++numDuplicates;
|
||||||
|
} else {
|
||||||
|
obj.Checked = true;
|
||||||
|
outObjects[startIndex + i - numDuplicates] = *static_cast<T*>(obj.Box.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < numDuplicates; ++i) {
|
||||||
|
outObjects.pop_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -3,9 +3,12 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
|
#include <limits>
|
||||||
|
#include <queue>
|
||||||
|
|
||||||
#include <glm/common.hpp>
|
#include <glm/common.hpp>
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
|
#include <boost/shared_array.hpp>
|
||||||
|
|
||||||
#include "Network/Network.h"
|
#include "Network/Network.h"
|
||||||
#include "Network/MessageType.h"
|
#include "Network/MessageType.h"
|
||||||
@@ -15,6 +18,8 @@
|
|||||||
#include "Core/EventBroker.h"
|
#include "Core/EventBroker.h"
|
||||||
#include "Core/ConfigFile.h"
|
#include "Core/ConfigFile.h"
|
||||||
#include "Input/EInputCommand.h"
|
#include "Input/EInputCommand.h"
|
||||||
|
#include "Core/EPlayerDamage.h"
|
||||||
|
#include "Network/EInterpolate.h"
|
||||||
|
|
||||||
class Client : public Network
|
class Client : public Network
|
||||||
{
|
{
|
||||||
@@ -32,8 +37,6 @@ private:
|
|||||||
// Sending message to server logic
|
// Sending message to server logic
|
||||||
int bytesRead = -1;
|
int bytesRead = -1;
|
||||||
char readBuf[INPUTSIZE] = { 0 };
|
char readBuf[INPUTSIZE] = { 0 };
|
||||||
int snapshotInterval = 33;
|
|
||||||
std::clock_t previousSnapshotMessage = std::clock();
|
|
||||||
|
|
||||||
// Packet loss logic
|
// Packet loss logic
|
||||||
unsigned int m_PacketID = 0;
|
unsigned int m_PacketID = 0;
|
||||||
@@ -44,40 +47,55 @@ private:
|
|||||||
World* m_World;
|
World* m_World;
|
||||||
std::string m_PlayerName;
|
std::string m_PlayerName;
|
||||||
int m_PlayerID = -1;
|
int m_PlayerID = -1;
|
||||||
|
EntityID m_ServerEntityID = std::numeric_limits<EntityID>::max();
|
||||||
|
bool m_IsConnected = false;
|
||||||
|
// Server Client Lookup map
|
||||||
|
// Assumes that root node for client and server is EntityID 0.
|
||||||
|
|
||||||
|
// Don't Add items to these two maps with insert, use insertIntoServerClientMaps(EntityID, EntityID)!!!!
|
||||||
|
std::unordered_map<EntityID, EntityID> m_ServerIDToClientID;
|
||||||
|
std::unordered_map<EntityID, EntityID> m_ClientIDToServerID;
|
||||||
|
|
||||||
// Network logic
|
// Network logic
|
||||||
PlayerDefinition m_PlayerDefinitions[MAXCONNECTIONS];
|
PlayerDefinition m_PlayerDefinitions[MAXCONNECTIONS];
|
||||||
SnapshotDefinitions m_NextSnapshot;
|
SnapshotDefinitions m_NextSnapshot;
|
||||||
double m_DurationOfPingTime;
|
double m_DurationOfPingTime;
|
||||||
std::clock_t m_StartPingTime;
|
std::clock_t m_StartPingTime;
|
||||||
// Use to check if we should send disconnect message
|
std::vector<Events::InputCommand> m_InputCommandBuffer;
|
||||||
// if game is turned of by closing window.
|
|
||||||
bool m_WasStarted = false;
|
|
||||||
|
|
||||||
// Private member functions
|
// Private member functions
|
||||||
void readFromServer();
|
void readFromServer();
|
||||||
void sendSnapshotToServer();
|
|
||||||
int receive(char* data, size_t length);
|
int receive(char* data, size_t length);
|
||||||
void send(Packet& packet);
|
void send(Packet& packet);
|
||||||
void connect();
|
void connect();
|
||||||
void disconnect();
|
void disconnect();
|
||||||
void ping();
|
void ping();
|
||||||
void moveMessageHead(char*& data, size_t& length, size_t stepSize);
|
|
||||||
void parseMessageType(Packet& packet);
|
void parseMessageType(Packet& packet);
|
||||||
void parseEventMessage(Packet& packet);
|
|
||||||
void updateFields(Packet& packet, const ComponentInfo& componentInfo, const EntityID& entityID, const std::string& componentType);
|
void updateFields(Packet& packet, const ComponentInfo& componentInfo, const EntityID& entityID, const std::string& componentType);
|
||||||
void parseConnect(Packet& packet);
|
void parseConnect(Packet& packet);
|
||||||
|
void parsePlayerConnected(Packet& packet);
|
||||||
void parsePing();
|
void parsePing();
|
||||||
void parseServerPing();
|
void parseServerPing();
|
||||||
|
void InterpolateFields(Packet & packet, const ComponentInfo & componentInfo, const EntityID & entityID, const std::string & componentType);
|
||||||
void parseSnapshot(Packet& packet);
|
void parseSnapshot(Packet& packet);
|
||||||
void identifyPacketLoss();
|
void identifyPacketLoss();
|
||||||
bool isConnected();
|
bool hasServerTimedOut();
|
||||||
EntityID createPlayer();
|
EntityID createPlayer();
|
||||||
|
void sendInputCommands();
|
||||||
|
void becomePlayer();
|
||||||
|
// Mapping Logic
|
||||||
|
// Returns if local EntityID exist in map
|
||||||
|
bool clientServerMapsHasEntity(EntityID clientEntityID);
|
||||||
|
// Returns if server EntityID exist in map
|
||||||
|
bool serverClientMapsHasEntity(EntityID serverEntityID);
|
||||||
|
void insertIntoServerClientMaps(EntityID serverEntityID, EntityID clientEntityID);
|
||||||
|
|
||||||
// Events
|
// Events
|
||||||
EventBroker* m_EventBroker;
|
EventBroker* m_EventBroker;
|
||||||
EventRelay<Client, Events::InputCommand> m_EInputCommand;
|
EventRelay<Client, Events::InputCommand> m_EInputCommand;
|
||||||
bool OnInputCommand(const Events::InputCommand &e);
|
bool OnInputCommand(const Events::InputCommand& e);
|
||||||
|
EventRelay<Client, Events::PlayerDamage> m_EPlayeDamage;
|
||||||
|
bool OnPlayerDamage(const Events::PlayerDamage& e);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
#ifndef Events_Interpolate_h__
|
||||||
|
#define Events_Interpolate_h__
|
||||||
|
|
||||||
|
#include <boost/shared_array.hpp>
|
||||||
|
|
||||||
|
#include "Core/EventBroker.h"
|
||||||
|
#include "Core/Entity.h"
|
||||||
|
|
||||||
|
namespace Events
|
||||||
|
{
|
||||||
|
|
||||||
|
struct Interpolate : Event
|
||||||
|
{
|
||||||
|
EntityID Entity;
|
||||||
|
boost::shared_array<char> DataArray;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -11,7 +11,10 @@ enum class MessageType
|
|||||||
ServerPing,
|
ServerPing,
|
||||||
Message,
|
Message,
|
||||||
Snapshot,
|
Snapshot,
|
||||||
Event,
|
OnInputCommand,
|
||||||
|
OnPlayerDamage,
|
||||||
|
PlayerConnected,
|
||||||
|
BecomePlayer
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#define MAXCONNECTIONS 8
|
#define MAXCONNECTIONS 8
|
||||||
#define INPUTSIZE 4097
|
#define INPUTSIZE 4097
|
||||||
|
#define TIMEOUTMS 15000
|
||||||
|
|
||||||
class Network
|
class Network
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ public:
|
|||||||
Packet(MessageType type, unsigned int& packetID);
|
Packet(MessageType type, unsigned int& packetID);
|
||||||
// Used to create packet from already existing data buffer.
|
// Used to create packet from already existing data buffer.
|
||||||
Packet(char* data, const int sizeOfPacket);
|
Packet(char* data, const int sizeOfPacket);
|
||||||
|
Packet(MessageType type);
|
||||||
~Packet();
|
~Packet();
|
||||||
void Init(MessageType type, unsigned int& packetID);
|
void Init(MessageType type, unsigned int& packetID);
|
||||||
|
|
||||||
@@ -49,7 +50,7 @@ public:
|
|||||||
// Pops the first element as if it was a string.
|
// Pops the first element as if it was a string.
|
||||||
std::string ReadString();
|
std::string ReadString();
|
||||||
char* ReadData(int SizeOfData);
|
char* ReadData(int SizeOfData);
|
||||||
|
void ChangePacketID(unsigned int& packetID);
|
||||||
int Size() { return m_Offset; };
|
int Size() { return m_Offset; };
|
||||||
char* Data() { return m_Data; };
|
char* Data() { return m_Data; };
|
||||||
unsigned int DataReadSize() { return m_ReturnDataOffset; }
|
unsigned int DataReadSize() { return m_ReturnDataOffset; }
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ struct PlayerDefinition {
|
|||||||
int EntityID = -1;
|
int EntityID = -1;
|
||||||
std::string Name = "";
|
std::string Name = "";
|
||||||
boost::asio::ip::udp::endpoint Endpoint;
|
boost::asio::ip::udp::endpoint Endpoint;
|
||||||
|
unsigned int PacketID;
|
||||||
|
std::clock_t StopTime;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -11,7 +11,9 @@
|
|||||||
#include "Network/PlayerDefinition.h"
|
#include "Network/PlayerDefinition.h"
|
||||||
#include "Core/World.h"
|
#include "Core/World.h"
|
||||||
#include "Core/EventBroker.h"
|
#include "Core/EventBroker.h"
|
||||||
#include "Network/Network.h"
|
#include "../Network/Network.h"
|
||||||
|
#include "Input/EInputCommand.h"
|
||||||
|
#include "Core/EPlayerDamage.h"
|
||||||
|
|
||||||
class Server : public Network
|
class Server : public Network
|
||||||
{
|
{
|
||||||
@@ -25,9 +27,10 @@ private:
|
|||||||
boost::asio::ip::udp::endpoint m_ReceiverEndpoint;
|
boost::asio::ip::udp::endpoint m_ReceiverEndpoint;
|
||||||
boost::asio::io_service m_IOService;
|
boost::asio::io_service m_IOService;
|
||||||
boost::asio::ip::udp::socket m_Socket;
|
boost::asio::ip::udp::socket m_Socket;
|
||||||
PlayerDefinition m_PlayerDefinitions[MAXCONNECTIONS];
|
|
||||||
|
|
||||||
// Sending messages to client logic
|
// Sending messages to client logic
|
||||||
|
PlayerDefinition m_PlayerDefinitions[MAXCONNECTIONS];
|
||||||
|
std::vector<PlayerDefinition> m_ConnectedUsers;
|
||||||
char readBuffer[INPUTSIZE] = { 0 };
|
char readBuffer[INPUTSIZE] = { 0 };
|
||||||
int bytesRead = 0;
|
int bytesRead = 0;
|
||||||
// time for previouse message
|
// time for previouse message
|
||||||
@@ -41,40 +44,38 @@ private:
|
|||||||
|
|
||||||
//Timers
|
//Timers
|
||||||
std::clock_t m_StartPingTime;
|
std::clock_t m_StartPingTime;
|
||||||
std::clock_t m_StopTimes[8];
|
|
||||||
|
|
||||||
// Game logic
|
// Game logic
|
||||||
World* m_World;
|
World* m_World;
|
||||||
EventBroker* m_EventBroker;
|
EventBroker* m_EventBroker;
|
||||||
// vec.size() = ammount of players to create, stores playerID's
|
|
||||||
std::vector<unsigned int> m_PlayersToCreate;
|
|
||||||
|
|
||||||
// Packet loss logic
|
// Packet loss logic
|
||||||
unsigned int m_PacketID;
|
unsigned int m_PacketID = 0;
|
||||||
unsigned int m_PreviousPacketID;
|
unsigned int m_PreviousPacketID = 0;
|
||||||
unsigned int m_SendPacketID;
|
|
||||||
|
|
||||||
// Private member functions
|
// Private member functions
|
||||||
int receive(char* data, size_t length);
|
int receive(char* data, size_t length);
|
||||||
void readFromClients();
|
void readFromClients();
|
||||||
void send(Packet& packet, int playerID);
|
void send(Packet& packet, int playerID);
|
||||||
void send(Packet& packet);
|
void send(Packet& packet);
|
||||||
void moveMessageHead(char*& data, size_t& length, size_t stepSize);
|
|
||||||
void broadcast(std::string message);
|
|
||||||
void broadcast(Packet& packet);
|
void broadcast(Packet& packet);
|
||||||
void sendSnapshot();
|
void sendSnapshot();
|
||||||
void sendPing();
|
void sendPing();
|
||||||
void checkForTimeOuts();
|
void checkForTimeOuts();
|
||||||
void disconnect(int i);
|
void disconnect(int i);
|
||||||
void parseMessageType(Packet& packet);
|
void parseMessageType(Packet& packet);
|
||||||
void parseEvent(Packet& packet);
|
void parseOnInputCommand(Packet& packet);
|
||||||
|
void parseOnPlayerDamage(Packet& packet);
|
||||||
void parseConnect(Packet& packet);
|
void parseConnect(Packet& packet);
|
||||||
void parseDisconnect();
|
void parseDisconnect();
|
||||||
void parseClientPing();
|
void parseClientPing();
|
||||||
void parseServerPing();
|
void parseServerPing();
|
||||||
void parseSnapshot(Packet& packet);
|
|
||||||
void identifyPacketLoss();
|
void identifyPacketLoss();
|
||||||
EntityID createPlayer();
|
void createPlayer();
|
||||||
|
int GetPlayerIDFromEndpoint(boost::asio::ip::udp::endpoint endpoint);
|
||||||
|
// Debug event
|
||||||
|
EventRelay<Server, Events::InputCommand> m_EInputCommand;
|
||||||
|
bool OnInputCommand(const Events::InputCommand& e);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+3
-3
@@ -19,7 +19,7 @@
|
|||||||
#include "Rendering/RenderSystem.h"
|
#include "Rendering/RenderSystem.h"
|
||||||
#include "Core/EntityFileParser.h"
|
#include "Core/EntityFileParser.h"
|
||||||
#include "Core/Octree.h"
|
#include "Core/Octree.h"
|
||||||
|
#include "Systems/InterpolationSystem.h"
|
||||||
// Network
|
// Network
|
||||||
#include <boost/thread.hpp>
|
#include <boost/thread.hpp>
|
||||||
#include "Network/Network.h"
|
#include "Network/Network.h"
|
||||||
@@ -47,8 +47,8 @@ private:
|
|||||||
InputProxy* m_InputProxy;
|
InputProxy* m_InputProxy;
|
||||||
GUI::Frame* m_FrameStack;
|
GUI::Frame* m_FrameStack;
|
||||||
World* m_World;
|
World* m_World;
|
||||||
Octree* m_OctreeCollision;
|
Octree<AABB>* m_OctreeCollision;
|
||||||
Octree* m_OctreeFrustrumCulling;
|
Octree<AABB>* m_OctreeFrustrumCulling;
|
||||||
SystemPipeline* m_SystemPipeline;
|
SystemPipeline* m_SystemPipeline;
|
||||||
RenderFrame* m_RenderFrame;
|
RenderFrame* m_RenderFrame;
|
||||||
// Network variables
|
// Network variables
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
#ifndef Systems_InterpolationSystem_h__
|
||||||
|
#define Systems_InterpolationSystem_h__
|
||||||
|
|
||||||
|
#include <queue>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <boost/shared_array.hpp>
|
||||||
|
#include <glm/common.hpp>
|
||||||
|
#include <glm/gtc/quaternion.hpp>
|
||||||
|
|
||||||
|
#include "Common.h"
|
||||||
|
#include "Core/System.h"
|
||||||
|
#include "Core/EventBroker.h"
|
||||||
|
|
||||||
|
#include "Network/EInterpolate.h"
|
||||||
|
|
||||||
|
#define SNAPSHOTINTERVAL 0.05f
|
||||||
|
|
||||||
|
class InterpolationSystem : public PureSystem
|
||||||
|
{
|
||||||
|
struct Transform
|
||||||
|
{
|
||||||
|
glm::vec3 Position;
|
||||||
|
glm::vec3 Scale;
|
||||||
|
glm::quat Orientation;
|
||||||
|
double interpolationTime;
|
||||||
|
};
|
||||||
|
public:
|
||||||
|
InterpolationSystem(EventBroker* eventBroker)
|
||||||
|
: System(eventBroker)
|
||||||
|
, PureSystem("Transform")
|
||||||
|
{
|
||||||
|
EVENT_SUBSCRIBE_MEMBER(m_EInterpolate, &InterpolationSystem::OnInterpolate);
|
||||||
|
}
|
||||||
|
~InterpolationSystem() { }
|
||||||
|
virtual void UpdateComponent(World* world, EntityWrapper& entity, ComponentWrapper& transform, double dt) override;
|
||||||
|
private:
|
||||||
|
std::unordered_map<EntityID, Transform> m_NextTransform;
|
||||||
|
std::unordered_map<EntityID, Transform> m_LastReceivedTransform;
|
||||||
|
|
||||||
|
//glm::vec3 vectorInterpolation(glm::vec3 prev, glm::vec3 next, double currentTime);
|
||||||
|
template <typename T>
|
||||||
|
T vectorInterpolation(T prev, T next, double currentTime)
|
||||||
|
{
|
||||||
|
T difference = next - prev;
|
||||||
|
T vector = (difference / SNAPSHOTINTERVAL) * static_cast<float>(currentTime);
|
||||||
|
return vector;
|
||||||
|
}
|
||||||
|
|
||||||
|
EventRelay<InterpolationSystem, Events::Interpolate> m_EInterpolate;
|
||||||
|
bool InterpolationSystem::OnInterpolate(const Events::Interpolate& e);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
|
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
|
||||||
<Physics xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Physics.xsd">
|
<Physics xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Physics.xsd">
|
||||||
<Velocity X="0" Y="0" Z="0"/>
|
<Velocity X="0" Y="0" Z="0"/>
|
||||||
|
<Gravity>true</Gravity>
|
||||||
</Physics>
|
</Physics>
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
<xs:complexType>
|
<xs:complexType>
|
||||||
<xs:all>
|
<xs:all>
|
||||||
<xs:element name="Velocity" type="t:Vector" minOccurs="0"/>
|
<xs:element name="Velocity" type="t:Vector" minOccurs="0"/>
|
||||||
|
<xs:element name="Gravity" type="t:bool" minOccurs="0"/>
|
||||||
</xs:all>
|
</xs:all>
|
||||||
</xs:complexType>
|
</xs:complexType>
|
||||||
</xs:element>
|
</xs:element>
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ void CollisionSystem::UpdateComponent(World* world, EntityWrapper& entity, Compo
|
|||||||
|
|
||||||
// Collide against octree
|
// Collide against octree
|
||||||
std::vector<AABB> octreeResult;
|
std::vector<AABB> octreeResult;
|
||||||
m_Octree->BoxesInSameRegion(*boundingBox, octreeResult);
|
m_Octree->ObjectsInSameRegion(*boundingBox, octreeResult);
|
||||||
for (auto& boxB : octreeResult) {
|
for (auto& boxB : octreeResult) {
|
||||||
glm::vec3 resolutionVector;
|
glm::vec3 resolutionVector;
|
||||||
if (Collision::IsSameBoxProbably(boxA, boxB)) {
|
if (Collision::IsSameBoxProbably(boxA, boxB)) {
|
||||||
|
|||||||
@@ -34,9 +34,12 @@ void TriggerSystem::UpdateComponent(World* world, EntityWrapper& entity, Compone
|
|||||||
throwLeaveIfWasInTrigger(m_EntitiesCompletelyInTrigger[tId], pId, tId);
|
throwLeaveIfWasInTrigger(m_EntitiesCompletelyInTrigger[tId], pId, tId);
|
||||||
} else {
|
} else {
|
||||||
//Entity is at least touching the trigger.
|
//Entity is at least touching the trigger.
|
||||||
AABB completelyInsideBox = AABB::FromOriginSize((*triggerBox).Origin(), (*triggerBox).Size() - 2.0f * (*playerBox).Size());
|
AABB completelyInsideBox;
|
||||||
if (Collision::AABBVsAABB(completelyInsideBox, *playerBox) &&
|
bool playerFitsInTrigger = glm::all(glm::greaterThan((*triggerBox).Size(), (*playerBox).Size()));
|
||||||
glm::all(glm::greaterThan((*triggerBox).Size(), (*playerBox).Size()))) {
|
if (playerFitsInTrigger) {
|
||||||
|
completelyInsideBox = AABB::FromOriginSize((*triggerBox).Origin(), (*triggerBox).Size() - 2.0f * (*playerBox).Size());
|
||||||
|
}
|
||||||
|
if (playerFitsInTrigger && Collision::AABBVsAABB(completelyInsideBox, *playerBox)) {
|
||||||
//Entity is completely inside the trigger.
|
//Entity is completely inside the trigger.
|
||||||
//If it was only touching before, it is erased.
|
//If it was only touching before, it is erased.
|
||||||
m_EntitiesTouchingTrigger[tId].erase(pId);
|
m_EntitiesTouchingTrigger[tId].erase(pId);
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ AABB::AABB(const glm::vec3& minPos, const glm::vec3& maxPos)
|
|||||||
m_MinCorner.y = glm::min(m_MaxCorner.y, m_MinCorner.y);
|
m_MinCorner.y = glm::min(m_MaxCorner.y, m_MinCorner.y);
|
||||||
m_MaxCorner.z = glm::max(m_MaxCorner.z, m_MinCorner.z);
|
m_MaxCorner.z = glm::max(m_MaxCorner.z, m_MinCorner.z);
|
||||||
m_MinCorner.z = glm::min(m_MaxCorner.z, m_MinCorner.z);
|
m_MinCorner.z = glm::min(m_MaxCorner.z, m_MinCorner.z);
|
||||||
|
m_Origin = 0.5f * (m_MaxCorner + m_MinCorner);
|
||||||
|
m_HalfSize = 0.5f * (m_MaxCorner - m_MinCorner);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+25
-114
@@ -21,71 +21,10 @@ bool isFirstLower(const ChildInfo& first, const ChildInfo& second)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Octree::Octree(const AABB& octTreeBounds, int subDivisions)
|
namespace OctSpace
|
||||||
: m_Root(new Child(octTreeBounds, subDivisions, m_StaticObjects, m_DynamicObjects))
|
|
||||||
, m_UpdatedOnce(false)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
Octree::~Octree()
|
|
||||||
{
|
{
|
||||||
delete m_Root;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Octree::AddDynamicObject(const AABB& box)
|
Child::Child(const AABB& octTreeBounds,
|
||||||
{
|
|
||||||
m_Root->AddDynamicObject(box);
|
|
||||||
m_DynamicObjects.push_back(box);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Octree::AddStaticObject(const AABB& box)
|
|
||||||
{
|
|
||||||
m_Root->AddStaticObject(box);
|
|
||||||
m_StaticObjects.push_back(box);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Octree::BoxesInSameRegion(const AABB& box, std::vector<AABB>& outBoxes)
|
|
||||||
{
|
|
||||||
falsifyObjectChecks();
|
|
||||||
m_Root->BoxesInSameRegion(box, outBoxes);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Octree::ClearObjects()
|
|
||||||
{
|
|
||||||
m_StaticObjects.clear();
|
|
||||||
m_DynamicObjects.clear();
|
|
||||||
m_Root->ClearObjects();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Octree::ClearDynamicObjects()
|
|
||||||
{
|
|
||||||
m_DynamicObjects.clear();
|
|
||||||
m_Root->ClearDynamicObjects();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Octree::RayCollides(const Ray& ray, Output& data)
|
|
||||||
{
|
|
||||||
falsifyObjectChecks();
|
|
||||||
data.CollideDistance = -1;
|
|
||||||
return m_Root->RayCollides(ray, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Octree::BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected)
|
|
||||||
{
|
|
||||||
falsifyObjectChecks();
|
|
||||||
return m_Root->BoxCollides(boxToTest, outBoxIntersected);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Octree::falsifyObjectChecks()
|
|
||||||
{
|
|
||||||
for (auto& obj : m_StaticObjects) {
|
|
||||||
obj.Checked = false;
|
|
||||||
}
|
|
||||||
for (auto& obj : m_DynamicObjects) {
|
|
||||||
obj.Checked = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Octree::Child::Child(const AABB& octTreeBounds,
|
|
||||||
int subDivisions,
|
int subDivisions,
|
||||||
std::vector<ContainedObject>& staticObjects,
|
std::vector<ContainedObject>& staticObjects,
|
||||||
std::vector<ContainedObject>& dynamicObjects)
|
std::vector<ContainedObject>& dynamicObjects)
|
||||||
@@ -135,7 +74,7 @@ Octree::Child::Child(const AABB& octTreeBounds,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Octree::Child::~Child()
|
Child::~Child()
|
||||||
{
|
{
|
||||||
for (Child*& c : m_Children) {
|
for (Child*& c : m_Children) {
|
||||||
if (c != nullptr) {
|
if (c != nullptr) {
|
||||||
@@ -145,7 +84,7 @@ Octree::Child::~Child()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Octree::Child::BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected) const
|
bool Child::BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected) const
|
||||||
{
|
{
|
||||||
if (hasChildren()) {
|
if (hasChildren()) {
|
||||||
for (int i : childIndicesContainingBox(boxToTest)) {
|
for (int i : childIndicesContainingBox(boxToTest)) {
|
||||||
@@ -155,7 +94,7 @@ bool Octree::Child::BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected)
|
|||||||
} else {
|
} else {
|
||||||
for (int i : m_StaticObjIndices) {
|
for (int i : m_StaticObjIndices) {
|
||||||
if (!m_StaticObjectsRef[i].Checked) {
|
if (!m_StaticObjectsRef[i].Checked) {
|
||||||
const AABB& objBox = m_StaticObjectsRef[i].Box;
|
const AABB& objBox = *m_StaticObjectsRef[i].Box;
|
||||||
if (Collision::AABBVsAABB(boxToTest, objBox)) {
|
if (Collision::AABBVsAABB(boxToTest, objBox)) {
|
||||||
outBoxIntersected = objBox;
|
outBoxIntersected = objBox;
|
||||||
return true;
|
return true;
|
||||||
@@ -165,7 +104,7 @@ bool Octree::Child::BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected)
|
|||||||
}
|
}
|
||||||
for (int i : m_DynamicObjIndices) {
|
for (int i : m_DynamicObjIndices) {
|
||||||
if (!m_DynamicObjectsRef[i].Checked) {
|
if (!m_DynamicObjectsRef[i].Checked) {
|
||||||
const AABB& objBox = m_DynamicObjectsRef[i].Box;
|
const AABB& objBox = *m_DynamicObjectsRef[i].Box;
|
||||||
if (!Collision::IsSameBoxProbably(boxToTest, objBox) &&
|
if (!Collision::IsSameBoxProbably(boxToTest, objBox) &&
|
||||||
Collision::AABBVsAABB(boxToTest, objBox)) {
|
Collision::AABBVsAABB(boxToTest, objBox)) {
|
||||||
outBoxIntersected = objBox;
|
outBoxIntersected = objBox;
|
||||||
@@ -178,7 +117,7 @@ bool Octree::Child::BoxCollides(const AABB& boxToTest, AABB& outBoxIntersected)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Octree::Child::RayCollides(const Ray& ray, Output& data) const
|
bool Child::RayCollides(const Ray& ray, OctSpace::Output& data) const
|
||||||
{
|
{
|
||||||
//If the node AABB is missed, everything it contains is missed.
|
//If the node AABB is missed, everything it contains is missed.
|
||||||
if (Collision::RayAABBIntr(ray, m_Box)) {
|
if (Collision::RayAABBIntr(ray, m_Box)) {
|
||||||
@@ -205,7 +144,7 @@ bool Octree::Child::RayCollides(const Ray& ray, Output& data) const
|
|||||||
float dist;
|
float dist;
|
||||||
//If we haven't tested against this object before, and the ray hits.
|
//If we haven't tested against this object before, and the ray hits.
|
||||||
if (!m_StaticObjectsRef[i].Checked &&
|
if (!m_StaticObjectsRef[i].Checked &&
|
||||||
Collision::RayVsAABB(ray, m_StaticObjectsRef[i].Box, dist)) {
|
Collision::RayVsAABB(ray, *m_StaticObjectsRef[i].Box, dist)) {
|
||||||
minDist = std::min(dist, minDist);
|
minDist = std::min(dist, minDist);
|
||||||
intersected = true;
|
intersected = true;
|
||||||
}
|
}
|
||||||
@@ -215,7 +154,7 @@ bool Octree::Child::RayCollides(const Ray& ray, Output& data) const
|
|||||||
float dist;
|
float dist;
|
||||||
//If we haven't tested against this object before, and the ray hits.
|
//If we haven't tested against this object before, and the ray hits.
|
||||||
if (!m_DynamicObjectsRef[i].Checked &&
|
if (!m_DynamicObjectsRef[i].Checked &&
|
||||||
Collision::RayVsAABB(ray, m_DynamicObjectsRef[i].Box, dist)) {
|
Collision::RayVsAABB(ray, *m_DynamicObjectsRef[i].Box, dist)) {
|
||||||
minDist = std::min(dist, minDist);
|
minDist = std::min(dist, minDist);
|
||||||
intersected = true;
|
intersected = true;
|
||||||
}
|
}
|
||||||
@@ -230,7 +169,7 @@ bool Octree::Child::RayCollides(const Ray& ray, Output& data) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Octree::Child::AddDynamicObject(const AABB& box)
|
void Child::AddDynamicObject(const AABB& box)
|
||||||
{
|
{
|
||||||
if (hasChildren()) {
|
if (hasChildren()) {
|
||||||
for (auto i : childIndicesContainingBox(box)) {
|
for (auto i : childIndicesContainingBox(box)) {
|
||||||
@@ -242,7 +181,7 @@ void Octree::Child::AddDynamicObject(const AABB& box)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Octree::Child::AddStaticObject(const AABB& box)
|
void Child::AddStaticObject(const AABB& box)
|
||||||
{
|
{
|
||||||
if (hasChildren()) {
|
if (hasChildren()) {
|
||||||
for (auto i : childIndicesContainingBox(box)) {
|
for (auto i : childIndicesContainingBox(box)) {
|
||||||
@@ -254,41 +193,7 @@ void Octree::Child::AddStaticObject(const AABB& box)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Octree::Child::BoxesInSameRegion(const AABB& box, std::vector<AABB>& outBoxes) const
|
void Child::ClearObjects()
|
||||||
{
|
|
||||||
if (hasChildren()) {
|
|
||||||
for (auto i : childIndicesContainingBox(box)) {
|
|
||||||
m_Children[i]->BoxesInSameRegion(box, outBoxes);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
size_t startIndex = outBoxes.size();
|
|
||||||
int numDuplicates = 0;
|
|
||||||
outBoxes.resize(outBoxes.size() + m_StaticObjIndices.size() + m_DynamicObjIndices.size());
|
|
||||||
for (size_t i = 0; i < m_StaticObjIndices.size(); ++i){
|
|
||||||
ContainedObject& obj = m_StaticObjectsRef[m_StaticObjIndices[i]];
|
|
||||||
if (obj.Checked) {
|
|
||||||
++numDuplicates;
|
|
||||||
} else {
|
|
||||||
obj.Checked = true;
|
|
||||||
outBoxes[startIndex + i - numDuplicates] = obj.Box;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (size_t i = 0; i < m_DynamicObjIndices.size(); ++i) {
|
|
||||||
ContainedObject& obj = m_DynamicObjectsRef[m_DynamicObjIndices[i]];
|
|
||||||
if (obj.Checked) {
|
|
||||||
++numDuplicates;
|
|
||||||
} else {
|
|
||||||
obj.Checked = true;
|
|
||||||
outBoxes[startIndex + i - numDuplicates] = obj.Box;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (size_t i = 0; i < numDuplicates; ++i) {
|
|
||||||
outBoxes.pop_back();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Octree::Child::ClearObjects()
|
|
||||||
{
|
{
|
||||||
if (hasChildren()) {
|
if (hasChildren()) {
|
||||||
for (Child*& c : m_Children) {
|
for (Child*& c : m_Children) {
|
||||||
@@ -300,11 +205,11 @@ void Octree::Child::ClearObjects()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Octree::Child::ClearDynamicObjects()
|
void Child::ClearDynamicObjects()
|
||||||
{
|
{
|
||||||
if (hasChildren()) {
|
if (hasChildren()) {
|
||||||
for (Child*& c : m_Children) {
|
for (Child*& c : m_Children) {
|
||||||
c->ClearObjects();
|
c->ClearDynamicObjects();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
m_DynamicObjIndices.clear();
|
m_DynamicObjIndices.clear();
|
||||||
@@ -323,13 +228,13 @@ void Octree::Child::ClearDynamicObjects()
|
|||||||
// x : - - - - + + + +
|
// x : - - - - + + + +
|
||||||
// y : - - + + - - + +
|
// y : - - + + - - + +
|
||||||
// z : - + - + - + - +
|
// z : - + - + - + - +
|
||||||
int Octree::Child::childIndexContainingPoint(const glm::vec3& point) const
|
int Child::childIndexContainingPoint(const glm::vec3& point) const
|
||||||
{
|
{
|
||||||
const glm::vec3& c = m_Box.Origin();
|
const glm::vec3& c = m_Box.Origin();
|
||||||
return (1 << 2) * (point.x >= c.x) | (1 << 1) * (point.y >= c.y) | (point.z >= c.z);
|
return (1 << 2) * (point.x >= c.x) | (1 << 1) * (point.y >= c.y) | (point.z >= c.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<int> Octree::Child::childIndicesContainingBox(const AABB& box) const
|
std::vector<int> Child::childIndicesContainingBox(const AABB& box) const
|
||||||
{
|
{
|
||||||
int minInd = childIndexContainingPoint(box.MinCorner());
|
int minInd = childIndexContainingPoint(box.MinCorner());
|
||||||
int maxInd = childIndexContainingPoint(box.MaxCorner());
|
int maxInd = childIndexContainingPoint(box.MaxCorner());
|
||||||
@@ -352,9 +257,13 @@ std::vector<int> Octree::Child::childIndicesContainingBox(const AABB& box) const
|
|||||||
//the dimensions they are responsible for (which octant).
|
//the dimensions they are responsible for (which octant).
|
||||||
bits.flip();
|
bits.flip();
|
||||||
//At this point the bits necessarily have exactly one bit set.
|
//At this point the bits necessarily have exactly one bit set.
|
||||||
|
//Check the same bit in the minInd as the one set in bits.
|
||||||
|
int setOrUnset = (bits.to_ulong() & minInd);
|
||||||
for (int c = 0; c < 8; ++c) {
|
for (int c = 0; c < 8; ++c) {
|
||||||
//If the child index have the same bit set as the bits, add box to it.
|
//Check the same bit in the child index as the one set in bits.
|
||||||
if (bits.to_ulong() & c) {
|
//Enter here if both c and minInd have the bit set, or if neither have it set.
|
||||||
|
//I.e, if they are on the same side (+ or -) in the dimension marked by the bit in bits.
|
||||||
|
if (!((bits.to_ulong() & c) ^ setOrUnset)) {
|
||||||
ret.push_back(c);
|
ret.push_back(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -367,7 +276,9 @@ std::vector<int> Octree::Child::childIndicesContainingBox(const AABB& box) const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool Octree::Child::hasChildren() const
|
inline bool Child::hasChildren() const
|
||||||
{
|
{
|
||||||
return m_Children[0] != nullptr;
|
return m_Children[0] != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+155
-130
@@ -5,28 +5,27 @@ using namespace boost::asio::ip;
|
|||||||
|
|
||||||
Client::Client(ConfigFile* config) : m_Socket(m_IOService)
|
Client::Client(ConfigFile* config) : m_Socket(m_IOService)
|
||||||
{
|
{
|
||||||
|
// Asumes root node is EntityID 0
|
||||||
|
insertIntoServerClientMaps(0, 0);
|
||||||
// Default is local host
|
// Default is local host
|
||||||
std::string address = config->Get<std::string>("Networking.Address", "127.0.0.1");
|
std::string address = config->Get<std::string>("Networking.Address", "127.0.0.1");
|
||||||
int port = config->Get<int>("Networking.Port", 13);
|
int port = config->Get<int>("Networking.Port", 13);
|
||||||
m_ReceiverEndpoint = udp::endpoint(boost::asio::ip::address::from_string(address), port);
|
m_ReceiverEndpoint = udp::endpoint(boost::asio::ip::address::from_string(address), port);
|
||||||
// Set up network stream
|
// Set up network stream
|
||||||
m_PlayerName = config->Get<std::string>("Networking.Name", "Raptorcopter");
|
m_PlayerName = config->Get<std::string>("Networking.Name", "Raptorcopter");
|
||||||
m_NextSnapshot.InputForward = "";
|
|
||||||
m_NextSnapshot.InputRight = "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Client::~Client()
|
Client::~Client()
|
||||||
{
|
{ }
|
||||||
}
|
|
||||||
|
|
||||||
void Client::Start(World* world, EventBroker* eventBroker)
|
void Client::Start(World* world, EventBroker* eventBroker)
|
||||||
{
|
{
|
||||||
m_WasStarted = true;
|
|
||||||
m_EventBroker = eventBroker;
|
m_EventBroker = eventBroker;
|
||||||
m_World = world;
|
m_World = world;
|
||||||
|
|
||||||
// Subscribe to events
|
// Subscribe to events
|
||||||
EVENT_SUBSCRIBE_MEMBER(m_EInputCommand, &Client::OnInputCommand);
|
EVENT_SUBSCRIBE_MEMBER(m_EInputCommand, &Client::OnInputCommand);
|
||||||
|
EVENT_SUBSCRIBE_MEMBER(m_EPlayeDamage, &Client::OnPlayerDamage);
|
||||||
|
|
||||||
m_Socket.connect(m_ReceiverEndpoint);
|
m_Socket.connect(m_ReceiverEndpoint);
|
||||||
LOG_INFO("I am client. BIP BOP");
|
LOG_INFO("I am client. BIP BOP");
|
||||||
@@ -34,7 +33,11 @@ void Client::Start(World* world, EventBroker* eventBroker)
|
|||||||
|
|
||||||
void Client::Update()
|
void Client::Update()
|
||||||
{
|
{
|
||||||
|
m_EventBroker->Process<Client>();
|
||||||
readFromServer();
|
readFromServer();
|
||||||
|
if (m_IsConnected) {
|
||||||
|
hasServerTimedOut();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::readFromServer()
|
void Client::readFromServer()
|
||||||
@@ -46,58 +49,7 @@ void Client::readFromServer()
|
|||||||
parseMessageType(packet);
|
parseMessageType(packet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::clock_t currentTime = std::clock();
|
sendInputCommands();
|
||||||
if (snapshotInterval < (1000 * (currentTime - previousSnapshotMessage) / (double)CLOCKS_PER_SEC)) {
|
|
||||||
if (isConnected()) {
|
|
||||||
//sendSnapshotToServer();
|
|
||||||
}
|
|
||||||
previousSnapshotMessage = currentTime;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Client::sendSnapshotToServer()
|
|
||||||
{
|
|
||||||
// Reset previous key state in snapshot.
|
|
||||||
m_NextSnapshot.InputForward = "";
|
|
||||||
m_NextSnapshot.InputRight = "";
|
|
||||||
|
|
||||||
auto player = m_World->GetComponent(m_PlayerDefinitions[m_PlayerID].EntityID, "Player");
|
|
||||||
|
|
||||||
// See if any movement keys are down
|
|
||||||
// We dont care if it's overwritten by later
|
|
||||||
// if statement. Watcha gonna do, right!
|
|
||||||
if (player["Forward"]) {
|
|
||||||
m_NextSnapshot.InputForward = "+Forward";
|
|
||||||
}
|
|
||||||
if (player["Left"]) {
|
|
||||||
m_NextSnapshot.InputRight = "-Right";
|
|
||||||
}
|
|
||||||
if (player["Back"]) {
|
|
||||||
m_NextSnapshot.InputForward = "-Forward";
|
|
||||||
}
|
|
||||||
if (player["Right"]) {
|
|
||||||
m_NextSnapshot.InputRight = "+Right";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_NextSnapshot.InputForward != "") {
|
|
||||||
Packet packet(MessageType::Event, m_SendPacketID);
|
|
||||||
packet.WriteString(m_NextSnapshot.InputForward);
|
|
||||||
send(packet);
|
|
||||||
} else {
|
|
||||||
Packet packet(MessageType::Event, m_SendPacketID);
|
|
||||||
packet.WriteString("0Forward");
|
|
||||||
send(packet);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_NextSnapshot.InputRight != "") {
|
|
||||||
Packet packet(MessageType::Event, m_SendPacketID);
|
|
||||||
packet.WriteString(m_NextSnapshot.InputRight);
|
|
||||||
send(packet);
|
|
||||||
} else {
|
|
||||||
Packet packet(MessageType::Event, m_SendPacketID);
|
|
||||||
packet.WriteString("0Right");
|
|
||||||
send(packet);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::parseMessageType(Packet& packet)
|
void Client::parseMessageType(Packet& packet)
|
||||||
@@ -108,9 +60,7 @@ void Client::parseMessageType(Packet& packet)
|
|||||||
// Read packet ID
|
// Read packet ID
|
||||||
m_PreviousPacketID = m_PacketID; // Set previous packet id
|
m_PreviousPacketID = m_PacketID; // Set previous packet id
|
||||||
m_PacketID = packet.ReadPrimitive<int>(); //Read new packet id
|
m_PacketID = packet.ReadPrimitive<int>(); //Read new packet id
|
||||||
if (m_PacketID <= m_PreviousPacketID)
|
identifyPacketLoss();
|
||||||
return;
|
|
||||||
//IdentifyPacketLoss();
|
|
||||||
|
|
||||||
switch (static_cast<MessageType>(messageType)) {
|
switch (static_cast<MessageType>(messageType)) {
|
||||||
case MessageType::Connect:
|
case MessageType::Connect:
|
||||||
@@ -129,9 +79,8 @@ void Client::parseMessageType(Packet& packet)
|
|||||||
break;
|
break;
|
||||||
case MessageType::Disconnect:
|
case MessageType::Disconnect:
|
||||||
break;
|
break;
|
||||||
case MessageType::Event:
|
case MessageType::PlayerConnected:
|
||||||
parseEventMessage(packet);
|
parsePlayerConnected(packet);
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -139,34 +88,52 @@ void Client::parseMessageType(Packet& packet)
|
|||||||
|
|
||||||
void Client::parseConnect(Packet& packet)
|
void Client::parseConnect(Packet& packet)
|
||||||
{
|
{
|
||||||
m_PlayerID = packet.ReadPrimitive<int>();
|
// Map ServerEntityID and your PlayerID
|
||||||
LOG_INFO("%i: I am player: %i", m_PacketID, m_PlayerID);
|
LOG_INFO("I be connected PogChamp");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Client::parsePlayerConnected(Packet & packet)
|
||||||
|
{
|
||||||
|
// Map ServerEntityID and other player's PlayerID
|
||||||
|
LOG_INFO("A Player connected");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::parsePing()
|
void Client::parsePing()
|
||||||
{
|
{
|
||||||
m_DurationOfPingTime = 1000 * (std::clock() - m_StartPingTime) / static_cast<double>(CLOCKS_PER_SEC);
|
|
||||||
LOG_INFO("%i: response time with ctime(ms): %f", m_PacketID, m_DurationOfPingTime);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::parseServerPing()
|
void Client::parseServerPing()
|
||||||
{
|
{
|
||||||
|
// Might miss connect message so set it here instead.
|
||||||
|
m_IsConnected = true;
|
||||||
|
// Time since last ping was received
|
||||||
|
m_DurationOfPingTime = 1000 * (std::clock() - m_StartPingTime) / static_cast<double>(CLOCKS_PER_SEC);
|
||||||
|
LOG_INFO("%i: response time with ctime(ms): %f", m_PacketID, m_DurationOfPingTime);
|
||||||
|
m_StartPingTime = std::clock();
|
||||||
|
|
||||||
Packet packet(MessageType::ServerPing, m_SendPacketID);
|
Packet packet(MessageType::ServerPing, m_SendPacketID);
|
||||||
packet.WriteString("Ping recieved");
|
packet.WriteString("Ping recieved");
|
||||||
send(packet);
|
send(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::parseEventMessage(Packet& packet)
|
// Fields with strings will not work right now
|
||||||
|
void Client::InterpolateFields(Packet& packet, const ComponentInfo& componentInfo, const EntityID& entityID, const std::string& componentType)
|
||||||
{
|
{
|
||||||
int Id = -1;
|
int sizeOfFields = 0;
|
||||||
std::string command = packet.ReadString();
|
for (auto field : componentInfo.FieldsInOrder) {
|
||||||
if (command.find("+Player") != std::string::npos) {
|
ComponentInfo::Field_t fieldInfo = componentInfo.Fields.at(field);
|
||||||
Id = packet.ReadPrimitive<int>();
|
sizeOfFields += fieldInfo.Stride;
|
||||||
// Sett Player name
|
|
||||||
m_PlayerDefinitions[Id].Name = command.erase(0, 7);
|
|
||||||
} else {
|
|
||||||
LOG_INFO("%i: Event message: %s", m_PacketID, command.c_str());
|
|
||||||
}
|
}
|
||||||
|
// Is the size correct?
|
||||||
|
boost::shared_array<char> eventData(new char[componentInfo.Stride]);
|
||||||
|
memcpy(eventData.get(), packet.ReadData(componentInfo.Stride), componentInfo.Stride);
|
||||||
|
//Send event to interpolat system
|
||||||
|
Events::Interpolate e;
|
||||||
|
e.Entity = entityID;
|
||||||
|
e.DataArray = eventData;
|
||||||
|
m_EventBroker->Publish(e);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::updateFields(Packet& packet, const ComponentInfo& componentInfo, const EntityID& entityID, const std::string& componentType)
|
void Client::updateFields(Packet& packet, const ComponentInfo& componentInfo, const EntityID& entityID, const std::string& componentType)
|
||||||
@@ -182,17 +149,27 @@ void Client::updateFields(Packet& packet, const ComponentInfo& componentInfo, co
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Field parse
|
|
||||||
void Client::parseSnapshot(Packet& packet)
|
void Client::parseSnapshot(Packet& packet)
|
||||||
{
|
{
|
||||||
std::string componentType = packet.ReadString();
|
std::string componentType = packet.ReadString();
|
||||||
while (packet.DataReadSize() < packet.Size()) {
|
while (packet.DataReadSize() < packet.Size()) {
|
||||||
EntityID entityID = packet.ReadPrimitive<EntityID>();
|
// Components EntityID
|
||||||
|
EntityID receivedEntityID = packet.ReadPrimitive<EntityID>();
|
||||||
|
// Parents EntityID
|
||||||
|
EntityID receivedParentEntityID = packet.ReadPrimitive<EntityID>();
|
||||||
ComponentInfo componentInfo = m_World->GetComponents(componentType)->ComponentInfo();
|
ComponentInfo componentInfo = m_World->GetComponents(componentType)->ComponentInfo();
|
||||||
if (m_World->ValidEntity(entityID)) {
|
// Check if the received EntityID is mapped to one of our local EntityIDs
|
||||||
|
if (serverClientMapsHasEntity(receivedEntityID)) {
|
||||||
|
// Get the local EntityID
|
||||||
|
EntityID entityID = m_ServerIDToClientID.at(receivedEntityID);
|
||||||
|
// Check if the component exists
|
||||||
if (m_World->HasComponent(entityID, componentType)) {
|
if (m_World->HasComponent(entityID, componentType)) {
|
||||||
// If the entity and the component exists update it
|
// If the entity and the component exists update it
|
||||||
updateFields(packet, componentInfo, entityID, componentType);
|
if (componentType == "Transform") {
|
||||||
|
InterpolateFields(packet, componentInfo, entityID, componentType);
|
||||||
|
} else {
|
||||||
|
updateFields(packet, componentInfo, entityID, componentType);
|
||||||
|
}
|
||||||
// if entity exists but not the component
|
// if entity exists but not the component
|
||||||
} else {
|
} else {
|
||||||
// Create component
|
// Create component
|
||||||
@@ -202,11 +179,12 @@ void Client::parseSnapshot(Packet& packet)
|
|||||||
}
|
}
|
||||||
// If the entity dosent exist nor the component
|
// If the entity dosent exist nor the component
|
||||||
} else {
|
} else {
|
||||||
//Create Entity
|
// Create Entity
|
||||||
// If entity dosen't exist
|
// If entity dosen't exist
|
||||||
EntityID newEntityID = m_World->CreateEntity();
|
EntityID newEntityID = m_World->CreateEntity();
|
||||||
|
insertIntoServerClientMaps(receivedEntityID, newEntityID);
|
||||||
// Check if EntityIDs are out of sync
|
// Check if EntityIDs are out of sync
|
||||||
if (newEntityID != entityID) {
|
if (newEntityID != receivedEntityID) {
|
||||||
LOG_INFO("Client::parseSnapshot(Packet& packet): Newly created EntityID is not the \
|
LOG_INFO("Client::parseSnapshot(Packet& packet): Newly created EntityID is not the \
|
||||||
same as the one sent by server (EntityIDs are out of sync)");
|
same as the one sent by server (EntityIDs are out of sync)");
|
||||||
}
|
}
|
||||||
@@ -215,6 +193,21 @@ void Client::parseSnapshot(Packet& packet)
|
|||||||
// Copy data to newly created component
|
// Copy data to newly created component
|
||||||
updateFields(packet, componentInfo, newEntityID, componentType);
|
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<EntityID>::max()) {
|
||||||
|
if (serverClientMapsHasEntity(receivedParentEntityID)) {
|
||||||
|
m_World->SetParent(m_ServerIDToClientID.at(receivedEntityID), m_ServerIDToClientID.at(receivedParentEntityID));
|
||||||
|
// If Parent dosen't exist create one and map receivedParentEntityID to it.
|
||||||
|
} else {
|
||||||
|
// Create the new parent and add it to map
|
||||||
|
EntityID newParentEntityID = m_World->CreateEntity();
|
||||||
|
insertIntoServerClientMaps(receivedParentEntityID, newParentEntityID);
|
||||||
|
// Set the newly created Entity as parent.
|
||||||
|
m_World->SetParent(m_ServerIDToClientID.at(receivedEntityID), newParentEntityID);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,9 +221,8 @@ int Client::receive(char* data, size_t length)
|
|||||||
0, error);
|
0, error);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
LOG_ERROR("receive: %s", error.message().c_str());
|
//LOG_ERROR("receive: %s", error.message().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
return bytesReceived;
|
return bytesReceived;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -252,76 +244,73 @@ void Client::connect()
|
|||||||
|
|
||||||
void Client::disconnect()
|
void Client::disconnect()
|
||||||
{
|
{
|
||||||
Packet packet(MessageType::Connect, m_SendPacketID);
|
m_PreviousPacketID = 0;
|
||||||
packet.WriteString("+Disconnect");
|
m_PacketID = 0;
|
||||||
|
Packet packet(MessageType::Disconnect, m_SendPacketID);
|
||||||
send(packet);
|
send(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::ping()
|
void Client::ping()
|
||||||
{
|
{
|
||||||
Packet packet(MessageType::Connect, m_SendPacketID);
|
//Packet packet(MessageType::Connect, m_SendPacketID);
|
||||||
packet.WriteString("Ping");
|
//packet.WriteString("Ping");
|
||||||
m_StartPingTime = std::clock();
|
//m_StartPingTime = std::clock();
|
||||||
send(packet);
|
//send(packet);
|
||||||
}
|
|
||||||
|
|
||||||
void Client::moveMessageHead(char*& data, size_t& length, size_t stepSize)
|
|
||||||
{
|
|
||||||
data += stepSize;
|
|
||||||
length -= stepSize;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Client::OnInputCommand(const Events::InputCommand & e)
|
bool Client::OnInputCommand(const Events::InputCommand & e)
|
||||||
{
|
{
|
||||||
if (isConnected()) {
|
|
||||||
ComponentWrapper& player = m_World->GetComponent(m_PlayerDefinitions[m_PlayerID].EntityID, "Player");
|
|
||||||
if (e.Command == "Forward") {
|
|
||||||
if (e.Value > 0) {
|
|
||||||
(bool&)player["Forward"] = true;
|
|
||||||
(bool&)player["Back"] = false;
|
|
||||||
} else if (e.Value < 0) {
|
|
||||||
(bool&)player["Back"] = true;
|
|
||||||
(bool&)player["Forward"] = false;
|
|
||||||
} else {
|
|
||||||
(bool&)player["Forward"] = false;
|
|
||||||
(bool&)player["Back"] = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (e.Command == "Right") {
|
|
||||||
if (e.Value > 0) {
|
|
||||||
(bool&)player["Right"] = true;
|
|
||||||
(bool&)player["Left"] = false;
|
|
||||||
} else if (e.Value < 0) {
|
|
||||||
(bool&)player["Left"] = true;
|
|
||||||
(bool&)player["Right"] = false;
|
|
||||||
} else {
|
|
||||||
(bool&)player["Left"] = false;
|
|
||||||
(bool&)player["Right"] = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (e.Command == "ConnectToServer") { // Connect for now
|
if (e.Command == "ConnectToServer") { // Connect for now
|
||||||
connect();
|
if (e.Value > 0) {
|
||||||
|
connect();
|
||||||
|
}
|
||||||
|
//LOG_DEBUG("Client::OnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID);
|
||||||
|
return true;
|
||||||
|
} else if (e.Command == "DisconnectFromServer") {
|
||||||
|
if (e.Value > 0) {
|
||||||
|
disconnect();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else if (e.Command == "SwitchToPlayer") {
|
||||||
|
if (e.Value > 0) {
|
||||||
|
becomePlayer();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
m_InputCommandBuffer.push_back(e);
|
||||||
|
//LOG_DEBUG("Client::OnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Client::OnPlayerDamage(const Events::PlayerDamage & e)
|
||||||
|
{
|
||||||
|
Packet packet(MessageType::OnInputCommand, m_SendPacketID);
|
||||||
|
packet.WritePrimitive(e.DamageAmount);
|
||||||
|
packet.WritePrimitive(e.PlayerDamagedID);
|
||||||
|
packet.WriteString(e.TypeOfDamage);
|
||||||
|
send(packet);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void Client::identifyPacketLoss()
|
void Client::identifyPacketLoss()
|
||||||
{
|
{
|
||||||
// if no packets lost, difference should be equal to 1
|
// if no packets lost, difference should be equal to 1
|
||||||
int difference = m_PacketID - m_PreviousPacketID;
|
int difference = m_PacketID - m_PreviousPacketID;
|
||||||
if (difference != 1) {
|
if (difference != 1) {
|
||||||
LOG_INFO("%i Packet(s) were lost...", difference);
|
LOG_INFO("%i Packet(s) were lost...", difference - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Client::isConnected()
|
bool Client::hasServerTimedOut()
|
||||||
{
|
{
|
||||||
if (m_PlayerID != -1) {
|
// Time in ms
|
||||||
if (m_PlayerDefinitions[m_PlayerID].EntityID != -1) {
|
float timeSincePing = 1000 * (std::clock() - m_StartPingTime) / static_cast<double>(CLOCKS_PER_SEC);
|
||||||
return true;
|
if (timeSincePing > TIMEOUTMS) {
|
||||||
}
|
// Clear everything and go to menu.
|
||||||
|
LOG_INFO("Server has timed out, returning to menu, Beep Boop.");
|
||||||
|
m_IsConnected = false;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -335,3 +324,39 @@ EntityID Client::createPlayer()
|
|||||||
ComponentWrapper player = m_World->AttachComponent(entityID, "Player");
|
ComponentWrapper player = m_World->AttachComponent(entityID, "Player");
|
||||||
return entityID;
|
return entityID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Client::sendInputCommands()
|
||||||
|
{
|
||||||
|
if (m_InputCommandBuffer.size() > 0) {
|
||||||
|
Packet packet(MessageType::OnInputCommand, m_SendPacketID);
|
||||||
|
for (int i = 0; i < m_InputCommandBuffer.size(); i++) {
|
||||||
|
packet.WriteString(m_InputCommandBuffer[i].Command);
|
||||||
|
packet.WritePrimitive(m_InputCommandBuffer[i].Value);
|
||||||
|
}
|
||||||
|
send(packet);
|
||||||
|
m_InputCommandBuffer.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Client::becomePlayer()
|
||||||
|
{
|
||||||
|
Packet packet = Packet(MessageType::BecomePlayer, m_SendPacketID);
|
||||||
|
send(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Client::clientServerMapsHasEntity(EntityID clientEntityID)
|
||||||
|
{
|
||||||
|
return m_ClientIDToServerID.find(clientEntityID) != m_ClientIDToServerID.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Client::serverClientMapsHasEntity(EntityID serverEntityID)
|
||||||
|
{
|
||||||
|
return m_ServerIDToClientID.find(serverEntityID) != m_ServerIDToClientID.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Client::insertIntoServerClientMaps(EntityID serverEntityID, EntityID clientEntityID)
|
||||||
|
{
|
||||||
|
m_ServerIDToClientID.insert(std::make_pair(serverEntityID, clientEntityID));
|
||||||
|
m_ClientIDToServerID.insert(std::make_pair(clientEntityID, serverEntityID));
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -17,6 +17,13 @@ Packet::Packet(char* data, const int sizeOfPacket)
|
|||||||
m_Offset = sizeOfPacket;
|
m_Offset = sizeOfPacket;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Packet::Packet(MessageType type)
|
||||||
|
{
|
||||||
|
m_Data = new char[m_MaxPacketSize];
|
||||||
|
unsigned int dummy = 0;
|
||||||
|
Init(type, dummy);
|
||||||
|
}
|
||||||
|
|
||||||
Packet::~Packet()
|
Packet::~Packet()
|
||||||
{
|
{
|
||||||
delete[] m_Data;
|
delete[] m_Data;
|
||||||
@@ -30,7 +37,6 @@ void Packet::Init(MessageType type, unsigned int & packetID)
|
|||||||
// Add message type
|
// Add message type
|
||||||
int messageType = static_cast<int>(type);
|
int messageType = static_cast<int>(type);
|
||||||
Packet::WritePrimitive<int>(messageType);
|
Packet::WritePrimitive<int>(messageType);
|
||||||
packetID = packetID % 1000; // Packet id modulos
|
|
||||||
Packet::WritePrimitive<int>(packetID);
|
Packet::WritePrimitive<int>(packetID);
|
||||||
packetID++;
|
packetID++;
|
||||||
}
|
}
|
||||||
@@ -40,7 +46,7 @@ void Packet::WriteString(const std::string& str)
|
|||||||
// Message, add one extra byte for null terminator
|
// Message, add one extra byte for null terminator
|
||||||
int sizeOfString = str.size() + 1;
|
int sizeOfString = str.size() + 1;
|
||||||
if (m_Offset + sizeOfString > m_MaxPacketSize) {
|
if (m_Offset + sizeOfString > m_MaxPacketSize) {
|
||||||
LOG_WARNING("Package::WriteString(): Data size in packet exceeded maximum package size. New size is %i bytes\n", m_MaxPacketSize*2);
|
//LOG_WARNING("Package::WriteString(): Data size in packet exceeded maximum package size. New size is %i bytes\n", m_MaxPacketSize*2);
|
||||||
resizeData();
|
resizeData();
|
||||||
}
|
}
|
||||||
memcpy(m_Data + m_Offset, str.data(), sizeOfString * sizeof(char));
|
memcpy(m_Data + m_Offset, str.data(), sizeOfString * sizeof(char));
|
||||||
@@ -50,7 +56,7 @@ void Packet::WriteString(const std::string& str)
|
|||||||
void Packet::WriteData(char * data, int sizeOfData)
|
void Packet::WriteData(char * data, int sizeOfData)
|
||||||
{
|
{
|
||||||
if (m_Offset + sizeOfData > m_MaxPacketSize) {
|
if (m_Offset + sizeOfData > m_MaxPacketSize) {
|
||||||
LOG_WARNING("Packet::WriteData(): Data size in packet exceeded maximum packet size. New size is %i bytes\n", m_MaxPacketSize*2);
|
//LOG_WARNING("Packet::WriteData(): Data size in packet exceeded maximum packet size. New size is %i bytes\n", m_MaxPacketSize*2);
|
||||||
resizeData();
|
resizeData();
|
||||||
}
|
}
|
||||||
memcpy(m_Data + m_Offset, data, sizeOfData);
|
memcpy(m_Data + m_Offset, data, sizeOfData);
|
||||||
@@ -61,7 +67,7 @@ std::string Packet::ReadString()
|
|||||||
{
|
{
|
||||||
std::string returnValue(m_Data + m_ReturnDataOffset);
|
std::string returnValue(m_Data + m_ReturnDataOffset);
|
||||||
if (m_Offset < m_ReturnDataOffset + returnValue.size()) {
|
if (m_Offset < m_ReturnDataOffset + returnValue.size()) {
|
||||||
LOG_WARNING("packet ReadString(): Oh no! You are trying to remove things outside my memory kingdom");
|
//LOG_WARNING("packet ReadString(): Oh no! You are trying to remove things outside my memory kingdom");
|
||||||
return "PopFrontString Failed";
|
return "PopFrontString Failed";
|
||||||
}
|
}
|
||||||
// +1 for null terminator.
|
// +1 for null terminator.
|
||||||
@@ -72,7 +78,7 @@ std::string Packet::ReadString()
|
|||||||
char * Packet::ReadData(int SizeOfData)
|
char * Packet::ReadData(int SizeOfData)
|
||||||
{
|
{
|
||||||
if (m_Offset < m_ReturnDataOffset + SizeOfData) {
|
if (m_Offset < m_ReturnDataOffset + SizeOfData) {
|
||||||
LOG_WARNING("packet ReadData(): Oh no! You are trying to remove things outside my memory kingdom");
|
//LOG_WARNING("packet ReadData(): Oh no! You are trying to remove things outside my memory kingdom");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
unsigned int oldReturnDataOffset = m_ReturnDataOffset;
|
unsigned int oldReturnDataOffset = m_ReturnDataOffset;
|
||||||
@@ -80,6 +86,13 @@ char * Packet::ReadData(int SizeOfData)
|
|||||||
return (m_Data + oldReturnDataOffset);
|
return (m_Data + oldReturnDataOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Packet::ChangePacketID(unsigned int & packetID)
|
||||||
|
{
|
||||||
|
packetID = packetID + 1;
|
||||||
|
// Overwrite old PacketID
|
||||||
|
memcpy(m_Data + sizeof(int), &packetID, sizeof(int));
|
||||||
|
}
|
||||||
|
|
||||||
void Packet::resizeData()
|
void Packet::resizeData()
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -87,7 +100,7 @@ void Packet::resizeData()
|
|||||||
char* holdData = new char[m_MaxPacketSize];
|
char* holdData = new char[m_MaxPacketSize];
|
||||||
// Copy our data to the newly allocated memory
|
// Copy our data to the newly allocated memory
|
||||||
memcpy(holdData, m_Data, m_Offset);
|
memcpy(holdData, m_Data, m_Offset);
|
||||||
// Increase max packet size
|
// Increase max packet size
|
||||||
m_MaxPacketSize = m_MaxPacketSize * 2;
|
m_MaxPacketSize = m_MaxPacketSize * 2;
|
||||||
// Delete our data
|
// Delete our data
|
||||||
delete m_Data;
|
delete m_Data;
|
||||||
|
|||||||
+152
-131
@@ -8,13 +8,14 @@ Server::~Server()
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Server::Start(World* world, EventBroker* eventBroker)
|
void Server::Start(World* world, EventBroker* eventBroker)
|
||||||
{
|
{
|
||||||
m_World = world;
|
m_World = world;
|
||||||
m_EventBroker = eventBroker;
|
m_EventBroker = eventBroker;
|
||||||
|
// Subscribe to events
|
||||||
|
EVENT_SUBSCRIBE_MEMBER(m_EInputCommand, &Server::OnInputCommand);
|
||||||
for (size_t i = 0; i < MAXCONNECTIONS; i++) {
|
for (size_t i = 0; i < MAXCONNECTIONS; i++) {
|
||||||
m_StopTimes[i] = std::clock();
|
m_PlayerDefinitions[i].StopTime = std::clock();
|
||||||
}
|
}
|
||||||
LOG_INFO("I am Server. BIP BOP\n");
|
LOG_INFO("I am Server. BIP BOP\n");
|
||||||
}
|
}
|
||||||
@@ -22,8 +23,10 @@ void Server::Start(World* world, EventBroker* eventBroker)
|
|||||||
void Server::Update()
|
void Server::Update()
|
||||||
{
|
{
|
||||||
readFromClients();
|
readFromClients();
|
||||||
|
m_EventBroker->Process<Server>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Server::readFromClients()
|
void Server::readFromClients()
|
||||||
{
|
{
|
||||||
while (m_Socket.available()) {
|
while (m_Socket.available()) {
|
||||||
@@ -50,7 +53,7 @@ void Server::readFromClients()
|
|||||||
|
|
||||||
// Time out logic
|
// Time out logic
|
||||||
if (checkTimeOutInterval < (1000 * (currentTime - timOutTimer) / (double)CLOCKS_PER_SEC)) {
|
if (checkTimeOutInterval < (1000 * (currentTime - timOutTimer) / (double)CLOCKS_PER_SEC)) {
|
||||||
//checkForTimeOuts();
|
checkForTimeOuts();
|
||||||
timOutTimer = currentTime;
|
timOutTimer = currentTime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -62,7 +65,7 @@ void Server::parseMessageType(Packet& packet)
|
|||||||
// Read packet ID
|
// Read packet ID
|
||||||
m_PreviousPacketID = m_PacketID; // Set previous packet id
|
m_PreviousPacketID = m_PacketID; // Set previous packet id
|
||||||
m_PacketID = packet.ReadPrimitive<int>(); //Read new packet id
|
m_PacketID = packet.ReadPrimitive<int>(); //Read new packet id
|
||||||
//IdentifyPacketLoss();
|
//identifyPacketLoss();
|
||||||
switch (static_cast<MessageType>(messageType)) {
|
switch (static_cast<MessageType>(messageType)) {
|
||||||
case MessageType::Connect:
|
case MessageType::Connect:
|
||||||
parseConnect(packet);
|
parseConnect(packet);
|
||||||
@@ -76,13 +79,18 @@ void Server::parseMessageType(Packet& packet)
|
|||||||
case MessageType::Message:
|
case MessageType::Message:
|
||||||
break;
|
break;
|
||||||
case MessageType::Snapshot:
|
case MessageType::Snapshot:
|
||||||
parseSnapshot(packet);
|
|
||||||
break;
|
break;
|
||||||
case MessageType::Disconnect:
|
case MessageType::Disconnect:
|
||||||
parseDisconnect();
|
parseDisconnect();
|
||||||
break;
|
break;
|
||||||
case MessageType::Event:
|
case MessageType::OnInputCommand:
|
||||||
parseEvent(packet);
|
parseOnInputCommand(packet);
|
||||||
|
break;
|
||||||
|
case MessageType::OnPlayerDamage:
|
||||||
|
parseOnPlayerDamage(packet);
|
||||||
|
break;
|
||||||
|
case MessageType::BecomePlayer:
|
||||||
|
createPlayer();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -98,11 +106,11 @@ int Server::receive(char * data, size_t length)
|
|||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Server::send(Packet& packet, int playerID)
|
void Server::send(Packet& packet, int userID)
|
||||||
{
|
{
|
||||||
int bytesSent = m_Socket.send_to(
|
int bytesSent = m_Socket.send_to(
|
||||||
boost::asio::buffer(packet.Data(), packet.Size()),
|
boost::asio::buffer(packet.Data(), packet.Size()),
|
||||||
m_PlayerDefinitions[playerID].Endpoint,
|
m_ConnectedUsers[userID].Endpoint,
|
||||||
0);
|
0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,27 +124,11 @@ void Server::send(Packet & packet)
|
|||||||
0);
|
0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Server::moveMessageHead(char *& data, size_t & length, size_t stepSize)
|
|
||||||
{
|
|
||||||
data += stepSize;
|
|
||||||
length -= stepSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Server::broadcast(std::string message)
|
|
||||||
{
|
|
||||||
Packet packet(MessageType::Event, m_SendPacketID);
|
|
||||||
packet.WriteString(message);
|
|
||||||
for (int i = 0; i < MAXCONNECTIONS; i++) {
|
|
||||||
if (m_PlayerDefinitions[i].Endpoint.address() != boost::asio::ip::address()) {
|
|
||||||
send(packet, i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Server::broadcast(Packet& packet)
|
void Server::broadcast(Packet& packet)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < MAXCONNECTIONS; ++i) {
|
for (int i = 0; i < m_ConnectedUsers.size(); i++) {
|
||||||
if (m_PlayerDefinitions[i].Endpoint.address() != boost::asio::ip::address()) {
|
if (m_ConnectedUsers[i].Endpoint.address() != boost::asio::ip::address()) {
|
||||||
|
packet.ChangePacketID(m_ConnectedUsers[i].PacketID);
|
||||||
send(packet, i);
|
send(packet, i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -148,14 +140,16 @@ void Server::sendSnapshot()
|
|||||||
// Should time this
|
// Should time this
|
||||||
std::unordered_map<std::string, ComponentPool*> worldComponentPools = m_World->GetComponentPools();
|
std::unordered_map<std::string, ComponentPool*> worldComponentPools = m_World->GetComponentPools();
|
||||||
for (auto& it : worldComponentPools) {
|
for (auto& it : worldComponentPools) {
|
||||||
Packet packet(MessageType::Snapshot, m_SendPacketID);
|
Packet packet(MessageType::Snapshot);
|
||||||
std::string componentType = it.first;
|
|
||||||
ComponentPool* componentPool = it.second;
|
ComponentPool* componentPool = it.second;
|
||||||
ComponentInfo componentInfo = componentPool->ComponentInfo();
|
ComponentInfo componentInfo = componentPool->ComponentInfo();
|
||||||
|
// Component Type
|
||||||
packet.WriteString(componentInfo.Name);
|
packet.WriteString(componentInfo.Name);
|
||||||
|
|
||||||
for (auto& componentWrapper : *componentPool) {
|
for (auto& componentWrapper : *componentPool) {
|
||||||
|
// Components EntityID
|
||||||
packet.WritePrimitive(componentWrapper.EntityID);
|
packet.WritePrimitive(componentWrapper.EntityID);
|
||||||
|
// Parents EntityID
|
||||||
|
packet.WritePrimitive(m_World->GetParent(componentWrapper.EntityID));
|
||||||
for (auto& componentField : componentWrapper.Info.FieldsInOrder) {
|
for (auto& componentField : componentWrapper.Info.FieldsInOrder) {
|
||||||
ComponentInfo::Field_t fieldInfo = componentInfo.Fields.at(componentField);
|
ComponentInfo::Field_t fieldInfo = componentInfo.Fields.at(componentField);
|
||||||
if (fieldInfo.Type == "string") {
|
if (fieldInfo.Type == "string") {
|
||||||
@@ -173,14 +167,14 @@ void Server::sendSnapshot()
|
|||||||
void Server::sendPing()
|
void Server::sendPing()
|
||||||
{
|
{
|
||||||
// Prints connected players ping
|
// Prints connected players ping
|
||||||
for (size_t i = 0; i < MAXCONNECTIONS; i++) {
|
for (int i = 0; i < m_ConnectedUsers.size(); i++) {
|
||||||
if (m_PlayerDefinitions[i].Endpoint.address() != boost::asio::ip::address()) {
|
if (m_ConnectedUsers[i].Endpoint.address() != boost::asio::ip::address()) {
|
||||||
int ping = 1000 * (m_StopTimes[i] - m_StartPingTime) / static_cast<double>(CLOCKS_PER_SEC);
|
int ping = 1000 * (m_ConnectedUsers[i].StopTime - m_StartPingTime) / static_cast<double>(CLOCKS_PER_SEC);
|
||||||
LOG_INFO("Last packetID received %i: Player %i's ping: %i", m_PacketID, i, ping);
|
LOG_INFO("Last packetID received %i: User %i's ping: %i", m_ConnectedUsers[i].PacketID, i, std::abs(ping));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Create ping message
|
// Create ping message
|
||||||
Packet packet(MessageType::ServerPing, m_SendPacketID);
|
Packet packet(MessageType::ServerPing);
|
||||||
packet.WriteString("Ping from server");
|
packet.WriteString("Ping from server");
|
||||||
// Time message
|
// Time message
|
||||||
m_StartPingTime = std::clock();
|
m_StartPingTime = std::clock();
|
||||||
@@ -190,16 +184,15 @@ void Server::sendPing()
|
|||||||
|
|
||||||
void Server::checkForTimeOuts()
|
void Server::checkForTimeOuts()
|
||||||
{
|
{
|
||||||
int timeOutTimeMs = 5000;
|
|
||||||
int startPing = 1000 * m_StartPingTime
|
int startPing = 1000 * m_StartPingTime
|
||||||
/ static_cast<double>(CLOCKS_PER_SEC);
|
/ static_cast<double>(CLOCKS_PER_SEC);
|
||||||
|
|
||||||
for (size_t i = 0; i < MAXCONNECTIONS; i++) {
|
for (int i = 0; i < m_ConnectedUsers.size(); i++) {
|
||||||
if (m_PlayerDefinitions[i].Endpoint.address() != boost::asio::ip::address()) {
|
if (m_ConnectedUsers[i].Endpoint.address() != boost::asio::ip::address()) {
|
||||||
int stopPing = 1000 * m_StopTimes[i]
|
int stopPing = 1000 * m_ConnectedUsers[i].StopTime /
|
||||||
/ static_cast<double>(CLOCKS_PER_SEC);
|
static_cast<double>(CLOCKS_PER_SEC);
|
||||||
if (startPing > stopPing + timeOutTimeMs) {
|
if (startPing > stopPing + TIMEOUTMS) {
|
||||||
LOG_INFO("Player %i timed out!", i);
|
LOG_INFO("User %i timed out!", i);
|
||||||
disconnect(i);
|
disconnect(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -208,92 +201,89 @@ void Server::checkForTimeOuts()
|
|||||||
|
|
||||||
void Server::disconnect(int i)
|
void Server::disconnect(int i)
|
||||||
{
|
{
|
||||||
broadcast("A player disconnected");
|
//broadcast("A player disconnected");
|
||||||
LOG_INFO("Player %i disconnected/timed out", i);
|
LOG_INFO("User %s disconnected/timed out", m_PlayerDefinitions[i].Name.c_str());
|
||||||
|
// Remove enteties and stuff (When we can remove entity, remove it and tell clients to remove the copy they have)
|
||||||
// Remove enteties and stuff
|
|
||||||
m_PlayerDefinitions[i].Endpoint = boost::asio::ip::udp::endpoint();
|
m_PlayerDefinitions[i].Endpoint = boost::asio::ip::udp::endpoint();
|
||||||
m_PlayerDefinitions[i].EntityID = -1;
|
m_PlayerDefinitions[i].EntityID = -1;
|
||||||
m_PlayerDefinitions[i].Name = "";
|
m_PlayerDefinitions[i].Name = "";
|
||||||
|
m_PlayerDefinitions[i].PacketID = 0;
|
||||||
|
m_ConnectedUsers.erase(m_ConnectedUsers.begin() + i);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Server::parseEvent(Packet& packet)
|
void Server::parseOnInputCommand(Packet& packet)
|
||||||
{
|
{
|
||||||
size_t i;
|
int playerID = -1;
|
||||||
for (i = 0; i < MAXCONNECTIONS; i++) {
|
// Check which player it was who sent the message
|
||||||
if (m_PlayerDefinitions[i].Endpoint.address() == m_ReceiverEndpoint.address()) {
|
for (int i = 0; i < MAXCONNECTIONS; i++) {
|
||||||
|
// if the player is connected set playerID to the correct PlayerID
|
||||||
|
if (m_PlayerDefinitions[i].Endpoint.address() == m_ReceiverEndpoint.address()
|
||||||
|
&& m_PlayerDefinitions[i].Endpoint.port() == m_ReceiverEndpoint.port()) {
|
||||||
|
playerID = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If no player matches the address return.
|
if (playerID != -1) {
|
||||||
if (i >= 8)
|
while (packet.DataReadSize() < packet.Size()) {
|
||||||
return;
|
Events::InputCommand e;
|
||||||
|
e.Command = packet.ReadString();
|
||||||
|
e.PlayerID = playerID; // Set correct player id
|
||||||
|
e.Value = packet.ReadPrimitive<float>();
|
||||||
|
m_EventBroker->Publish(e);
|
||||||
|
//LOG_INFO("Server::parseOnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
unsigned int entityId = m_PlayerDefinitions[i].EntityID;
|
void Server::parseOnPlayerDamage(Packet & packet)
|
||||||
std::string eventString = packet.ReadString();
|
{
|
||||||
if ("+Forward" == eventString) {
|
Events::PlayerDamage e;
|
||||||
m_World->GetComponent(entityId, "Player")["Forward"] = true;
|
e.DamageAmount = packet.ReadPrimitive<double>();
|
||||||
m_World->GetComponent(entityId, "Player")["Back"] = false;
|
e.PlayerDamagedID = packet.ReadPrimitive<EntityID>();
|
||||||
} else if ("-Forward" == eventString) {
|
e.TypeOfDamage = packet.ReadString();
|
||||||
m_World->GetComponent(entityId, "Player")["Forward"] = false;
|
m_EventBroker->Publish(e);
|
||||||
m_World->GetComponent(entityId, "Player")["Back"] = true;
|
//LOG_DEBUG("Server::parseOnPlayerDamage: Command is %s. Value is %f. PlayerID is %i.", e.DamageAmount, e.PlayerDamagedID, e.TypeOfDamage.c_str());
|
||||||
} else if ("0Forward" == eventString) {
|
|
||||||
m_World->GetComponent(entityId, "Player")["Forward"] = false;
|
|
||||||
m_World->GetComponent(entityId, "Player")["Back"] = false;
|
|
||||||
}
|
|
||||||
if ("+Right" == eventString) {
|
|
||||||
m_World->GetComponent(entityId, "Player")["Left"] = false;
|
|
||||||
m_World->GetComponent(entityId, "Player")["Right"] = true;
|
|
||||||
} else if ("-Right" == eventString) {
|
|
||||||
m_World->GetComponent(entityId, "Player")["Right"] = false;
|
|
||||||
m_World->GetComponent(entityId, "Player")["Left"] = true;
|
|
||||||
} else if ("0Right" == eventString) {
|
|
||||||
m_World->GetComponent(entityId, "Player")["Right"] = false;
|
|
||||||
m_World->GetComponent(entityId, "Player")["Left"] = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Server::parseConnect(Packet& packet)
|
void Server::parseConnect(Packet& packet)
|
||||||
{
|
{
|
||||||
LOG_INFO("Parsing connections");
|
LOG_INFO("Parsing connections");
|
||||||
// Check if player is already connected
|
// Check if player is already connected
|
||||||
for (int i = 0; i < MAXCONNECTIONS; i++) {
|
if (GetPlayerIDFromEndpoint(m_ReceiverEndpoint) != -1) {
|
||||||
if (m_PlayerDefinitions[i].Endpoint.address() == m_ReceiverEndpoint.address()) {
|
return;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < m_ConnectedUsers.size(); i++) {
|
||||||
|
if (m_ConnectedUsers[i].Endpoint.address() == m_ReceiverEndpoint.address() &&
|
||||||
|
m_ConnectedUsers[i].Endpoint.port() == m_ReceiverEndpoint.port()) {
|
||||||
|
// Already connected
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Create a new player
|
||||||
|
PlayerDefinition pd;
|
||||||
|
pd.EntityID = 0; // Overlook this
|
||||||
|
pd.Endpoint = m_ReceiverEndpoint;
|
||||||
|
pd.Name = packet.ReadString();
|
||||||
|
pd.PacketID = 0;
|
||||||
|
pd.StopTime = std::clock();
|
||||||
|
m_ConnectedUsers.push_back(pd);
|
||||||
|
LOG_INFO("Spectator \"%s\" connected on IP: %s", pd.Name.c_str(), pd.Endpoint.address().to_string().c_str());
|
||||||
|
|
||||||
for (int i = 0; i < MAXCONNECTIONS; i++) {
|
// Send a message to the player that connected
|
||||||
if (m_PlayerDefinitions[i].Endpoint.address() == boost::asio::ip::address()) {
|
Packet connnectPacket(MessageType::Connect, m_ConnectedUsers[m_ConnectedUsers.size() - 1].PacketID);
|
||||||
// Create new player
|
send(connnectPacket);
|
||||||
m_PlayerDefinitions[i].EntityID = createPlayer();
|
|
||||||
m_PlayerDefinitions[i].Endpoint = m_ReceiverEndpoint;
|
|
||||||
m_PlayerDefinitions[i].Name = packet.ReadString();
|
|
||||||
|
|
||||||
m_StopTimes[i] = std::clock();
|
// Send notification that a player has connected
|
||||||
|
Packet notificationPacket(MessageType::PlayerConnected);
|
||||||
LOG_INFO("Player \"%s\" connected on IP: %s", m_PlayerDefinitions[i].Name.c_str(), m_PlayerDefinitions[i].Endpoint.address().to_string().c_str());
|
broadcast(notificationPacket);
|
||||||
|
|
||||||
Packet packet(MessageType::Connect, m_SendPacketID);
|
|
||||||
packet.WritePrimitive<int>(i); // Player ID
|
|
||||||
|
|
||||||
send(packet, i);
|
|
||||||
|
|
||||||
// Send notification that a player has connected
|
|
||||||
std::string str = m_PacketID + "Player " + m_PlayerDefinitions[i].Name + " connected on: "
|
|
||||||
+ m_PlayerDefinitions[i].Endpoint.address().to_string();
|
|
||||||
broadcast(str);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Server::parseDisconnect()
|
void Server::parseDisconnect()
|
||||||
{
|
{
|
||||||
LOG_INFO("%i: Parsing disconnect", m_PacketID);
|
LOG_INFO("%i: Parsing disconnect", m_PacketID);
|
||||||
|
|
||||||
for (int i = 0; i < MAXCONNECTIONS; i++) {
|
for (int i = 0; i < m_ConnectedUsers.size(); i++) {
|
||||||
if (m_PlayerDefinitions[i].Endpoint.address() == m_ReceiverEndpoint.address()) {
|
if (m_ConnectedUsers[i].Endpoint.address() == m_ReceiverEndpoint.address()) {
|
||||||
disconnect(i);
|
disconnect(i);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -303,37 +293,26 @@ void Server::parseDisconnect()
|
|||||||
void Server::parseClientPing()
|
void Server::parseClientPing()
|
||||||
{
|
{
|
||||||
LOG_INFO("%i: Parsing ping", m_PacketID);
|
LOG_INFO("%i: Parsing ping", m_PacketID);
|
||||||
|
int playerID = GetPlayerIDFromEndpoint(m_ReceiverEndpoint);
|
||||||
|
if (playerID == -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
// Return ping
|
// Return ping
|
||||||
Packet packet(MessageType::ClientPing, m_SendPacketID);
|
Packet packet(MessageType::ClientPing, m_PlayerDefinitions[playerID].PacketID);
|
||||||
packet.WriteString("Ping received");
|
packet.WriteString("Ping received");
|
||||||
send(packet); // This dosen't work for multiple users
|
send(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Server::parseServerPing()
|
void Server::parseServerPing()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < MAXCONNECTIONS; i++) {
|
for (int i = 0; i < m_ConnectedUsers.size(); i++) {
|
||||||
if (m_PlayerDefinitions[i].Endpoint.address() == m_ReceiverEndpoint.address()) {
|
if (m_ConnectedUsers[i].Endpoint.address() == m_ReceiverEndpoint.address()) {
|
||||||
m_StopTimes[i] = std::clock();
|
m_ConnectedUsers[i].StopTime = std::clock();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOT USED
|
|
||||||
void Server::parseSnapshot(Packet& packet)
|
|
||||||
{
|
|
||||||
// Does no logic. Returns snapshot if client request one
|
|
||||||
// The snapshot is not a real snapshot tho...
|
|
||||||
for (int i = 0; i < MAXCONNECTIONS; i++) {
|
|
||||||
if (m_PlayerDefinitions[i].Endpoint.address() != boost::asio::ip::address()) {
|
|
||||||
m_Socket.send_to(
|
|
||||||
boost::asio::buffer("I'm sending a snapshot to you guys!"),
|
|
||||||
m_PlayerDefinitions[i].Endpoint,
|
|
||||||
0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Server::identifyPacketLoss()
|
void Server::identifyPacketLoss()
|
||||||
{
|
{
|
||||||
// if no packets lost, difference should be equal to 1
|
// if no packets lost, difference should be equal to 1
|
||||||
@@ -343,14 +322,56 @@ void Server::identifyPacketLoss()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EntityID Server::createPlayer()
|
void Server::createPlayer()
|
||||||
{
|
{
|
||||||
EntityID entityID = m_World->CreateEntity();
|
if (GetPlayerIDFromEndpoint(m_ReceiverEndpoint) != -1) {
|
||||||
ComponentWrapper transform = m_World->AttachComponent(entityID, "Transform");
|
// Already connected as player
|
||||||
transform["Position"] = glm::vec3(-1.5f, 0.f, 0.f);
|
LOG_WARNING("Already connected!");
|
||||||
ComponentWrapper model = m_World->AttachComponent(entityID, "Model");
|
return;
|
||||||
model["Resource"] = "Models/Core/UnitSphere.obj";
|
}
|
||||||
model["Color"] = glm::vec4(rand()%255 / 255.f, rand()%255 / 255.f, rand() %255 / 255.f, 1.f);
|
int userIndex;
|
||||||
ComponentWrapper player = m_World->AttachComponent(entityID, "Player");
|
for (userIndex = 0; userIndex < m_ConnectedUsers.size(); userIndex++) {
|
||||||
return entityID;
|
if (m_ConnectedUsers[userIndex].Endpoint.address() == m_ReceiverEndpoint.address() &&
|
||||||
|
m_ConnectedUsers[userIndex].Endpoint.port() == m_ReceiverEndpoint.port()) {
|
||||||
|
// Found user
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (userIndex == m_ConnectedUsers.size()) {
|
||||||
|
LOG_WARNING("Not a recognized user!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (int playerIndex = 0; playerIndex < MAXCONNECTIONS; playerIndex++) {
|
||||||
|
if (m_PlayerDefinitions[playerIndex].Endpoint.address() == boost::asio::ip::address()) {
|
||||||
|
m_PlayerDefinitions[playerIndex] = m_ConnectedUsers[userIndex];
|
||||||
|
EntityID entityID = m_World->CreateEntity();
|
||||||
|
ComponentWrapper transform = m_World->AttachComponent(entityID, "Transform");
|
||||||
|
transform["Position"] = glm::vec3(-1.5f, 0.f, 0.f);
|
||||||
|
ComponentWrapper model = m_World->AttachComponent(entityID, "Model");
|
||||||
|
model["Resource"] = "Models/Core/UnitSphere.obj";
|
||||||
|
model["Color"] = glm::vec4(rand()%255 / 255.f, rand()%255 / 255.f, rand() %255 / 255.f, 1.f);
|
||||||
|
ComponentWrapper player = m_World->AttachComponent(entityID, "Player");
|
||||||
|
m_PlayerDefinitions[playerIndex].EntityID = entityID;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LOG_WARNING("Server is full!");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int Server::GetPlayerIDFromEndpoint(boost::asio::ip::udp::endpoint endpoint)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < MAXCONNECTIONS; i++) {
|
||||||
|
if (m_PlayerDefinitions[i].Endpoint.address() == endpoint.address() &&
|
||||||
|
m_PlayerDefinitions[i].Endpoint.port() == endpoint.port()) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Server::OnInputCommand(const Events::InputCommand & e)
|
||||||
|
{
|
||||||
|
//LOG_DEBUG("Server::OnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,9 @@ set(SOURCE_FILES
|
|||||||
${SOURCE_FILES}
|
${SOURCE_FILES}
|
||||||
"Game.cpp"
|
"Game.cpp"
|
||||||
${SOURCE_FILES_Systems}
|
${SOURCE_FILES_Systems}
|
||||||
${SOURCE_FILES_Events}
|
${SOURCE_FILES_Events}
|
||||||
|
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
set(LIBRARIES
|
set(LIBRARIES
|
||||||
|
|||||||
+3
-3
@@ -68,8 +68,8 @@ Game::Game(int argc, char* argv[])
|
|||||||
|
|
||||||
|
|
||||||
// Create Octrees
|
// Create Octrees
|
||||||
m_OctreeCollision = new Octree(AABB(glm::vec3(-100), glm::vec3(100)), 4);
|
m_OctreeCollision = new Octree<AABB>(AABB(glm::vec3(-100), glm::vec3(100)), 4);
|
||||||
m_OctreeFrustrumCulling = new Octree(AABB(glm::vec3(-100), glm::vec3(100)), 4);
|
m_OctreeFrustrumCulling = new Octree<AABB>(AABB(glm::vec3(-100), glm::vec3(100)), 4);
|
||||||
// Create system pipeline
|
// Create system pipeline
|
||||||
m_SystemPipeline = new SystemPipeline(m_EventBroker);
|
m_SystemPipeline = new SystemPipeline(m_EventBroker);
|
||||||
|
|
||||||
@@ -79,6 +79,7 @@ Game::Game(int argc, char* argv[])
|
|||||||
m_SystemPipeline->AddSystem<EditorSystem>(updateOrderLevel, m_Renderer);
|
m_SystemPipeline->AddSystem<EditorSystem>(updateOrderLevel, m_Renderer);
|
||||||
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);
|
||||||
// Populate Octree with collidables
|
// Populate Octree with collidables
|
||||||
@@ -145,7 +146,6 @@ void Game::Tick()
|
|||||||
m_SystemPipeline->Update(m_World, dt);
|
m_SystemPipeline->Update(m_World, dt);
|
||||||
debugTick(dt);
|
debugTick(dt);
|
||||||
m_Renderer->Update(dt);
|
m_Renderer->Update(dt);
|
||||||
m_EventBroker->Process<Client>();
|
|
||||||
m_SoundSystem->Update(dt);
|
m_SoundSystem->Update(dt);
|
||||||
GLERROR("Game::Tick m_RenderQueueFactory->Update");
|
GLERROR("Game::Tick m_RenderQueueFactory->Update");
|
||||||
m_Renderer->Draw(*m_RenderFrame);
|
m_Renderer->Draw(*m_RenderFrame);
|
||||||
|
|||||||
@@ -0,0 +1,86 @@
|
|||||||
|
#include "Systems/InterpolationSystem.h"
|
||||||
|
|
||||||
|
//void InterpolationSystem::UpdateComponent(World * world, ComponentWrapper & transform, double dt)
|
||||||
|
//{
|
||||||
|
// if (m_InterpolationPoints[transform.EntityID].size() > 0) {
|
||||||
|
// Transform& sTransform = m_InterpolationPoints[transform.EntityID].front();
|
||||||
|
// sTransform.interpolationTime += dt;
|
||||||
|
// if (sTransform.interpolationTime > 0.05) {
|
||||||
|
// double time = std::fmod(sTransform.interpolationTime, 0.05f);
|
||||||
|
// m_InterpolationPoints[transform.EntityID].pop();
|
||||||
|
// if (m_InterpolationPoints[transform.EntityID].size() <= 0) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// sTransform = m_InterpolationPoints[transform.EntityID].front();
|
||||||
|
// sTransform.interpolationTime = time;
|
||||||
|
// }
|
||||||
|
// glm::vec3 nextPosition = sTransform.Position;
|
||||||
|
// glm::vec3 currentPosition = static_cast<glm::vec3>(transform["Position"]);
|
||||||
|
// transform["Position"] = vectorInterpolation(currentPosition, nextPosition, sTransform.interpolationTime);
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
void InterpolationSystem::UpdateComponent(World * world, EntityWrapper& entity, ComponentWrapper & transform, double dt)
|
||||||
|
{
|
||||||
|
if (m_NextTransform.find(transform.EntityID) != m_NextTransform.end()) { // Exists in map
|
||||||
|
m_NextTransform[transform.EntityID].interpolationTime += dt;
|
||||||
|
Transform sTransform = m_NextTransform[transform.EntityID];
|
||||||
|
double time = sTransform.interpolationTime;
|
||||||
|
if (time > SNAPSHOTINTERVAL) {
|
||||||
|
if (m_LastReceivedTransform.find(transform.EntityID) != m_LastReceivedTransform.end()) {
|
||||||
|
m_NextTransform[transform.EntityID] = m_LastReceivedTransform[transform.EntityID];
|
||||||
|
m_NextTransform[transform.EntityID].interpolationTime = time - SNAPSHOTINTERVAL;
|
||||||
|
sTransform = m_NextTransform[transform.EntityID];
|
||||||
|
m_LastReceivedTransform.erase(transform.EntityID);
|
||||||
|
} else {
|
||||||
|
m_NextTransform.erase(transform.EntityID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (transform.Info.Name == "Transform") {
|
||||||
|
// Position
|
||||||
|
glm::vec3 nextPosition = sTransform.Position;
|
||||||
|
glm::vec3 currentPosition = static_cast<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, sTransform.interpolationTime / SNAPSHOTINTERVAL));
|
||||||
|
// 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::OnInterpolate(const Events::Interpolate & e)
|
||||||
|
{
|
||||||
|
Transform transform;
|
||||||
|
int offset = 0;
|
||||||
|
// Read the data
|
||||||
|
memcpy(&transform.Position, e.DataArray.get() + offset, sizeof(glm::vec3));
|
||||||
|
offset += sizeof(glm::vec3);
|
||||||
|
glm::vec3 tempOrientation;
|
||||||
|
memcpy(&tempOrientation, e.DataArray.get() + offset, sizeof(glm::vec3));
|
||||||
|
transform.Orientation = glm::quat(tempOrientation);
|
||||||
|
offset += sizeof(glm::vec3);
|
||||||
|
memcpy(&transform.Scale, e.DataArray.get() + offset, sizeof(glm::vec3));
|
||||||
|
transform.interpolationTime = 0.0f;
|
||||||
|
|
||||||
|
if (m_NextTransform.find(e.Entity) != m_NextTransform.end()) { // Did exist
|
||||||
|
m_LastReceivedTransform[e.Entity] = transform;
|
||||||
|
} else { // Did not
|
||||||
|
m_NextTransform[e.Entity] = transform;
|
||||||
|
}
|
||||||
|
// Check if queue already exists
|
||||||
|
//if (m_InterpolationPoints.find(e.Entity) != m_InterpolationPoints.end()) { // Did exist, push to queue
|
||||||
|
// m_InterpolationPoints[e.Entity].push(transform);
|
||||||
|
//}
|
||||||
|
|
||||||
|
//else { // Did not exist, create queue
|
||||||
|
// std::queue<Transform> transformQueue;
|
||||||
|
// transformQueue.push(transform);
|
||||||
|
// m_InterpolationPoints[e.Entity] = transformQueue;
|
||||||
|
//}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
@@ -9,7 +9,9 @@ void PlayerMovementSystem::UpdateComponent(World* world, EntityWrapper& entity,
|
|||||||
ComponentWrapper& cPhysics = entity["Physics"];
|
ComponentWrapper& cPhysics = entity["Physics"];
|
||||||
|
|
||||||
glm::vec3& velocity = cPhysics["Velocity"];
|
glm::vec3& velocity = cPhysics["Velocity"];
|
||||||
velocity.y -= 9.82 * dt;
|
if (cPhysics["Gravity"]) {
|
||||||
|
velocity.y -= 9.82 * dt;
|
||||||
|
}
|
||||||
|
|
||||||
glm::vec3& position = cTransform["Position"];
|
glm::vec3& position = cTransform["Position"];
|
||||||
position += velocity * (float)dt;
|
position += velocity * (float)dt;
|
||||||
|
|||||||
@@ -205,9 +205,9 @@ BOOST_AUTO_TEST_CASE(octTest)
|
|||||||
{
|
{
|
||||||
glm::vec3 mini = glm::vec3(-1, -1, -1);
|
glm::vec3 mini = glm::vec3(-1, -1, -1);
|
||||||
glm::vec3 maxi = glm::vec3(1, 1, 1);
|
glm::vec3 maxi = glm::vec3(1, 1, 1);
|
||||||
Octree tree(AABB(mini, maxi), 2);
|
Octree<AABB> tree(AABB(mini, maxi), 2);
|
||||||
tree.AddDynamicObject(AABB(mini, -0.9f*maxi));
|
tree.AddDynamicObject(AABB(mini, -0.9f*maxi));
|
||||||
Octree::Output data;
|
OctSpace::Output data;
|
||||||
glm::vec3 origin = 3.0f * mini;
|
glm::vec3 origin = 3.0f * mini;
|
||||||
bool rayIntersected = tree.RayCollides(Ray(origin , mini - origin), data);
|
bool rayIntersected = tree.RayCollides(Ray(origin , mini - origin), data);
|
||||||
BOOST_CHECK(rayIntersected);
|
BOOST_CHECK(rayIntersected);
|
||||||
|
|||||||
+20
-10
@@ -13,12 +13,12 @@ BOOST_AUTO_TEST_CASE(octSameRegionTest)
|
|||||||
{
|
{
|
||||||
glm::vec3 mini = glm::vec3(-1, -1, -1);
|
glm::vec3 mini = glm::vec3(-1, -1, -1);
|
||||||
glm::vec3 maxi = glm::vec3(1, 1, 1);
|
glm::vec3 maxi = glm::vec3(1, 1, 1);
|
||||||
Octree tree(AABB(mini, maxi), 2);
|
Octree<AABB> tree(AABB(mini, maxi), 2);
|
||||||
AABB firstQuadrant(mini, 0.8f*mini);
|
AABB firstQuadrant(mini, 0.8f*mini);
|
||||||
tree.AddStaticObject(firstQuadrant);
|
tree.AddStaticObject(firstQuadrant);
|
||||||
AABB testBox(0.9f*mini, 0.8f*mini);
|
AABB testBox(0.9f*mini, 0.8f*mini);
|
||||||
std::vector<AABB> region;
|
std::vector<AABB> region;
|
||||||
tree.BoxesInSameRegion(testBox, region);
|
tree.ObjectsInSameRegion(testBox, region);
|
||||||
BOOST_REQUIRE(region.size() == 1);
|
BOOST_REQUIRE(region.size() == 1);
|
||||||
AABB& box = region[0];
|
AABB& box = region[0];
|
||||||
BOOST_CHECK_CLOSE_FRACTION(box.Origin().x, firstQuadrant.Origin().x, 0.00001f);
|
BOOST_CHECK_CLOSE_FRACTION(box.Origin().x, firstQuadrant.Origin().x, 0.00001f);
|
||||||
@@ -40,7 +40,7 @@ const int NUM_FUNCTION_LOOPS = 25;
|
|||||||
const int TESTS = 0; //10
|
const int TESTS = 0; //10
|
||||||
|
|
||||||
template<typename Tree>
|
template<typename Tree>
|
||||||
void RegionTest(Tree& tree)
|
void RegionTestOld(Tree& tree)
|
||||||
{
|
{
|
||||||
AABB aabb;
|
AABB aabb;
|
||||||
aabb.FromOriginSize(glm::vec3(rand() % LEVEL_BOUNDS, rand() % LEVEL_BOUNDS, rand() % LEVEL_BOUNDS),
|
aabb.FromOriginSize(glm::vec3(rand() % LEVEL_BOUNDS, rand() % LEVEL_BOUNDS, rand() % LEVEL_BOUNDS),
|
||||||
@@ -50,9 +50,19 @@ void RegionTest(Tree& tree)
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename Tree>
|
template<typename Tree>
|
||||||
|
void RegionTest(Tree& tree)
|
||||||
|
{
|
||||||
|
AABB aabb;
|
||||||
|
aabb.CreateFromCenter(glm::vec3(rand() % LEVEL_BOUNDS, rand() % LEVEL_BOUNDS, rand() % LEVEL_BOUNDS),
|
||||||
|
glm::vec3(rand() % MAXSIZE, rand() % MAXSIZE, rand() % MAXSIZE));
|
||||||
|
std::vector<AABB> outVec;
|
||||||
|
tree.ObjectsInSameRegion(aabb, outVec);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Tree, typename Output>
|
||||||
void RayTest(Tree& tree)
|
void RayTest(Tree& tree)
|
||||||
{
|
{
|
||||||
Tree::Output data;
|
Output data;
|
||||||
glm::vec3 rayStart = glm::vec3(rand() % LEVEL_BOUNDS, rand() % LEVEL_BOUNDS, rand() % LEVEL_BOUNDS);
|
glm::vec3 rayStart = glm::vec3(rand() % LEVEL_BOUNDS, rand() % LEVEL_BOUNDS, rand() % LEVEL_BOUNDS);
|
||||||
glm::vec3 rayEnd = glm::vec3(rand() % LEVEL_BOUNDS, rand() % LEVEL_BOUNDS, rand() % LEVEL_BOUNDS);
|
glm::vec3 rayEnd = glm::vec3(rand() % LEVEL_BOUNDS, rand() % LEVEL_BOUNDS, rand() % LEVEL_BOUNDS);
|
||||||
tree.RayCollides({ rayStart , glm::normalize(rayEnd - rayStart) }, data);
|
tree.RayCollides({ rayStart , glm::normalize(rayEnd - rayStart) }, data);
|
||||||
@@ -111,13 +121,13 @@ void TestLoop(TestFunction xTest)
|
|||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(octRegionPerfTestWithDuplicates)
|
BOOST_AUTO_TEST_CASE(octRegionPerfTestWithDuplicates)
|
||||||
{
|
{
|
||||||
TestLoop<Old::OctTree>(RegionTest<Old::OctTree>);
|
TestLoop<Old::OctTree>(RegionTestOld<Old::OctTree>);
|
||||||
BOOST_CHECK(true);
|
BOOST_CHECK(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(octRegionPerfTestNoDuplicates)
|
BOOST_AUTO_TEST_CASE(octRegionPerfTestNoDuplicates)
|
||||||
{
|
{
|
||||||
TestLoop<Octree>(RegionTest<Octree>);
|
TestLoop<Octree<AABB>>(RegionTest<Octree<AABB>>);
|
||||||
BOOST_CHECK(true);
|
BOOST_CHECK(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,19 +139,19 @@ BOOST_AUTO_TEST_CASE(octBoxPerfTestWithDuplicates)
|
|||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(octBoxPerfTestNoDuplicates)
|
BOOST_AUTO_TEST_CASE(octBoxPerfTestNoDuplicates)
|
||||||
{
|
{
|
||||||
TestLoop<Octree>(BoxTest<Octree>);
|
TestLoop<Octree<AABB>>(BoxTest<Octree<AABB>>);
|
||||||
BOOST_CHECK(true);
|
BOOST_CHECK(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(octRayPerfTestWithDuplicates)
|
BOOST_AUTO_TEST_CASE(octRayPerfTestWithDuplicates)
|
||||||
{
|
{
|
||||||
TestLoop<Old::OctTree>(RayTest<Old::OctTree>);
|
TestLoop<Old::OctTree>(RayTest<Old::OctTree, Old::OctTree::Output>);
|
||||||
BOOST_CHECK(true);
|
BOOST_CHECK(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(octRayPerfTestNoDuplicates)
|
BOOST_AUTO_TEST_CASE(octRayPerfTestNoDuplicates)
|
||||||
{
|
{
|
||||||
TestLoop<Octree>(RayTest<Octree>);
|
TestLoop<Octree<AABB>>(RayTest<Octree<AABB>, OctSpace::Output>);
|
||||||
BOOST_CHECK(true);
|
BOOST_CHECK(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,7 +163,7 @@ BOOST_AUTO_TEST_CASE(octNopPerfTestWithDuplicates)
|
|||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(octNopPerfTestNoDuplicates)
|
BOOST_AUTO_TEST_CASE(octNopPerfTestNoDuplicates)
|
||||||
{
|
{
|
||||||
TestLoop<Octree>(NopTest<Octree>);
|
TestLoop<Octree<AABB>>(NopTest<Octree<AABB>>);
|
||||||
BOOST_CHECK(true);
|
BOOST_CHECK(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user