Merge remote-tracking branch 'origin/TCPConnections' into WeaponSystem
# Conflicts: # include/Engine/Network/Server.h # src/Engine/Network/Client.cpp # src/Engine/Network/Server.cpp
This commit is contained in:
@@ -13,6 +13,8 @@
|
||||
#include "Network/Network.h"
|
||||
#include "Network/MessageType.h"
|
||||
#include "Network/PlayerDefinition.h"
|
||||
#include "Network/UDPClient.h"
|
||||
#include "Network/TCPClient.h"
|
||||
#include "Network/SnapshotDefinitions.h"
|
||||
#include "Core/World.h"
|
||||
#include "Core/EventBroker.h"
|
||||
@@ -33,17 +35,15 @@ public:
|
||||
void Connect(std::string address, int port);
|
||||
void Update() override;
|
||||
|
||||
private:
|
||||
std::vector<Events::PlayerSpawned> m_PlayerSpawnEvents;
|
||||
void parseSpawnEvents();
|
||||
// Save for children
|
||||
std::unique_ptr<SnapshotFilter> m_SnapshotFilter = nullptr;
|
||||
|
||||
// Assio UDP logic
|
||||
boost::asio::ip::udp::endpoint m_ReceiverEndpoint;
|
||||
boost::asio::io_service m_IOService;
|
||||
boost::asio::ip::udp::socket m_Socket;
|
||||
|
||||
std::string m_Address;
|
||||
int m_Port = 0;
|
||||
// Sending message to server logic
|
||||
size_t bytesRead = 0;
|
||||
char readBuf[INPUTSIZE] = { 0 };
|
||||
|
||||
// Packet loss logic
|
||||
PacketID m_PacketID = 0;
|
||||
@@ -72,16 +72,14 @@ private:
|
||||
std::vector<Events::InputCommand> m_InputCommandBuffer;
|
||||
|
||||
// Private member functions
|
||||
void readFromServer();
|
||||
size_t receive(char* data);
|
||||
void send(Packet& packet);
|
||||
void connect();
|
||||
void disconnect();
|
||||
void parseMessageType(Packet& packet);
|
||||
void updateFields(Packet& packet, const ComponentInfo& componentInfo, const EntityID& entityID);
|
||||
SharedComponentWrapper createSharedComponent(Packet& packet, EntityID entityID, const ComponentInfo& componentInfo);
|
||||
void ignoreFields(Packet& packet, const ComponentInfo& componentInfo);
|
||||
void parseConnect(Packet& packet);
|
||||
void parseUDPConnect(Packet& packet);
|
||||
void parseTCPConnect(Packet& packet);
|
||||
void parsePlayerConnected(Packet& packet);
|
||||
void parsePing();
|
||||
void parseKick();
|
||||
@@ -91,7 +89,7 @@ private:
|
||||
void InterpolateFields(Packet & packet, const ComponentInfo & componentInfo, const EntityID & entityID, const std::string & componentType);
|
||||
void parseSnapshot(Packet& packet);
|
||||
void identifyPacketLoss();
|
||||
bool hasServerTimedOut();
|
||||
void hasServerTimedOut();
|
||||
EntityID createPlayer();
|
||||
void sendInputCommands();
|
||||
void sendLocalPlayerTransform();
|
||||
@@ -111,6 +109,10 @@ private:
|
||||
bool OnPlayerDamage(const Events::PlayerDamage& e);
|
||||
EventRelay<Client, Events::PlayerSpawned> m_EPlayerSpawned;
|
||||
bool OnPlayerSpawned(const Events::PlayerSpawned& e);
|
||||
|
||||
private:
|
||||
UDPClient m_Unreliable;
|
||||
TCPClient m_Reliable;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
#ifndef HybridClient_h__
|
||||
#define HybridClient_h__
|
||||
|
||||
class HybridClient
|
||||
{
|
||||
public:
|
||||
HybridClient();
|
||||
~HybridClient();
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
#ifndef HybridServer_h__
|
||||
#define HybridServer_h__
|
||||
|
||||
class HybridServer
|
||||
{
|
||||
public:
|
||||
HybridServer();
|
||||
~HybridServer();
|
||||
private:
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -18,7 +18,8 @@ enum class MessageType
|
||||
OnPlayerSpawned,
|
||||
EntityDeleted,
|
||||
ComponentDeleted,
|
||||
PlayerTransform
|
||||
PlayerTransform,
|
||||
Invalid
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
#define INPUTSIZE 32000
|
||||
#define BUFFERSIZE 32000
|
||||
typedef unsigned int PlayerID;
|
||||
typedef unsigned int PacketID;
|
||||
|
||||
@@ -35,6 +35,8 @@ protected:
|
||||
std::clock_t m_SaveDataTimer;
|
||||
unsigned int m_MaxConnections;
|
||||
double m_TimeoutMs;
|
||||
void logSentData(int bytesSent);
|
||||
void logReceivedData(int bytesReceived);
|
||||
void saveToFile();
|
||||
void updateNetworkData();
|
||||
};
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
#ifndef NetworkClient_h__
|
||||
#define NetworkClient_h__
|
||||
|
||||
#include "Network/Packet.h"
|
||||
#define BUFFERSIZE 32000
|
||||
typedef unsigned int PlayerID;
|
||||
typedef unsigned int PacketID;
|
||||
|
||||
class NetworkClient
|
||||
{
|
||||
public:
|
||||
virtual void Connect(std::string playerName, std::string address, int port) = 0;
|
||||
virtual void Disconnect() = 0;
|
||||
virtual void Receive(Packet& packet) = 0;
|
||||
virtual void Send(Packet & packet) = 0;
|
||||
virtual bool IsSocketAvailable() = 0;
|
||||
protected:
|
||||
char m_ReadBuffer[BUFFERSIZE] = { 0 };
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,21 @@
|
||||
#ifndef NetworkServer_h__
|
||||
#define NetworkServer_h__
|
||||
#include <boost/asio.hpp>
|
||||
#include "Network/Packet.h"
|
||||
#include "Network/PlayerDefinition.h"
|
||||
#define BUFFERSIZE 32000
|
||||
typedef unsigned int PlayerID;
|
||||
typedef unsigned int PacketID;
|
||||
|
||||
class NetworkServer
|
||||
{
|
||||
public:
|
||||
virtual void AcceptNewConnections(int& nextPlayerID, std::map<PlayerID, PlayerDefinition>& connectedPlayers) = 0;
|
||||
virtual void Receive(Packet & packet, PlayerDefinition & playerDefinition) = 0;
|
||||
virtual void Send(Packet & packet, PlayerDefinition & playerDefinition) = 0;
|
||||
virtual void Send(Packet & packet) = 0;
|
||||
protected:
|
||||
char m_ReadBuffer[BUFFERSIZE] = { 0 };
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -49,10 +49,15 @@ public:
|
||||
void WriteData(char* data, int sizeOfData);
|
||||
// Pops the first element as if it was a string.
|
||||
std::string ReadString();
|
||||
// Construct a packet
|
||||
void ReconstructFromData(char* data, size_t SizeOfData);
|
||||
// Update size of packet variable in header
|
||||
void UpdateSize();
|
||||
char* ReadData(int SizeOfData);
|
||||
void ChangePacketID(unsigned int& packetID);
|
||||
size_t Size() { return m_Offset; };
|
||||
char* Data() { return m_Data; };
|
||||
MessageType GetMessageType();
|
||||
size_t DataReadSize() { return m_ReturnDataOffset; }
|
||||
size_t MaxSize() { return m_MaxPacketSize; }
|
||||
size_t HeaderSize() { return m_HeaderSize; }
|
||||
@@ -64,6 +69,7 @@ private:
|
||||
size_t m_MaxPacketSize = 512;
|
||||
size_t m_HeaderSize = 0;
|
||||
void resizeData();
|
||||
void resizeData(int size);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -2,6 +2,7 @@
|
||||
#define PlayerDefinition_h__
|
||||
#include <string>
|
||||
#include "../Core/Entity.h"
|
||||
#include <boost/asio.hpp>
|
||||
|
||||
struct PlayerDefinition {
|
||||
::EntityID EntityID = EntityID_Invalid;
|
||||
@@ -9,6 +10,10 @@ struct PlayerDefinition {
|
||||
boost::asio::ip::udp::endpoint Endpoint;
|
||||
unsigned int PacketID;
|
||||
std::clock_t StopTime;
|
||||
boost::asio::ip::address TCPAddress;
|
||||
unsigned short TCPPort;
|
||||
// use for tcp connections
|
||||
boost::shared_ptr<boost::asio::ip::tcp::socket> TCPSocket;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -5,8 +5,9 @@
|
||||
#include <ctime>
|
||||
|
||||
#include <glm/common.hpp>
|
||||
#include <boost/asio/ip/udp.hpp>
|
||||
|
||||
#include "Network/TCPServer.h"
|
||||
#include "Network/UDPServer.h"
|
||||
#include "Network/MessageType.h"
|
||||
#include "Network/PlayerDefinition.h"
|
||||
#include "Core/World.h"
|
||||
@@ -28,28 +29,29 @@ public:
|
||||
void Update() override;
|
||||
|
||||
private:
|
||||
// Network channels
|
||||
TCPServer m_Reliable;
|
||||
UDPServer m_Unreliable;
|
||||
// dont forget to set these in the childrens receive logic
|
||||
boost::asio::ip::address m_Address;
|
||||
int m_Port = 27666;
|
||||
// UDP logic
|
||||
boost::asio::ip::udp::endpoint m_ReceiverEndpoint;
|
||||
boost::asio::io_service m_IOService;
|
||||
std::unique_ptr<boost::asio::ip::udp::socket> m_Socket;
|
||||
|
||||
// Sending messages to client logic
|
||||
std::map<PlayerID, PlayerDefinition> m_ConnectedPlayers;
|
||||
std::vector<PlayerID> m_PlayersToDisconnect;
|
||||
// HACK: Fix INPUTSIZE
|
||||
char readBuffer[INPUTSIZE] = { 0 };
|
||||
char readBuffer[BUFFERSIZE] = { 0 };
|
||||
size_t bytesRead = 0;
|
||||
// time for previouse message
|
||||
std::clock_t previousePingMessage = std::clock();
|
||||
std::clock_t previousSnapshotMessage = std::clock();
|
||||
std::clock_t timOutTimer = std::clock();
|
||||
|
||||
// How often we send messages (milliseconds)
|
||||
float pingIntervalMs;
|
||||
float snapshotInterval;
|
||||
int checkTimeOutInterval = 100;
|
||||
int m_NextPlayerID = 0;
|
||||
std::vector<Events::InputCommand> m_InputCommandsToBroadcast;
|
||||
|
||||
//Timers
|
||||
std::clock_t m_StartPingTime;
|
||||
|
||||
@@ -58,11 +60,9 @@ private:
|
||||
PacketID m_PreviousPacketID = 0;
|
||||
|
||||
// Private member functions
|
||||
size_t receive(char* data);
|
||||
void readFromClients();
|
||||
void send(PlayerID player, Packet& packet);
|
||||
void send(Packet& packet);
|
||||
void broadcast(Packet& packet);
|
||||
//int receive(char* data);
|
||||
void reliableBroadcast(Packet& packet);
|
||||
void unreliableBroadcast(Packet& packet);
|
||||
void sendSnapshot();
|
||||
void addChildrenToPacket(Packet& packet, EntityID entityID);
|
||||
void addInputCommandsToPacket(Packet& packet);
|
||||
@@ -70,15 +70,18 @@ private:
|
||||
void checkForTimeOuts();
|
||||
void disconnect(PlayerID playerID);
|
||||
void parseMessageType(Packet& packet);
|
||||
void parseOnInputCommand(Packet& packet);
|
||||
void parseOnPlayerDamage(Packet& packet);
|
||||
void parseConnect(Packet& packet);
|
||||
void parseDisconnect();
|
||||
void parseClientPing();
|
||||
void parsePing();
|
||||
void identifyPacketLoss();
|
||||
void kick(PlayerID player);
|
||||
PlayerID GetPlayerIDFromEndpoint(boost::asio::ip::udp::endpoint endpoint);
|
||||
PlayerID GetPlayerIDFromEndpoint();
|
||||
void parsePlayerTransform(Packet& packet);
|
||||
void parseOnInputCommand(Packet& packet);
|
||||
void parseClientPing();
|
||||
void parsePing();
|
||||
void parseUDPConnect(Packet & packet);
|
||||
void parseTCPConnect(Packet & packet);
|
||||
void parseDisconnect();
|
||||
|
||||
// Debug event
|
||||
EventRelay<Server, Events::InputCommand> m_EInputCommand;
|
||||
bool OnInputCommand(const Events::InputCommand& e);
|
||||
@@ -88,7 +91,6 @@ private:
|
||||
bool OnEntityDeleted(const Events::EntityDeleted& e);
|
||||
EventRelay<Server, Events::ComponentDeleted> m_EComponentDeleted;
|
||||
bool OnComponentDeleted(const Events::ComponentDeleted& e);
|
||||
void parsePlayerTransform(Packet& packet);
|
||||
bool shouldSendToClient(EntityWrapper childEntity);
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
#ifndef TCPClient_h__
|
||||
#define TCPClient_h__
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include "NetworkClient.h"
|
||||
|
||||
class TCPClient : public NetworkClient
|
||||
{
|
||||
public:
|
||||
TCPClient();
|
||||
~TCPClient();
|
||||
|
||||
void Connect(std::string playerName, std::string address, int port);
|
||||
void Disconnect();
|
||||
void Receive(Packet& packet);
|
||||
void Send(Packet & packet);
|
||||
bool IsSocketAvailable();
|
||||
private:
|
||||
// Assio TCP logic
|
||||
boost::asio::ip::tcp::endpoint m_Endpoint;
|
||||
boost::asio::io_service m_IOService;
|
||||
std::unique_ptr<boost::asio::ip::tcp::socket> m_Socket;
|
||||
size_t readBuffer(char* data);
|
||||
PacketID m_SendPacketID = 0;
|
||||
bool m_IsConnected = false;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,31 @@
|
||||
#ifndef TCPServer_h__
|
||||
#define TCPServer_h__
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <map>
|
||||
#include "NetworkServer.h"
|
||||
|
||||
class TCPServer : public NetworkServer
|
||||
{
|
||||
public:
|
||||
TCPServer();
|
||||
~TCPServer();
|
||||
void AcceptNewConnections(int& nextPlayerID, std::map<PlayerID, PlayerDefinition>& connectedPlayers);
|
||||
void Receive(Packet & packet, PlayerDefinition & playerDefinition);
|
||||
void Send(Packet & packet, PlayerDefinition & playerDefinition);
|
||||
void Send(Packet & packet);
|
||||
void Disconnect();
|
||||
private:
|
||||
// TCP logic
|
||||
boost::asio::io_service m_IOService;
|
||||
std::unique_ptr<boost::asio::ip::tcp::acceptor> acceptor;
|
||||
boost::shared_ptr<boost::asio::ip::tcp::socket> lastReceivedSocket;
|
||||
|
||||
void handle_accept(boost::shared_ptr<boost::asio::ip::tcp::socket> socket,
|
||||
int& nextPlayerID, std::map<PlayerID, PlayerDefinition>& connectedPlayers,
|
||||
const boost::system::error_code& error);
|
||||
int readBuffer(char* data, PlayerDefinition& playerDefinition);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,27 @@
|
||||
#ifndef UDPClient_h__
|
||||
#define UDPClient_h__
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include "Network/NetworkClient.h"
|
||||
|
||||
class UDPClient : public NetworkClient
|
||||
{
|
||||
public:
|
||||
UDPClient();
|
||||
~UDPClient();
|
||||
|
||||
void Connect(std::string playerName, std::string address, int port);
|
||||
void Disconnect();
|
||||
void Receive(Packet& packet);
|
||||
void Send(Packet & packet);
|
||||
bool IsSocketAvailable();
|
||||
private:
|
||||
// Assio UDP logic
|
||||
boost::asio::io_service m_IOService;
|
||||
boost::asio::ip::udp::endpoint m_ReceiverEndpoint;
|
||||
boost::shared_ptr<boost::asio::ip::udp::socket> m_Socket;
|
||||
int readBuffer(char* data);
|
||||
PacketID m_SendPacketID = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,25 @@
|
||||
#ifndef UDPServer_h__
|
||||
#define UDPServer_h__
|
||||
|
||||
#include "NetworkServer.h"
|
||||
#include <boost/asio/ip/udp.hpp>
|
||||
|
||||
class UDPServer : public NetworkServer
|
||||
{
|
||||
public:
|
||||
UDPServer();
|
||||
~UDPServer();
|
||||
void AcceptNewConnections(int& nextPlayerID, std::map<PlayerID, PlayerDefinition>& connectedPlayers);
|
||||
void Receive(Packet & packet, PlayerDefinition & playerDefinition);
|
||||
void Send(Packet & packet, PlayerDefinition & playerDefinition);
|
||||
void Send(Packet & packet);
|
||||
bool IsSocketAvailable();
|
||||
private:
|
||||
// UDP logic
|
||||
boost::asio::io_service m_IOService;
|
||||
boost::asio::ip::udp::endpoint m_ReceiverEndpoint;
|
||||
std::unique_ptr<boost::asio::ip::udp::socket> m_Socket;
|
||||
int readBuffer(char* data);
|
||||
};
|
||||
|
||||
#endif
|
||||
+106
-92
@@ -1,10 +1,8 @@
|
||||
#include "Network/Client.h"
|
||||
|
||||
using namespace boost::asio::ip;
|
||||
|
||||
Client::Client(World* world, EventBroker* eventBroker)
|
||||
: Network(world, eventBroker)
|
||||
, m_Socket(m_IOService)
|
||||
{
|
||||
// Asumes root node is EntityID_Invalid
|
||||
insertIntoServerClientMaps(EntityID_Invalid, EntityID_Invalid);
|
||||
@@ -14,7 +12,6 @@ Client::Client(World* world, EventBroker* eventBroker)
|
||||
auto config = ResourceManager::Load<ConfigFile>("Config.ini");
|
||||
m_PlayerName = config->Get<std::string>("Networking.Name", "Raptorcopter");
|
||||
m_SendInputIntervalMs = config->Get<int>("Networking.SendInputIntervalMs", 33);
|
||||
|
||||
LOG_INFO("Client initialized");
|
||||
}
|
||||
|
||||
@@ -26,70 +23,77 @@ Client::Client(World* world, EventBroker* eventBroker, std::unique_ptr<SnapshotF
|
||||
|
||||
Client::~Client()
|
||||
{ }
|
||||
|
||||
// Need to call connect at start
|
||||
void Client::Connect(std::string address, int port)
|
||||
{
|
||||
// Subscribe to events
|
||||
EVENT_SUBSCRIBE_MEMBER(m_EInputCommand, &Client::OnInputCommand);
|
||||
EVENT_SUBSCRIBE_MEMBER(m_EPlayerDamage, &Client::OnPlayerDamage);
|
||||
EVENT_SUBSCRIBE_MEMBER(m_EPlayerSpawned, &Client::OnPlayerSpawned);
|
||||
|
||||
auto config = ResourceManager::Load<ConfigFile>("Config.ini");
|
||||
m_Address = address;
|
||||
if (address.empty()) {
|
||||
address = config->Get<std::string>("Networking.Address", "127.0.0.1");
|
||||
m_Address = config->Get<std::string>("Networking.Address", "127.0.0.1");
|
||||
}
|
||||
m_Port = port;
|
||||
if (port == 0) {
|
||||
port = config->Get<int>("Networking.Port", 27666);
|
||||
m_Port = config->Get<int>("Networking.Port", 27666);
|
||||
}
|
||||
|
||||
m_ReceiverEndpoint = udp::endpoint(boost::asio::ip::address::from_string(address), port);
|
||||
LOG_INFO("Client connecting...");
|
||||
m_Socket.connect(m_ReceiverEndpoint);
|
||||
connect();
|
||||
}
|
||||
|
||||
void Client::Update()
|
||||
{
|
||||
m_EventBroker->Process<Client>();
|
||||
readFromServer();
|
||||
while (m_Unreliable.IsSocketAvailable()) {
|
||||
// Packet will get real data in receive
|
||||
Packet packet(MessageType::Invalid);
|
||||
m_Unreliable.Receive(packet);
|
||||
if (packet.GetMessageType() == MessageType::Connect) {
|
||||
parseUDPConnect(packet);
|
||||
} else {
|
||||
parseMessageType(packet);
|
||||
}
|
||||
}
|
||||
while (m_Reliable.IsSocketAvailable()) {
|
||||
// Packet will get real data in receive
|
||||
Packet packet(MessageType::Invalid);
|
||||
m_Reliable.Receive(packet);
|
||||
if (packet.GetMessageType() == MessageType::Connect) {
|
||||
parseTCPConnect(packet);
|
||||
} else {
|
||||
parseMessageType(packet);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (m_IsConnected) {
|
||||
hasServerTimedOut();
|
||||
// Don't sent 1 input in 1 packet, bunch em up.
|
||||
// Don't send 1 input in 1 packet, bunch em up.
|
||||
if (m_SendInputIntervalMs < (1000 * (std::clock() - m_TimeSinceSentInputs) / (double)CLOCKS_PER_SEC)) {
|
||||
sendInputCommands();
|
||||
m_TimeSinceSentInputs = std::clock();
|
||||
}
|
||||
// HACK: Send absolute player positions for now to avoid desync until we have reliable messages
|
||||
sendLocalPlayerTransform();
|
||||
}
|
||||
Network::Update();
|
||||
}
|
||||
|
||||
void Client::readFromServer()
|
||||
{
|
||||
while (m_Socket.available()) {
|
||||
bytesRead = receive(readBuf);
|
||||
if (bytesRead > 0) {
|
||||
Packet packet(readBuf, bytesRead);
|
||||
parseMessageType(packet);
|
||||
}
|
||||
hasServerTimedOut();
|
||||
}
|
||||
//Network::Update();
|
||||
}
|
||||
|
||||
void Client::parseMessageType(Packet& packet)
|
||||
{
|
||||
// Pop packetSize which is used by TCP Client to
|
||||
// create a packet of the correct size
|
||||
packet.ReadPrimitive<int>();
|
||||
int messageType = packet.ReadPrimitive<int>();
|
||||
if (messageType == -1)
|
||||
return;
|
||||
// Read packet ID
|
||||
m_PreviousPacketID = m_PacketID; // Set previous packet id
|
||||
m_PacketID = packet.ReadPrimitive<int>(); //Read new packet id
|
||||
identifyPacketLoss();
|
||||
//identifyPacketLoss();
|
||||
|
||||
switch (static_cast<MessageType>(messageType)) {
|
||||
case MessageType::Connect:
|
||||
parseConnect(packet);
|
||||
break;
|
||||
case MessageType::Ping:
|
||||
parsePing();
|
||||
break;
|
||||
@@ -120,12 +124,32 @@ void Client::parseMessageType(Packet& packet)
|
||||
}
|
||||
}
|
||||
|
||||
void Client::parseConnect(Packet& packet)
|
||||
void Client::parseUDPConnect(Packet& packet)
|
||||
{
|
||||
// Map ServerEntityID and your PlayerID
|
||||
LOG_INFO("I be connected PogChamp");
|
||||
}
|
||||
|
||||
void Client::parseTCPConnect(Packet& packet)
|
||||
{
|
||||
LOG_INFO("Received TCP connect from server");
|
||||
// Pop size of message int
|
||||
packet.ReadPrimitive<int>();
|
||||
int messageType = packet.ReadPrimitive<int>();
|
||||
// Read packet ID
|
||||
m_PreviousPacketID = m_PacketID; // Set previous packet id
|
||||
m_PacketID = packet.ReadPrimitive<int>(); //Read new packet id
|
||||
// parse player id and other stuff
|
||||
m_PlayerID = packet.ReadPrimitive<int>();
|
||||
m_PlayerID = packet.ReadPrimitive<int>();
|
||||
LOG_INFO("A Player connected");
|
||||
Packet UnreliablePacket(MessageType::Connect, m_SendPacketID);
|
||||
// Add player id and other stuff
|
||||
packet.WritePrimitive(m_PlayerID);
|
||||
m_Unreliable.Send(packet);
|
||||
LOG_INFO("Sent UDP Connect Server");
|
||||
}
|
||||
|
||||
void Client::parsePlayerConnected(Packet & packet)
|
||||
{
|
||||
// Map ServerEntityID and other player's PlayerID
|
||||
@@ -143,7 +167,7 @@ void Client::parsePing()
|
||||
|
||||
Packet packet(MessageType::Ping, m_SendPacketID);
|
||||
packet.WriteString("Ping recieved");
|
||||
send(packet);
|
||||
m_Reliable.Send(packet);
|
||||
}
|
||||
|
||||
void Client::parseKick()
|
||||
@@ -152,14 +176,42 @@ void Client::parseKick()
|
||||
m_IsConnected = false;
|
||||
}
|
||||
|
||||
void Client::parseSpawnEvents()
|
||||
{
|
||||
std::vector<Events::PlayerSpawned> tempSpawn;
|
||||
for (int i = 0; i < m_PlayerSpawnEvents.size(); i++) {
|
||||
Events::PlayerSpawned e;
|
||||
if (!serverClientMapsHasEntity(m_PlayerSpawnEvents.at(i).Player.ID) ||
|
||||
!serverClientMapsHasEntity(m_PlayerSpawnEvents.at(i).Spawner.ID)) {
|
||||
tempSpawn.push_back(m_PlayerSpawnEvents.at(i));
|
||||
continue;
|
||||
}
|
||||
e.Player = EntityWrapper(m_World, m_ServerIDToClientID.at(m_PlayerSpawnEvents.at(i).Player.ID));
|
||||
e.Spawner = EntityWrapper(m_World, m_ServerIDToClientID.at(m_PlayerSpawnEvents.at(i).Spawner.ID));
|
||||
e.PlayerID = -1;
|
||||
e.PlayerName = m_PlayerSpawnEvents.at(i).PlayerName;
|
||||
m_EventBroker->Publish(e);
|
||||
}
|
||||
m_PlayerSpawnEvents = tempSpawn;
|
||||
// m_PlayerSpawnEvents.clear();
|
||||
}
|
||||
|
||||
void Client::parsePlayersSpawned(Packet& packet)
|
||||
{
|
||||
//Events::PlayerSpawned e;
|
||||
//e.Player = EntityWrapper(m_World, m_ServerIDToClientID[packet.ReadPrimitive<EntityID>()]);
|
||||
//e.Spawner = EntityWrapper(m_World, m_ServerIDToClientID[packet.ReadPrimitive<EntityID>()]);
|
||||
//e.PlayerID = -1;
|
||||
//e.PlayerName = packet.ReadString();
|
||||
//m_EventBroker->Publish(e);
|
||||
|
||||
Events::PlayerSpawned e;
|
||||
e.Player = EntityWrapper(m_World, m_ServerIDToClientID[packet.ReadPrimitive<EntityID>()]);
|
||||
e.Spawner = EntityWrapper(m_World, m_ServerIDToClientID[packet.ReadPrimitive<EntityID>()]);
|
||||
e.Player = EntityWrapper(m_World, packet.ReadPrimitive<EntityID>());
|
||||
e.Spawner = EntityWrapper(m_World, packet.ReadPrimitive<EntityID>());
|
||||
e.PlayerID = -1;
|
||||
e.PlayerName = packet.ReadString();
|
||||
m_EventBroker->Publish(e);
|
||||
m_PlayerSpawnEvents.push_back(e);
|
||||
parseSpawnEvents();
|
||||
}
|
||||
|
||||
void Client::parseEntityDeletion(Packet & packet)
|
||||
@@ -235,7 +287,8 @@ void Client::parseSnapshot(Packet& packet)
|
||||
for (std::size_t i = 0; i < numInputCommands; ++i) {
|
||||
Events::InputCommand e;
|
||||
e.PlayerID = packet.ReadPrimitive<EntityID>();
|
||||
e.Player = EntityWrapper(m_World, m_ServerIDToClientID.at(packet.ReadPrimitive<EntityID>()));
|
||||
EntityID player = packet.ReadPrimitive<EntityID>();
|
||||
e.Player = EntityWrapper(m_World, m_ServerIDToClientID.at(player));
|
||||
e.Command = packet.ReadString();
|
||||
e.Value = packet.ReadPrimitive<float>();
|
||||
m_EventBroker->Publish(e);
|
||||
@@ -297,56 +350,17 @@ void Client::parseSnapshot(Packet& packet)
|
||||
m_World->SetParent(localEntityID, m_ServerIDToClientID.at(serverParentID));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t Client::receive(char* data)
|
||||
{
|
||||
boost::system::error_code error;
|
||||
|
||||
size_t bytesReceived = m_Socket.receive_from(boost
|
||||
::asio::buffer((void*)data, INPUTSIZE),
|
||||
m_ReceiverEndpoint,
|
||||
0, error);
|
||||
// Network Debug data
|
||||
if (isReadingData) {
|
||||
m_NetworkData.TotalDataReceived += bytesReceived;
|
||||
m_NetworkData.DataReceivedThisInterval += bytesReceived;
|
||||
m_NetworkData.AmountOfMessagesReceived++;
|
||||
}
|
||||
if (error) {
|
||||
//LOG_ERROR("receive: %s", error.message().c_str());
|
||||
}
|
||||
return bytesReceived;
|
||||
}
|
||||
|
||||
void Client::send(Packet& packet)
|
||||
{
|
||||
m_Socket.send_to(boost::asio::buffer(
|
||||
packet.Data(),
|
||||
packet.Size()),
|
||||
m_ReceiverEndpoint, 0);
|
||||
// Network Debug data
|
||||
if (isReadingData) {
|
||||
m_NetworkData.TotalDataSent += packet.Size();
|
||||
m_NetworkData.DataSentThisInterval += packet.Size();
|
||||
m_NetworkData.AmountOfMessagesSent++;
|
||||
}
|
||||
}
|
||||
|
||||
void Client::connect()
|
||||
{
|
||||
Packet packet(MessageType::Connect, m_SendPacketID);
|
||||
packet.WriteString(m_PlayerName);
|
||||
m_StartPingTime = std::clock();
|
||||
send(packet);
|
||||
parseSpawnEvents();
|
||||
}
|
||||
|
||||
void Client::disconnect()
|
||||
{
|
||||
m_IsConnected = false;
|
||||
m_PreviousPacketID = 0;
|
||||
m_PacketID = 0;
|
||||
Packet packet(MessageType::Disconnect, m_SendPacketID);
|
||||
send(packet);
|
||||
m_Reliable.Send(packet);
|
||||
m_Reliable.Disconnect();
|
||||
}
|
||||
|
||||
bool Client::OnInputCommand(const Events::InputCommand & e)
|
||||
@@ -357,7 +371,8 @@ bool Client::OnInputCommand(const Events::InputCommand & e)
|
||||
|
||||
if (e.Command == "ConnectToServer") { // Connect for now
|
||||
if (e.Value > 0) {
|
||||
connect();
|
||||
m_Reliable.Connect(m_PlayerName, m_Address, m_Port);
|
||||
m_Unreliable.Connect(m_PlayerName, m_Address, m_Port);
|
||||
}
|
||||
//LOG_DEBUG("Client::OnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID);
|
||||
return true;
|
||||
@@ -380,7 +395,9 @@ bool Client::OnInputCommand(const Events::InputCommand & e)
|
||||
m_SaveDataTimer = std::clock();
|
||||
}
|
||||
} else {
|
||||
m_InputCommandBuffer.push_back(e);
|
||||
if (m_IsConnected) {
|
||||
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;
|
||||
}
|
||||
@@ -393,7 +410,7 @@ bool Client::OnPlayerDamage(const Events::PlayerDamage & e)
|
||||
packet.WritePrimitive(m_ClientIDToServerID.at(e.Inflictor.ID));
|
||||
packet.WritePrimitive(m_ClientIDToServerID.at(e.Victim.ID));
|
||||
packet.WritePrimitive(e.Damage);
|
||||
send(packet);
|
||||
m_Reliable.Send(packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -422,7 +439,7 @@ void Client::sendLocalPlayerTransform()
|
||||
packet.WritePrimitive(orientation.x);
|
||||
packet.WritePrimitive(orientation.y);
|
||||
packet.WritePrimitive(orientation.z);
|
||||
|
||||
|
||||
bool hasAssaultWeapon = m_LocalPlayer.HasComponent("AssaultWeapon");
|
||||
packet.WritePrimitive(hasAssaultWeapon);
|
||||
if (hasAssaultWeapon) {
|
||||
@@ -430,8 +447,8 @@ void Client::sendLocalPlayerTransform()
|
||||
packet.WritePrimitive((int)cAssaultWeapon["MagazineAmmo"]);
|
||||
packet.WritePrimitive((int)cAssaultWeapon["Ammo"]);
|
||||
}
|
||||
|
||||
send(packet);
|
||||
|
||||
m_Unreliable.Send(packet);
|
||||
}
|
||||
|
||||
void Client::identifyPacketLoss()
|
||||
@@ -443,17 +460,15 @@ void Client::identifyPacketLoss()
|
||||
}
|
||||
}
|
||||
|
||||
bool Client::hasServerTimedOut()
|
||||
void Client::hasServerTimedOut()
|
||||
{
|
||||
// Time in ms
|
||||
double timeSincePing = 1000 * (std::clock() - m_StartPingTime) / static_cast<double>(CLOCKS_PER_SEC);
|
||||
if (timeSincePing > m_TimeoutMs) {
|
||||
// Clear everything and go to menu.
|
||||
LOG_INFO("Server has timed out, returning to menu, Beep Boop.");
|
||||
m_IsConnected = false;
|
||||
return true;
|
||||
disconnect();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
EntityID Client::createPlayer()
|
||||
@@ -474,7 +489,7 @@ void Client::sendInputCommands()
|
||||
packet.WriteString(m_InputCommandBuffer[i].Command);
|
||||
packet.WritePrimitive(m_InputCommandBuffer[i].Value);
|
||||
}
|
||||
send(packet);
|
||||
m_Reliable.Send(packet);
|
||||
m_InputCommandBuffer.clear();
|
||||
}
|
||||
}
|
||||
@@ -482,7 +497,7 @@ void Client::sendInputCommands()
|
||||
void Client::becomePlayer()
|
||||
{
|
||||
Packet packet = Packet(MessageType::BecomePlayer, m_SendPacketID);
|
||||
send(packet);
|
||||
m_Reliable.Send(packet);
|
||||
}
|
||||
|
||||
bool Client::clientServerMapsHasEntity(EntityID clientEntityID)
|
||||
@@ -513,7 +528,6 @@ void Client::insertIntoServerClientMaps(EntityID serverEntityID, EntityID client
|
||||
{
|
||||
m_ServerIDToClientID.insert(std::make_pair(serverEntityID, clientEntityID));
|
||||
m_ClientIDToServerID.insert(std::make_pair(clientEntityID, serverEntityID));
|
||||
|
||||
}
|
||||
|
||||
void Client::deleteFromServerClientMaps(EntityID serverEntityID, EntityID clientEntityID)
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
#include "Network/HybridClient.h"
|
||||
|
||||
|
||||
HybridClient::HybridClient()
|
||||
{
|
||||
}
|
||||
|
||||
HybridClient::~HybridClient()
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
#include "Network/HybridServer.h"
|
||||
|
||||
HybridServer::HybridServer()
|
||||
{
|
||||
}
|
||||
|
||||
HybridServer::~HybridServer()
|
||||
{
|
||||
}
|
||||
@@ -14,6 +14,21 @@ void Network::Update()
|
||||
updateNetworkData();
|
||||
}
|
||||
|
||||
void Network::logSentData(int bytesSent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Network::logReceivedData(int bytesReceived)
|
||||
{
|
||||
// Network Debug data
|
||||
if (isReadingData) {
|
||||
m_NetworkData.TotalDataReceived += bytesReceived;
|
||||
m_NetworkData.DataReceivedThisInterval += bytesReceived;
|
||||
m_NetworkData.AmountOfMessagesReceived++;
|
||||
}
|
||||
}
|
||||
|
||||
void Network::saveToFile()
|
||||
{
|
||||
std::ofstream outfile;
|
||||
|
||||
@@ -34,10 +34,12 @@ void Packet::Init(MessageType type, unsigned int & packetID)
|
||||
m_ReturnDataOffset = 0;
|
||||
m_Offset = 0;
|
||||
// Create message header
|
||||
// allocate memory for size of packet(only used in tcp)
|
||||
WritePrimitive<int>(0);
|
||||
// Add message type
|
||||
int messageType = static_cast<int>(type);
|
||||
Packet::WritePrimitive<int>(messageType);
|
||||
Packet::WritePrimitive<int>(packetID);
|
||||
WritePrimitive<int>(messageType);
|
||||
WritePrimitive<int>(packetID);
|
||||
packetID++;
|
||||
m_HeaderSize = m_Offset;
|
||||
}
|
||||
@@ -56,9 +58,12 @@ void Packet::WriteString(const std::string& str)
|
||||
|
||||
void Packet::WriteData(char * data, int sizeOfData)
|
||||
{
|
||||
|
||||
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);
|
||||
resizeData();
|
||||
while (m_Offset + sizeOfData > m_MaxPacketSize) {
|
||||
resizeData();
|
||||
}
|
||||
}
|
||||
memcpy(m_Data + m_Offset, data, sizeOfData);
|
||||
m_Offset += sizeOfData;
|
||||
@@ -76,14 +81,35 @@ std::string Packet::ReadString()
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
char * Packet::ReadData(int SizeOfData)
|
||||
void Packet::ReconstructFromData(char * data, size_t sizeOfData)
|
||||
{
|
||||
if (m_Offset < m_ReturnDataOffset + SizeOfData) {
|
||||
if (sizeOfData > m_MaxPacketSize) {
|
||||
// Delete our data
|
||||
delete[] m_Data;
|
||||
// Set new max size
|
||||
m_MaxPacketSize = sizeOfData;
|
||||
m_Data = new char[m_MaxPacketSize];
|
||||
// while we resized the old data container.
|
||||
}
|
||||
memcpy(m_Data, data, sizeOfData);
|
||||
m_Offset = sizeOfData;
|
||||
|
||||
}
|
||||
|
||||
void Packet::UpdateSize()
|
||||
{
|
||||
int whatisoffset = m_Offset;
|
||||
memcpy(m_Data, &m_Offset, sizeof(int));
|
||||
}
|
||||
|
||||
char * Packet::ReadData(int sizeOfData)
|
||||
{
|
||||
if (m_Offset < m_ReturnDataOffset + sizeOfData) {
|
||||
//LOG_WARNING("packet ReadData(): Oh no! You are trying to remove things outside my memory kingdom");
|
||||
return nullptr;
|
||||
}
|
||||
size_t oldReturnDataOffset = m_ReturnDataOffset;
|
||||
m_ReturnDataOffset += SizeOfData;
|
||||
m_ReturnDataOffset += sizeOfData;
|
||||
return (m_Data + oldReturnDataOffset);
|
||||
}
|
||||
|
||||
@@ -91,25 +117,36 @@ void Packet::ChangePacketID(unsigned int & packetID)
|
||||
{
|
||||
packetID = packetID + 1;
|
||||
// Overwrite old PacketID
|
||||
memcpy(m_Data + sizeof(int), &packetID, sizeof(int));
|
||||
memcpy(m_Data + 2*sizeof(int), &packetID, sizeof(int));
|
||||
}
|
||||
|
||||
MessageType Packet::GetMessageType()
|
||||
{
|
||||
MessageType messagType;
|
||||
memcpy(&messagType, m_Data + sizeof(int), sizeof(int));
|
||||
return messagType;
|
||||
}
|
||||
|
||||
void Packet::resizeData()
|
||||
{
|
||||
resizeData(m_MaxPacketSize * 2);
|
||||
}
|
||||
|
||||
void Packet::resizeData(int size)
|
||||
{
|
||||
// Allocate memory to store our data in
|
||||
char* holdData = new char[m_MaxPacketSize];
|
||||
// Copy our data to the newly allocated memory
|
||||
memcpy(holdData, m_Data, m_Offset);
|
||||
// Increase max packet size
|
||||
m_MaxPacketSize = m_MaxPacketSize * 2;
|
||||
m_MaxPacketSize = size;
|
||||
// Delete our data
|
||||
delete m_Data;
|
||||
// Allocate twice the memory we had before
|
||||
delete[] m_Data;
|
||||
// Allocate memory
|
||||
m_Data = new char[m_MaxPacketSize];
|
||||
// Copy our data to new location
|
||||
memcpy(m_Data, holdData, m_Offset);
|
||||
// Delete the memory allocated to hold our data
|
||||
// while we resized the old data container.
|
||||
delete holdData;
|
||||
delete[] holdData;
|
||||
}
|
||||
|
||||
+219
-203
@@ -6,7 +6,6 @@ Server::Server(World* world, EventBroker* eventBroker, int port)
|
||||
ConfigFile* config = ResourceManager::Load<ConfigFile>("Config.ini");
|
||||
snapshotInterval = 1000 * config->Get<float>("Networking.SnapshotInterval", 0.05f);
|
||||
pingIntervalMs = config->Get<float>("Networking.PingIntervalMs", 1000);
|
||||
|
||||
// Subscribe to events
|
||||
EVENT_SUBSCRIBE_MEMBER(m_EInputCommand, &Server::OnInputCommand);
|
||||
EVENT_SUBSCRIBE_MEMBER(m_EPlayerSpawned, &Server::OnPlayerSpawned);
|
||||
@@ -18,7 +17,6 @@ Server::Server(World* world, EventBroker* eventBroker, int port)
|
||||
port = config->Get<float>("Networking.Port", 27666);
|
||||
}
|
||||
m_Port = port;
|
||||
m_Socket = std::make_unique<boost::asio::ip::udp::socket>(m_IOService, boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), port));
|
||||
LOG_INFO("Server initialized and bound to port %i", port);
|
||||
}
|
||||
|
||||
@@ -29,7 +27,58 @@ Server::~Server()
|
||||
|
||||
void Server::Update()
|
||||
{
|
||||
readFromClients();
|
||||
PlayerDefinition pd;
|
||||
|
||||
m_Reliable.AcceptNewConnections(m_NextPlayerID, m_ConnectedPlayers);
|
||||
for (auto& kv : m_ConnectedPlayers) {
|
||||
while (kv.second.TCPSocket->available()) {
|
||||
// Packet will get real data in receive
|
||||
Packet packet(MessageType::Invalid);
|
||||
m_Reliable.Receive(packet, kv.second);
|
||||
m_Address = kv.second.TCPSocket->remote_endpoint().address();
|
||||
m_Port = kv.second.TCPSocket->remote_endpoint().port();
|
||||
if (packet.GetMessageType() == MessageType::Connect) {
|
||||
parseTCPConnect(packet);
|
||||
} else {
|
||||
parseMessageType(packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (m_Unreliable.IsSocketAvailable()) {
|
||||
// Packet will get real data in receive
|
||||
Packet packet(MessageType::Invalid);
|
||||
m_Unreliable.Receive(packet, pd);
|
||||
m_Address = pd.Endpoint.address();
|
||||
m_Port = pd.Endpoint.port();
|
||||
if (packet.GetMessageType() == MessageType::Connect) {
|
||||
parseUDPConnect(packet);
|
||||
} else {
|
||||
parseMessageType(packet);
|
||||
}
|
||||
}
|
||||
// Check if players have disconnected
|
||||
for (int i = 0; i < m_PlayersToDisconnect.size(); i++) {
|
||||
disconnect(m_PlayersToDisconnect.at(i));
|
||||
}
|
||||
m_PlayersToDisconnect.clear();
|
||||
|
||||
std::clock_t currentTime = std::clock();
|
||||
// Send snapshot
|
||||
if (snapshotInterval < (1000 * (currentTime - previousSnapshotMessage) / (double)CLOCKS_PER_SEC)) {
|
||||
sendSnapshot();
|
||||
previousSnapshotMessage = currentTime;
|
||||
}
|
||||
// Send pings each
|
||||
if (pingIntervalMs < (1000 * (currentTime - previousePingMessage) / (double)CLOCKS_PER_SEC)) {
|
||||
sendPing();
|
||||
previousePingMessage = currentTime;
|
||||
}
|
||||
// Time out logic
|
||||
if (checkTimeOutInterval < (1000 * (currentTime - timOutTimer) / (double)CLOCKS_PER_SEC)) {
|
||||
checkForTimeOuts();
|
||||
timOutTimer = currentTime;
|
||||
}
|
||||
m_EventBroker->Process<Server>();
|
||||
if (isReadingData) {
|
||||
Network::Update();
|
||||
@@ -37,48 +86,20 @@ void Server::Update()
|
||||
|
||||
}
|
||||
|
||||
void Server::readFromClients()
|
||||
{
|
||||
while (m_Socket->available()) {
|
||||
try {
|
||||
bytesRead = receive(readBuffer);
|
||||
Packet packet(readBuffer, bytesRead);
|
||||
parseMessageType(packet);
|
||||
} catch (const std::exception&) {
|
||||
//LOG_ERROR("%i: Read from client crashed %s", m_PacketID, err.what());
|
||||
}
|
||||
}
|
||||
std::clock_t currentTime = std::clock();
|
||||
// Send snapshot
|
||||
if (snapshotInterval < (1000 * (currentTime - previousSnapshotMessage) / (double)CLOCKS_PER_SEC)) {
|
||||
sendSnapshot();
|
||||
previousSnapshotMessage = currentTime;
|
||||
}
|
||||
|
||||
// Send pings each
|
||||
if (pingIntervalMs < (1000 * (currentTime - previousePingMessage) / (double)CLOCKS_PER_SEC)) {
|
||||
sendPing();
|
||||
previousePingMessage = currentTime;
|
||||
}
|
||||
|
||||
// Time out logic
|
||||
if (checkTimeOutInterval < (1000 * (currentTime - timOutTimer) / (double)CLOCKS_PER_SEC)) {
|
||||
checkForTimeOuts();
|
||||
timOutTimer = currentTime;
|
||||
}
|
||||
}
|
||||
|
||||
void Server::parseMessageType(Packet& packet)
|
||||
{
|
||||
int messageType = packet.ReadPrimitive<int>(); // Read what type off message was sent from server
|
||||
// Pop packetSize which is used by TCP Client to
|
||||
// create a packet of the correct size
|
||||
packet.ReadPrimitive<int>();
|
||||
|
||||
int messageType = packet.ReadPrimitive<int>(); // Read what type off message was sent from server
|
||||
// Read packet ID
|
||||
m_PreviousPacketID = m_PacketID; // Set previous packet id
|
||||
m_PacketID = packet.ReadPrimitive<int>(); //Read new packet id
|
||||
//identifyPacketLoss();
|
||||
switch (static_cast<MessageType>(messageType)) {
|
||||
case MessageType::Connect:
|
||||
parseConnect(packet);
|
||||
//parseConnect(packet);
|
||||
break;
|
||||
case MessageType::Ping:
|
||||
parsePing();
|
||||
@@ -104,60 +125,19 @@ void Server::parseMessageType(Packet& packet)
|
||||
}
|
||||
}
|
||||
|
||||
size_t Server::receive(char * data)
|
||||
{
|
||||
size_t length = m_Socket->receive_from(
|
||||
boost::asio::buffer((void*)data
|
||||
, INPUTSIZE)
|
||||
, m_ReceiverEndpoint, 0);
|
||||
// Network Debug data
|
||||
if (isReadingData) {
|
||||
m_NetworkData.TotalDataReceived += length;
|
||||
m_NetworkData.DataReceivedThisInterval += length;
|
||||
m_NetworkData.AmountOfMessagesReceived++;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
void Server::send(PlayerID player, Packet& packet)
|
||||
{
|
||||
try {
|
||||
size_t bytesSent = m_Socket->send_to(
|
||||
boost::asio::buffer(packet.Data(), packet.Size()),
|
||||
m_ConnectedPlayers[player].Endpoint,
|
||||
0);
|
||||
// Network Debug data
|
||||
if (isReadingData) {
|
||||
m_NetworkData.TotalDataSent += packet.Size();
|
||||
m_NetworkData.DataSentThisInterval += packet.Size();
|
||||
m_NetworkData.AmountOfMessagesSent++;
|
||||
}
|
||||
} catch (const boost::system::system_error&) {
|
||||
// TODO: Clean up invalid endpoints out of m_ConnectedPlayers later
|
||||
m_ConnectedPlayers[player].Endpoint = boost::asio::ip::udp::endpoint();
|
||||
}
|
||||
}
|
||||
|
||||
void Server::send(Packet & packet)
|
||||
{
|
||||
m_Socket->send_to(
|
||||
boost::asio::buffer(
|
||||
packet.Data(),
|
||||
packet.Size()),
|
||||
m_ReceiverEndpoint,
|
||||
0);
|
||||
if (isReadingData) {
|
||||
// Network Debug data
|
||||
m_NetworkData.TotalDataSent += packet.Size();
|
||||
m_NetworkData.DataSentThisInterval += packet.Size();
|
||||
}
|
||||
}
|
||||
|
||||
void Server::broadcast(Packet& packet)
|
||||
void Server::reliableBroadcast(Packet& packet)
|
||||
{
|
||||
for (auto& kv : m_ConnectedPlayers) {
|
||||
packet.ChangePacketID(kv.second.PacketID);
|
||||
send(kv.first, packet);
|
||||
m_Reliable.Send(packet, kv.second);
|
||||
}
|
||||
}
|
||||
|
||||
void Server::unreliableBroadcast(Packet& packet)
|
||||
{
|
||||
for (auto& kv : m_ConnectedPlayers) {
|
||||
packet.ChangePacketID(kv.second.PacketID);
|
||||
m_Unreliable.Send(packet, kv.second);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,7 +147,7 @@ void Server::sendSnapshot()
|
||||
Packet packet(MessageType::Snapshot);
|
||||
addInputCommandsToPacket(packet);
|
||||
addChildrenToPacket(packet, EntityID_Invalid);
|
||||
broadcast(packet);
|
||||
unreliableBroadcast(packet);
|
||||
}
|
||||
|
||||
void Server::addInputCommandsToPacket(Packet& packet)
|
||||
@@ -248,7 +228,7 @@ void Server::sendPing()
|
||||
// Time message
|
||||
m_StartPingTime = std::clock();
|
||||
// Send message
|
||||
broadcast(packet);
|
||||
reliableBroadcast(packet);
|
||||
}
|
||||
|
||||
void Server::checkForTimeOuts()
|
||||
@@ -256,16 +236,91 @@ void Server::checkForTimeOuts()
|
||||
double startPing = 1000 * m_StartPingTime
|
||||
/ static_cast<double>(CLOCKS_PER_SEC);
|
||||
|
||||
for (int i = 0; i < m_ConnectedPlayers.size(); i++) {
|
||||
if (m_ConnectedPlayers[i].Endpoint.address() != boost::asio::ip::address()) {
|
||||
double stopPing = 1000 * m_ConnectedPlayers[i].StopTime /
|
||||
std::vector<PlayerID> playersToRemove;
|
||||
for (auto& kv : m_ConnectedPlayers) {
|
||||
if (kv.second.TCPAddress != boost::asio::ip::address()) {
|
||||
int stopPing = 1000 * kv.second.StopTime /
|
||||
static_cast<double>(CLOCKS_PER_SEC);
|
||||
if (startPing > stopPing + m_TimeoutMs) {
|
||||
//LOG_INFO("User %i timed out!", i);
|
||||
//disconnect(i);
|
||||
LOG_INFO("User %i timed out!", kv.second.Name);
|
||||
playersToRemove.push_back(kv.first);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < playersToRemove.size(); i++) {
|
||||
disconnect(playersToRemove.at(i));
|
||||
}
|
||||
}
|
||||
|
||||
void Server::parseUDPConnect(Packet & packet)
|
||||
{
|
||||
// Pop size of message int
|
||||
packet.ReadPrimitive<int>();
|
||||
int messageType = packet.ReadPrimitive<int>();
|
||||
// Read packet ID
|
||||
m_PreviousPacketID = m_PacketID; // Set previous packet id
|
||||
m_PacketID = packet.ReadPrimitive<int>(); //Read new packet id
|
||||
// parse player id and other stuff
|
||||
PlayerID playerID = packet.ReadPrimitive<int>();
|
||||
// Do something here?
|
||||
boost::asio::ip::udp::endpoint endpoint(m_Address, m_Port);
|
||||
m_ConnectedPlayers.at(playerID).Endpoint = endpoint;
|
||||
LOG_INFO("parseUDPConnect: Spectator \"%s\" connected on IP: %s", m_ConnectedPlayers.at(playerID).Name.c_str(), m_ConnectedPlayers.at(playerID).Endpoint.address().to_string().c_str());
|
||||
// Send a message to the player that connected
|
||||
Packet connnectPacket(MessageType::Connect, m_ConnectedPlayers.at(playerID).PacketID);
|
||||
m_Unreliable.Send(connnectPacket);
|
||||
LOG_INFO("UDP Connect sent to client");
|
||||
}
|
||||
|
||||
void Server::parseTCPConnect(Packet & packet)
|
||||
{
|
||||
// Pop size of message int
|
||||
packet.ReadPrimitive<int>();
|
||||
int messageType = packet.ReadPrimitive<int>();
|
||||
// Read packet ID
|
||||
m_PreviousPacketID = m_PacketID; // Set previous packet id
|
||||
m_PacketID = packet.ReadPrimitive<int>(); //Read new packet id
|
||||
|
||||
LOG_INFO("Parsing connections");
|
||||
// Check if player is already connected
|
||||
// Ska vara till lagd i TCPServer receive
|
||||
PlayerID playerID = GetPlayerIDFromEndpoint();
|
||||
if (playerID == -1) {
|
||||
return;
|
||||
}
|
||||
// Create a new player
|
||||
m_ConnectedPlayers.at(playerID).EntityID = 0; // Overlook this
|
||||
m_ConnectedPlayers.at(playerID).Name = packet.ReadString();
|
||||
m_ConnectedPlayers.at(playerID).PacketID = 0;
|
||||
m_ConnectedPlayers.at(playerID).StopTime = std::clock();
|
||||
m_ConnectedPlayers.at(playerID).TCPAddress = m_Address;
|
||||
m_ConnectedPlayers.at(playerID).TCPPort = m_Port;
|
||||
|
||||
LOG_INFO("parseTCPConnect: Spectator \"%s\" connected on IP: %s", m_ConnectedPlayers.at(playerID).Name.c_str(),
|
||||
m_ConnectedPlayers.at(playerID).TCPAddress.to_string().c_str());
|
||||
|
||||
// Send a message to the player that connected
|
||||
Packet connnectPacket(MessageType::Connect, m_ConnectedPlayers.at(playerID).PacketID);
|
||||
// Write playerID to packet
|
||||
connnectPacket.WritePrimitive(playerID);
|
||||
m_Reliable.Send(connnectPacket);
|
||||
|
||||
// Send notification that a player has connected
|
||||
//Packet notificationPacket(MessageType::PlayerConnected);
|
||||
//broadcast(notificationPacket);
|
||||
}
|
||||
|
||||
void Server::parseDisconnect()
|
||||
{
|
||||
LOG_INFO("%i: Parsing disconnect", m_PacketID);
|
||||
|
||||
for (auto& kv : m_ConnectedPlayers) {
|
||||
if (kv.second.TCPAddress == m_Address &&
|
||||
kv.second.TCPPort == m_Port) {
|
||||
m_PlayersToDisconnect.push_back(kv.first);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Server::disconnect(PlayerID playerID)
|
||||
@@ -274,33 +329,14 @@ void Server::disconnect(PlayerID playerID)
|
||||
LOG_INFO("User %s disconnected/timed out", m_ConnectedPlayers[playerID].Name.c_str());
|
||||
// Remove enteties and stuff (When we can remove entity, remove it and tell clients to remove the copy they have)
|
||||
Events::PlayerDisconnected e;
|
||||
e.Entity = m_ConnectedPlayers[playerID].EntityID;
|
||||
e.Entity = m_ConnectedPlayers.at(playerID).EntityID;
|
||||
e.PlayerID = playerID;
|
||||
m_EventBroker->Publish(e);
|
||||
|
||||
//m_World->DeleteEntity(m_ConnectedPlayers[playerID].EntityID);
|
||||
m_ConnectedPlayers[playerID].TCPSocket->shutdown(boost::asio::ip::tcp::socket::shutdown_both);
|
||||
m_ConnectedPlayers[playerID].TCPSocket->close();
|
||||
m_ConnectedPlayers.erase(playerID);
|
||||
}
|
||||
|
||||
void Server::parseOnInputCommand(Packet& packet)
|
||||
{
|
||||
PlayerID player = -1;
|
||||
// Check which player it was who sent the message
|
||||
player = GetPlayerIDFromEndpoint(m_ReceiverEndpoint);
|
||||
if (player != -1) {
|
||||
while (packet.DataReadSize() < packet.Size()) {
|
||||
Events::InputCommand e;
|
||||
e.Command = packet.ReadString();
|
||||
e.PlayerID = player; // Set correct player id
|
||||
e.Player = EntityWrapper(m_World, m_ConnectedPlayers.at(player).EntityID);
|
||||
e.Value = packet.ReadPrimitive<float>();
|
||||
m_EventBroker->Publish(e);
|
||||
|
||||
if (e.Command == "PrimaryFire" || e.Command == "Reload") {
|
||||
m_InputCommandsToBroadcast.push_back(e);
|
||||
}
|
||||
//LOG_INFO("Server::parseOnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID);
|
||||
}
|
||||
}
|
||||
// Send disconnect to the other players.
|
||||
}
|
||||
|
||||
void Server::parseOnPlayerDamage(Packet & packet)
|
||||
@@ -313,75 +349,6 @@ void Server::parseOnPlayerDamage(Packet & packet)
|
||||
//LOG_DEBUG("Server::parseOnPlayerDamage: Command is %s. Value is %f. PlayerID is %i.", e.DamageAmount, e.PlayerDamagedID, e.TypeOfDamage.c_str());
|
||||
}
|
||||
|
||||
void Server::parseConnect(Packet& packet)
|
||||
{
|
||||
LOG_INFO("Parsing connections");
|
||||
// Check if player is already connected
|
||||
if (GetPlayerIDFromEndpoint(m_ReceiverEndpoint) != -1) {
|
||||
return;
|
||||
}
|
||||
for (auto& kv : m_ConnectedPlayers) {
|
||||
if (kv.second.Endpoint.address() == m_ReceiverEndpoint.address() &&
|
||||
kv.second.Endpoint.port() == m_ReceiverEndpoint.port()) {
|
||||
// Already connected
|
||||
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_ConnectedPlayers[m_NextPlayerID++] = pd;
|
||||
LOG_INFO("Spectator \"%s\" connected on IP: %s", pd.Name.c_str(), pd.Endpoint.address().to_string().c_str());
|
||||
|
||||
// Send a message to the player that connected
|
||||
Packet connnectPacket(MessageType::Connect, pd.PacketID);
|
||||
send(connnectPacket);
|
||||
|
||||
// Send notification that a player has connected
|
||||
Packet notificationPacket(MessageType::PlayerConnected);
|
||||
broadcast(notificationPacket);
|
||||
}
|
||||
|
||||
void Server::parseDisconnect()
|
||||
{
|
||||
LOG_INFO("%i: Parsing disconnect", m_PacketID);
|
||||
|
||||
for (auto& kv : m_ConnectedPlayers) {
|
||||
if (kv.second.Endpoint.address() == m_ReceiverEndpoint.address() &&
|
||||
kv.second.Endpoint.port() == m_ReceiverEndpoint.port()) {
|
||||
disconnect(kv.first);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Server::parseClientPing()
|
||||
{
|
||||
LOG_INFO("%i: Parsing ping", m_PacketID);
|
||||
PlayerID player = GetPlayerIDFromEndpoint(m_ReceiverEndpoint);
|
||||
if (player == -1) {
|
||||
return;
|
||||
}
|
||||
// Return ping
|
||||
Packet packet(MessageType::Ping, m_ConnectedPlayers[player].PacketID);
|
||||
packet.WriteString("Ping received");
|
||||
send(packet);
|
||||
}
|
||||
|
||||
void Server::parsePing()
|
||||
{
|
||||
for (int i = 0; i < m_ConnectedPlayers.size(); i++) {
|
||||
if (m_ConnectedPlayers[i].Endpoint.address() == m_ReceiverEndpoint.address()) {
|
||||
m_ConnectedPlayers[i].StopTime = std::clock();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Server::identifyPacketLoss()
|
||||
{
|
||||
// if no packets lost, difference should be equal to 1
|
||||
@@ -395,18 +362,7 @@ void Server::kick(PlayerID player)
|
||||
{
|
||||
disconnect(player);
|
||||
Packet packet = Packet(MessageType::Kick);
|
||||
send(packet);
|
||||
}
|
||||
|
||||
PlayerID Server::GetPlayerIDFromEndpoint(boost::asio::ip::udp::endpoint endpoint)
|
||||
{
|
||||
for (auto& kv : m_ConnectedPlayers) {
|
||||
if (kv.second.Endpoint.address() == endpoint.address() &&
|
||||
kv.second.Endpoint.port() == endpoint.port()) {
|
||||
return kv.first;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
m_Reliable.Send(packet);
|
||||
}
|
||||
|
||||
bool Server::OnInputCommand(const Events::InputCommand & e)
|
||||
@@ -435,7 +391,7 @@ bool Server::OnPlayerSpawned(const Events::PlayerSpawned & e)
|
||||
packet.WritePrimitive<EntityID>(e.Spawner.ID);
|
||||
// We don't send PlayerID here because it will always be set to -1
|
||||
packet.WriteString(m_ConnectedPlayers[e.PlayerID].Name);
|
||||
send(e.PlayerID, packet);
|
||||
m_Reliable.Send(packet, m_ConnectedPlayers[e.PlayerID]);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -445,7 +401,7 @@ bool Server::OnEntityDeleted(const Events::EntityDeleted & e)
|
||||
if (shouldSendToClient(EntityWrapper(m_World, e.DeletedEntity))) {
|
||||
Packet packet = Packet(MessageType::EntityDeleted);
|
||||
packet.WritePrimitive<EntityID>(e.DeletedEntity);
|
||||
broadcast(packet);
|
||||
reliableBroadcast(packet);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@@ -458,12 +414,58 @@ bool Server::OnComponentDeleted(const Events::ComponentDeleted & e)
|
||||
Packet packet = Packet(MessageType::ComponentDeleted);
|
||||
packet.WritePrimitive<EntityID>(e.Entity);
|
||||
packet.WriteString(e.ComponentType);
|
||||
broadcast(packet);
|
||||
reliableBroadcast(packet);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void Server::parseClientPing()
|
||||
{
|
||||
LOG_INFO("%i: Parsing ping", m_PacketID);
|
||||
PlayerID player = GetPlayerIDFromEndpoint();
|
||||
if (player == -1) {
|
||||
return;
|
||||
}
|
||||
// Return ping
|
||||
Packet packet(MessageType::Ping, m_ConnectedPlayers[player].PacketID);
|
||||
packet.WriteString("Ping received");
|
||||
m_Reliable.Send(packet);
|
||||
}
|
||||
|
||||
void Server::parsePing()
|
||||
{
|
||||
for (auto& kv : m_ConnectedPlayers) {
|
||||
if (kv.second.TCPAddress == m_Address &&
|
||||
kv.second.TCPPort == m_Port) {
|
||||
kv.second.StopTime = std::clock();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Server::parseOnInputCommand(Packet& packet)
|
||||
{
|
||||
PlayerID player = -1;
|
||||
// Check which player it was who sent the message
|
||||
player = GetPlayerIDFromEndpoint();
|
||||
if (player != -1) {
|
||||
while (packet.DataReadSize() < packet.Size()) {
|
||||
Events::InputCommand e;
|
||||
e.Command = packet.ReadString();
|
||||
e.PlayerID = player; // Set correct player id
|
||||
e.Player = EntityWrapper(m_World, m_ConnectedPlayers.at(player).EntityID);
|
||||
e.Value = packet.ReadPrimitive<float>();
|
||||
m_EventBroker->Publish(e);
|
||||
if (e.Command == "PrimaryFire") {
|
||||
m_InputCommandsToBroadcast.push_back(e);
|
||||
}
|
||||
//LOG_INFO("Server::parseOnInputCommand: Command is %s. Value is %f. PlayerID is %i.", e.Command.c_str(), e.Value, e.PlayerID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Server::parsePlayerTransform(Packet& packet)
|
||||
{
|
||||
glm::vec3 position;
|
||||
@@ -475,6 +477,7 @@ void Server::parsePlayerTransform(Packet& packet)
|
||||
orientation.y = packet.ReadPrimitive<float>();
|
||||
orientation.z = packet.ReadPrimitive<float>();
|
||||
|
||||
PlayerID playerID = GetPlayerIDFromEndpoint();
|
||||
bool hasAssaultWeapon = packet.ReadPrimitive<bool>();
|
||||
int magazineAmmo;
|
||||
int ammo;
|
||||
@@ -483,7 +486,6 @@ void Server::parsePlayerTransform(Packet& packet)
|
||||
ammo = packet.ReadPrimitive<int>();
|
||||
}
|
||||
|
||||
PlayerID playerID = GetPlayerIDFromEndpoint(m_ReceiverEndpoint);
|
||||
EntityWrapper player(m_World, m_ConnectedPlayers.at(playerID).EntityID);
|
||||
if (player.Valid()) {
|
||||
player["Transform"]["Position"] = position;
|
||||
@@ -500,3 +502,17 @@ bool Server::shouldSendToClient(EntityWrapper childEntity)
|
||||
{
|
||||
return childEntity.HasComponent("Player") || childEntity.FirstParentWithComponent("Player").Valid();
|
||||
}
|
||||
|
||||
PlayerID Server::GetPlayerIDFromEndpoint()
|
||||
{
|
||||
// check both tcp and udp connection
|
||||
for (auto& kv : m_ConnectedPlayers) {
|
||||
if ((kv.second.TCPAddress == m_Address
|
||||
&& kv.second.TCPPort == m_Port)
|
||||
|| (kv.second.Endpoint.address() == m_Address
|
||||
&& kv.second.Endpoint.port() == m_Port)) {
|
||||
return kv.first;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
#include "Network/TCPClient.h"
|
||||
|
||||
using namespace boost::asio::ip;
|
||||
|
||||
TCPClient::TCPClient()
|
||||
{
|
||||
}
|
||||
|
||||
TCPClient::~TCPClient()
|
||||
{
|
||||
}
|
||||
|
||||
void TCPClient::Connect(std::string playerName, std::string address, int port)
|
||||
{
|
||||
if (m_Socket) {
|
||||
if (m_IsConnected) {
|
||||
Packet packet(MessageType::Connect, m_SendPacketID);
|
||||
packet.WriteString(playerName);
|
||||
Send(packet);
|
||||
LOG_INFO("Connect message sent again!");
|
||||
}
|
||||
}
|
||||
else if (!m_IsConnected) {
|
||||
boost::system::error_code error = boost::asio::error::host_not_found;
|
||||
m_Endpoint = tcp::endpoint(boost::asio::ip::address::from_string(address), port);
|
||||
m_Socket = std::unique_ptr<tcp::socket>(new tcp::socket(m_IOService));
|
||||
m_Socket->connect(m_Endpoint, error);
|
||||
tcp::no_delay option(true);
|
||||
m_Socket->set_option(option);
|
||||
LOG_INFO(error.message().c_str());
|
||||
if (!error) {
|
||||
m_IsConnected = true;
|
||||
Packet packet(MessageType::Connect, m_SendPacketID);
|
||||
packet.WriteString(playerName);
|
||||
Send(packet);
|
||||
LOG_INFO("Connect message sent!");
|
||||
}
|
||||
// If error
|
||||
else {
|
||||
m_Socket->close();
|
||||
m_Socket = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TCPClient::Disconnect()
|
||||
{
|
||||
if (!m_IsConnected) {
|
||||
return;
|
||||
}
|
||||
m_Socket->shutdown(boost::asio::ip::tcp::socket::shutdown_both);
|
||||
m_Socket->close();
|
||||
m_Socket = nullptr;
|
||||
m_IsConnected = false;
|
||||
}
|
||||
|
||||
void TCPClient::Receive(Packet& packet)
|
||||
{
|
||||
size_t bytesRead = readBuffer(m_ReadBuffer);
|
||||
if (bytesRead > 0) {
|
||||
packet.ReconstructFromData(m_ReadBuffer, bytesRead);
|
||||
}
|
||||
}
|
||||
|
||||
size_t TCPClient::readBuffer(char* data)
|
||||
{
|
||||
if (!m_Socket) {
|
||||
return 0;
|
||||
}
|
||||
boost::system::error_code error;
|
||||
// Read size of packet
|
||||
size_t bytesReceived = m_Socket->read_some(boost
|
||||
::asio::buffer((void*)data, sizeof(int)),
|
||||
error);
|
||||
int sizeOfPacket = 0;
|
||||
memcpy(&sizeOfPacket, data, sizeof(int));
|
||||
|
||||
// Read the rest of the message
|
||||
bytesReceived += m_Socket->read_some(boost
|
||||
::asio::buffer((void*)(data + bytesReceived), sizeOfPacket - bytesReceived),
|
||||
error);
|
||||
if (error) {
|
||||
//LOG_ERROR("receive: %s", error.message().c_str());
|
||||
}
|
||||
return bytesReceived;
|
||||
}
|
||||
|
||||
void TCPClient::Send(Packet & packet)
|
||||
{
|
||||
if (!m_Socket) {
|
||||
LOG_WARNING("TCPClient::Send: Socket is null");
|
||||
return;
|
||||
}
|
||||
packet.UpdateSize();
|
||||
boost::system::error_code error;
|
||||
m_Socket->send(boost::asio::buffer(
|
||||
packet.Data(),
|
||||
packet.Size()), 0, error);
|
||||
}
|
||||
|
||||
bool TCPClient::IsSocketAvailable()
|
||||
{
|
||||
if (!m_Socket) {
|
||||
return false;
|
||||
}
|
||||
return m_Socket->available();
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
#include "Network/TCPServer.h"
|
||||
using namespace boost::asio::ip;
|
||||
|
||||
TCPServer::TCPServer()
|
||||
{
|
||||
acceptor = std::unique_ptr<tcp::acceptor>(new tcp::acceptor(m_IOService, tcp::endpoint(tcp::v4(), 27666)));
|
||||
}
|
||||
|
||||
TCPServer::~TCPServer()
|
||||
{
|
||||
}
|
||||
|
||||
void TCPServer::AcceptNewConnections(int& nextPlayerID, std::map<PlayerID, PlayerDefinition>& connectedPlayers)
|
||||
{
|
||||
boost::shared_ptr<tcp::socket> newSocket = boost::shared_ptr<tcp::socket>(new tcp::socket(m_IOService));
|
||||
m_IOService.poll();
|
||||
acceptor->async_accept(*newSocket,
|
||||
boost::bind(&TCPServer::handle_accept, this, newSocket, boost::ref(nextPlayerID), boost::ref(connectedPlayers),
|
||||
boost::asio::placeholders::error));
|
||||
}
|
||||
|
||||
PlayerID GetPlayerIDFromEndpoint(const std::map<PlayerID, PlayerDefinition>& connectedPlayers,
|
||||
boost::asio::ip::address address, unsigned short port)
|
||||
{
|
||||
for (auto& kv : connectedPlayers) {
|
||||
if (kv.second.TCPAddress == address &&
|
||||
kv.second.TCPPort == port) {
|
||||
return kv.first;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void TCPServer::handle_accept(boost::shared_ptr<tcp::socket> socket,
|
||||
int& nextPlayerID, std::map<PlayerID, PlayerDefinition>& connectedPlayers,
|
||||
const boost::system::error_code& error)
|
||||
{
|
||||
if (!error && GetPlayerIDFromEndpoint(connectedPlayers, socket->remote_endpoint().address(),
|
||||
socket->remote_endpoint().port()) == -1) {
|
||||
// Add tcp socket to connections
|
||||
boost::asio::ip::tcp::no_delay option(true);
|
||||
socket->set_option(option);
|
||||
PlayerDefinition pd;
|
||||
pd.StopTime = std::clock();
|
||||
pd.TCPSocket = socket;
|
||||
pd.TCPAddress = socket.get()->remote_endpoint().address();
|
||||
pd.TCPPort = socket.get()->remote_endpoint().port();
|
||||
connectedPlayers[nextPlayerID++] = pd;
|
||||
}
|
||||
}
|
||||
|
||||
void TCPServer::Send(Packet & packet, PlayerDefinition & playerDefinition)
|
||||
{
|
||||
try {
|
||||
packet.UpdateSize();
|
||||
int bytesSent = playerDefinition.TCPSocket->send(
|
||||
boost::asio::buffer(packet.Data(), packet.Size()),
|
||||
0);
|
||||
} catch (const boost::system::system_error& e) {
|
||||
// TODO: Clean up invalid endpoints out of m_ConnectedPlayers later
|
||||
playerDefinition.Endpoint = boost::asio::ip::udp::endpoint();
|
||||
}
|
||||
}
|
||||
|
||||
void TCPServer::Send(Packet & packet)
|
||||
{
|
||||
packet.UpdateSize();
|
||||
lastReceivedSocket->send(
|
||||
boost::asio::buffer(
|
||||
packet.Data(),
|
||||
packet.Size()),
|
||||
0);
|
||||
}
|
||||
|
||||
void TCPServer::Disconnect()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void TCPServer::Receive(Packet & packet, PlayerDefinition & playerDefinition)
|
||||
{
|
||||
int bytesRead = readBuffer(m_ReadBuffer, playerDefinition);
|
||||
if (bytesRead > 0) {
|
||||
packet.ReconstructFromData(m_ReadBuffer, bytesRead);
|
||||
}
|
||||
lastReceivedSocket = playerDefinition.TCPSocket;
|
||||
}
|
||||
|
||||
int TCPServer::readBuffer(char* data, PlayerDefinition & playerDefinition)
|
||||
{
|
||||
if (!playerDefinition.TCPSocket) {
|
||||
return 0;
|
||||
}
|
||||
boost::system::error_code error;
|
||||
// Read size of packet
|
||||
size_t bytesReceived = playerDefinition.TCPSocket->read_some(boost
|
||||
::asio::buffer((void*)data, sizeof(int)),
|
||||
error);
|
||||
int sizeOfPacket = 0;
|
||||
memcpy(&sizeOfPacket, data, sizeof(int));
|
||||
|
||||
// Read the rest of the message
|
||||
bytesReceived += playerDefinition.TCPSocket->read_some(boost
|
||||
::asio::buffer((void*)(data + bytesReceived), sizeOfPacket - bytesReceived),
|
||||
error);
|
||||
if (error) {
|
||||
//LOG_ERROR("receive: %s", error.message().c_str());
|
||||
}
|
||||
return bytesReceived;
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
#include "Network/UDPClient.h"
|
||||
|
||||
using namespace boost::asio::ip;
|
||||
|
||||
UDPClient::UDPClient()
|
||||
{
|
||||
}
|
||||
|
||||
UDPClient::~UDPClient()
|
||||
{
|
||||
}
|
||||
|
||||
void UDPClient::Connect(std::string playerName, std::string address, int port)
|
||||
{
|
||||
if (m_Socket) {
|
||||
return;
|
||||
}
|
||||
m_ReceiverEndpoint = udp::endpoint(boost::asio::ip::address::from_string(address), port);
|
||||
m_Socket = boost::shared_ptr<boost::asio::ip::udp::socket>(new boost::asio::ip::udp::socket(m_IOService));
|
||||
m_Socket->connect(m_ReceiverEndpoint);
|
||||
}
|
||||
|
||||
void UDPClient::Disconnect()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void UDPClient::Receive(Packet& packet)
|
||||
{
|
||||
int bytesRead = readBuffer(m_ReadBuffer);
|
||||
if (bytesRead > 0) {
|
||||
packet.ReconstructFromData(m_ReadBuffer, bytesRead);
|
||||
}
|
||||
}
|
||||
|
||||
int UDPClient::readBuffer(char* data)
|
||||
{
|
||||
if (!m_Socket) {
|
||||
return 0;
|
||||
}
|
||||
boost::system::error_code error;
|
||||
int bytesReceived = m_Socket->receive_from(boost
|
||||
::asio::buffer((void*)data, BUFFERSIZE),
|
||||
m_ReceiverEndpoint,
|
||||
0, error);
|
||||
if (error) {
|
||||
//LOG_ERROR("receive: %s", error.message().c_str());
|
||||
}
|
||||
return bytesReceived;
|
||||
}
|
||||
|
||||
void UDPClient::Send(Packet& packet)
|
||||
{
|
||||
m_Socket->send_to(boost::asio::buffer(
|
||||
packet.Data(),
|
||||
packet.Size()),
|
||||
m_ReceiverEndpoint, 0);
|
||||
}
|
||||
|
||||
bool UDPClient::IsSocketAvailable()
|
||||
{
|
||||
if (!m_Socket) {
|
||||
return false;
|
||||
}
|
||||
return m_Socket->available();
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
#include "Network/UDPServer.h"
|
||||
|
||||
UDPServer::UDPServer()
|
||||
{
|
||||
m_Socket = std::unique_ptr<boost::asio::ip::udp::socket>(new boost::asio::ip::udp::socket(m_IOService, boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 27666)));
|
||||
}
|
||||
|
||||
UDPServer::~UDPServer()
|
||||
{ }
|
||||
|
||||
void UDPServer::Send(Packet& packet, PlayerDefinition & playerDefinition)
|
||||
{
|
||||
try {
|
||||
int bytesSent = m_Socket->send_to(
|
||||
boost::asio::buffer(packet.Data(), packet.Size()),
|
||||
playerDefinition.Endpoint,
|
||||
0);
|
||||
} catch (const boost::system::system_error& e) {
|
||||
// TODO: Clean up invalid endpoints out of m_ConnectedPlayers later
|
||||
playerDefinition.Endpoint = boost::asio::ip::udp::endpoint();
|
||||
}
|
||||
}
|
||||
// Send back to endpoint of received packet
|
||||
void UDPServer::Send(Packet & packet)
|
||||
{
|
||||
m_Socket->send_to(
|
||||
boost::asio::buffer(
|
||||
packet.Data(),
|
||||
packet.Size()),
|
||||
m_ReceiverEndpoint,
|
||||
0);
|
||||
}
|
||||
|
||||
void UDPServer::Receive(Packet & packet, PlayerDefinition & playerDefinition)
|
||||
{
|
||||
int bytesRead = readBuffer(m_ReadBuffer);
|
||||
if (bytesRead > 0) {
|
||||
packet.ReconstructFromData(m_ReadBuffer, bytesRead);
|
||||
}
|
||||
playerDefinition.Endpoint = m_ReceiverEndpoint;
|
||||
}
|
||||
|
||||
bool UDPServer::IsSocketAvailable()
|
||||
{
|
||||
return m_Socket->available();
|
||||
}
|
||||
|
||||
int UDPServer::readBuffer(char* data)
|
||||
{
|
||||
boost::system::error_code error = boost::asio::error::host_not_found;
|
||||
unsigned int length = m_Socket->receive_from(
|
||||
boost::asio::buffer((void*)data
|
||||
, BUFFERSIZE)
|
||||
, m_ReceiverEndpoint, 0, error);
|
||||
if (error) {
|
||||
LOG_WARNING(error.message().c_str());
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
void UDPServer::AcceptNewConnections(int& nextPlayerID, std::map<PlayerID, PlayerDefinition>& connectedPlayers)
|
||||
{ }
|
||||
@@ -42,22 +42,22 @@ void PickingPass::InitializeShaderPrograms()
|
||||
m_PickingProgram->BindFragDataLocation(0, "TextureFragment");
|
||||
m_PickingProgram->Link();
|
||||
|
||||
m_PickingSkinnedProgram = ResourceManager::Load<ShaderProgram>("#PickingSkinnedProgram");
|
||||
m_PickingSkinnedProgram = ResourceManager::Load<ShaderProgram>("#PickingSkinnedProgram");
|
||||
|
||||
m_PickingSkinnedProgram->AddShader(std::shared_ptr<Shader>(new VertexShader("Shaders/PickingSkinned.vert.glsl")));
|
||||
m_PickingSkinnedProgram->AddShader(std::shared_ptr<Shader>(new FragmentShader("Shaders/Picking.frag.glsl")));
|
||||
m_PickingSkinnedProgram->Compile();
|
||||
m_PickingSkinnedProgram->BindFragDataLocation(0, "TextureFragment");
|
||||
m_PickingSkinnedProgram->Link();
|
||||
m_PickingSkinnedProgram->AddShader(std::shared_ptr<Shader>(new VertexShader("Shaders/PickingSkinned.vert.glsl")));
|
||||
m_PickingSkinnedProgram->AddShader(std::shared_ptr<Shader>(new FragmentShader("Shaders/Picking.frag.glsl")));
|
||||
m_PickingSkinnedProgram->Compile();
|
||||
m_PickingSkinnedProgram->BindFragDataLocation(0, "TextureFragment");
|
||||
m_PickingSkinnedProgram->Link();
|
||||
}
|
||||
|
||||
void PickingPass::Draw(RenderScene& scene)
|
||||
{
|
||||
PickingPassState* state = new PickingPassState(m_PickingBuffer.GetHandle());
|
||||
|
||||
|
||||
//TODO: Render: Add code for more jobs than modeljobs.
|
||||
GLuint shaderHandle = m_PickingProgram->GetHandle();
|
||||
GLuint shaderSkinnedHandle = m_PickingSkinnedProgram->GetHandle();
|
||||
GLuint shaderSkinnedHandle = m_PickingSkinnedProgram->GetHandle();
|
||||
m_PickingProgram->Bind();
|
||||
|
||||
if (scene.ClearDepth) {
|
||||
@@ -92,15 +92,14 @@ void PickingPass::Draw(RenderScene& scene)
|
||||
|
||||
m_PickingColorsToEntity[glm::ivec2(pickColor[0], pickColor[1])] = pickInfo;
|
||||
|
||||
if (modelJob->Model->IsSkinned())
|
||||
{
|
||||
m_PickingSkinnedProgram->Bind();
|
||||
glUniformMatrix4fv(glGetUniformLocation(shaderSkinnedHandle, "M"), 1, GL_FALSE, glm::value_ptr(modelJob->Matrix));
|
||||
glUniformMatrix4fv(glGetUniformLocation(shaderSkinnedHandle, "V"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ViewMatrix()));
|
||||
glUniformMatrix4fv(glGetUniformLocation(shaderSkinnedHandle, "P"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ProjectionMatrix()));
|
||||
glUniform2fv(glGetUniformLocation(shaderSkinnedHandle, "PickingColor"), 1, glm::value_ptr(glm::vec2(pickColor[0], pickColor[1])));
|
||||
if (modelJob->Model->IsSkinned()) {
|
||||
m_PickingSkinnedProgram->Bind();
|
||||
glUniformMatrix4fv(glGetUniformLocation(shaderSkinnedHandle, "M"), 1, GL_FALSE, glm::value_ptr(modelJob->Matrix));
|
||||
glUniformMatrix4fv(glGetUniformLocation(shaderSkinnedHandle, "V"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ViewMatrix()));
|
||||
glUniformMatrix4fv(glGetUniformLocation(shaderSkinnedHandle, "P"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ProjectionMatrix()));
|
||||
glUniform2fv(glGetUniformLocation(shaderSkinnedHandle, "PickingColor"), 1, glm::value_ptr(glm::vec2(pickColor[0], pickColor[1])));
|
||||
|
||||
if (modelJob->Model->m_RawModel->m_Skeleton != nullptr) {
|
||||
if (modelJob->Model->m_RawModel->m_Skeleton != nullptr) {
|
||||
|
||||
std::vector<glm::mat4> frameBones;
|
||||
if (modelJob->AnimationOffset.animation != nullptr) {
|
||||
@@ -109,15 +108,14 @@ void PickingPass::Draw(RenderScene& scene)
|
||||
frameBones = modelJob->Skeleton->GetFrameBones(modelJob->Animations);
|
||||
}
|
||||
glUniformMatrix4fv(glGetUniformLocation(shaderSkinnedHandle, "Bones"), frameBones.size(), GL_FALSE, glm::value_ptr(frameBones[0]));
|
||||
|
||||
}
|
||||
} else {
|
||||
}
|
||||
} else {
|
||||
m_PickingProgram->Bind();
|
||||
glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "M"), 1, GL_FALSE, glm::value_ptr(modelJob->Matrix));
|
||||
glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "V"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ViewMatrix()));
|
||||
glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "P"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ProjectionMatrix()));
|
||||
glUniform2fv(glGetUniformLocation(shaderHandle, "PickingColor"), 1, glm::value_ptr(glm::vec2(pickColor[0], pickColor[1])));
|
||||
}
|
||||
glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "M"), 1, GL_FALSE, glm::value_ptr(modelJob->Matrix));
|
||||
glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "V"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ViewMatrix()));
|
||||
glUniformMatrix4fv(glGetUniformLocation(shaderHandle, "P"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ProjectionMatrix()));
|
||||
glUniform2fv(glGetUniformLocation(shaderHandle, "PickingColor"), 1, glm::value_ptr(glm::vec2(pickColor[0], pickColor[1])));
|
||||
}
|
||||
|
||||
glBindVertexArray(modelJob->Model->VAO);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, modelJob->Model->ElementBuffer);
|
||||
@@ -207,7 +205,7 @@ void PickingPass::Draw(RenderScene& scene)
|
||||
|
||||
m_PickingColorsToEntity[glm::ivec2(pickColor[0], pickColor[1])] = pickInfo;
|
||||
|
||||
if(modelJob->Model->IsSkinned()) {
|
||||
if (modelJob->Model->IsSkinned()) {
|
||||
m_PickingSkinnedProgram->Bind();
|
||||
glUniformMatrix4fv(glGetUniformLocation(shaderSkinnedHandle, "M"), 1, GL_FALSE, glm::value_ptr(modelJob->Matrix));
|
||||
glUniformMatrix4fv(glGetUniformLocation(shaderSkinnedHandle, "V"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ViewMatrix()));
|
||||
@@ -266,7 +264,7 @@ void PickingPass::Draw(RenderScene& scene)
|
||||
|
||||
if (modelJob->Model->IsSkinned()) {
|
||||
m_PickingSkinnedProgram->Bind();
|
||||
|
||||
|
||||
|
||||
glUniformMatrix4fv(glGetUniformLocation(shaderSkinnedHandle, "M"), 1, GL_FALSE, glm::value_ptr(modelJob->Matrix));
|
||||
glUniformMatrix4fv(glGetUniformLocation(shaderSkinnedHandle, "V"), 1, GL_FALSE, glm::value_ptr(scene.Camera->ViewMatrix()));
|
||||
@@ -293,7 +291,7 @@ void PickingPass::Draw(RenderScene& scene)
|
||||
glUniform2fv(glGetUniformLocation(shaderHandle, "PickingColor"), 1, glm::value_ptr(glm::vec2(pickColor[0], pickColor[1])));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
glBindVertexArray(modelJob->Model->VAO);
|
||||
@@ -301,7 +299,7 @@ void PickingPass::Draw(RenderScene& scene)
|
||||
glDrawElements(GL_TRIANGLES, modelJob->EndIndex - modelJob->StartIndex + 1, GL_UNSIGNED_INT, (void*)(modelJob->StartIndex * sizeof(unsigned int)));
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
m_PickingBuffer.Unbind();
|
||||
GLERROR("PickingPass Error");
|
||||
|
||||
|
||||
@@ -126,11 +126,12 @@ bool PlayerSpawnSystem::OnPlayerSpawned(Events::PlayerSpawned& e)
|
||||
m_PlayerIDs[e.Player.ID] = e.PlayerID;
|
||||
|
||||
// When a player is actually spawned (since the actual spawning is handled on the server)
|
||||
// Hack should be moved.
|
||||
|
||||
if (!IsClient) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Set the camera to the correct entity
|
||||
EntityWrapper cameraEntity = e.Player.FirstChildByName("Camera");
|
||||
bool outOfBodyExperience = ResourceManager::Load<ConfigFile>("Config.ini")->Get<bool>("Debug.OutOfBodyExperience", false);
|
||||
|
||||
Reference in New Issue
Block a user