@@ -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
|
||||||
|
|||||||
+1
-1
@@ -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"
|
||||||
|
|||||||
@@ -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
|
||||||
+152
-127
@@ -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
|
||||||
|
if (componentType == "Transform") {
|
||||||
|
InterpolateFields(packet, componentInfo, entityID, componentType);
|
||||||
|
} else {
|
||||||
updateFields(packet, componentInfo, entityID, componentType);
|
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,77 +244,74 @@ 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
|
||||||
|
if (e.Value > 0) {
|
||||||
connect();
|
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);
|
||||||
|
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 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()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|||||||
+144
-123
@@ -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();
|
|
||||||
|
|
||||||
LOG_INFO("Player \"%s\" connected on IP: %s", m_PlayerDefinitions[i].Name.c_str(), m_PlayerDefinitions[i].Endpoint.address().to_string().c_str());
|
|
||||||
|
|
||||||
Packet packet(MessageType::Connect, m_SendPacketID);
|
|
||||||
packet.WritePrimitive<int>(i); // Player ID
|
|
||||||
|
|
||||||
send(packet, i);
|
|
||||||
|
|
||||||
// Send notification that a player has connected
|
// Send notification that a player has connected
|
||||||
std::string str = m_PacketID + "Player " + m_PlayerDefinitions[i].Name + " connected on: "
|
Packet notificationPacket(MessageType::PlayerConnected);
|
||||||
+ m_PlayerDefinitions[i].Endpoint.address().to_string();
|
broadcast(notificationPacket);
|
||||||
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,8 +322,28 @@ void Server::identifyPacketLoss()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EntityID Server::createPlayer()
|
void Server::createPlayer()
|
||||||
{
|
{
|
||||||
|
if (GetPlayerIDFromEndpoint(m_ReceiverEndpoint) != -1) {
|
||||||
|
// Already connected as player
|
||||||
|
LOG_WARNING("Already connected!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int userIndex;
|
||||||
|
for (userIndex = 0; userIndex < m_ConnectedUsers.size(); userIndex++) {
|
||||||
|
if (m_ConnectedUsers[userIndex].Endpoint.address() == m_ReceiverEndpoint.address() &&
|
||||||
|
m_ConnectedUsers[userIndex].Endpoint.port() == m_ReceiverEndpoint.port()) {
|
||||||
|
// Found user
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (userIndex == m_ConnectedUsers.size()) {
|
||||||
|
LOG_WARNING("Not a recognized user!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (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();
|
EntityID entityID = m_World->CreateEntity();
|
||||||
ComponentWrapper transform = m_World->AttachComponent(entityID, "Transform");
|
ComponentWrapper transform = m_World->AttachComponent(entityID, "Transform");
|
||||||
transform["Position"] = glm::vec3(-1.5f, 0.f, 0.f);
|
transform["Position"] = glm::vec3(-1.5f, 0.f, 0.f);
|
||||||
@@ -352,5 +351,27 @@ EntityID Server::createPlayer()
|
|||||||
model["Resource"] = "Models/Core/UnitSphere.obj";
|
model["Resource"] = "Models/Core/UnitSphere.obj";
|
||||||
model["Color"] = glm::vec4(rand()%255 / 255.f, rand()%255 / 255.f, rand() %255 / 255.f, 1.f);
|
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");
|
ComponentWrapper player = m_World->AttachComponent(entityID, "Player");
|
||||||
return entityID;
|
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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ set(SOURCE_FILES
|
|||||||
"Game.cpp"
|
"Game.cpp"
|
||||||
${SOURCE_FILES_Systems}
|
${SOURCE_FILES_Systems}
|
||||||
${SOURCE_FILES_Events}
|
${SOURCE_FILES_Events}
|
||||||
|
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
set(LIBRARIES
|
set(LIBRARIES
|
||||||
|
|||||||
+1
-1
@@ -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;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user