Merge remote-tracking branch 'origin/master' into Sound

# Conflicts:
#	src/Game/Systems/PlayerSpawnSystem.cpp
#	src/Game/Systems/Weapon/AssaultWeaponBehaviour.cpp
This commit is contained in:
stiffly
2016-02-12 08:19:29 +01:00
74 changed files with 4338 additions and 527 deletions
+142 -95
View File
@@ -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;
@@ -115,17 +119,40 @@ void Client::parseMessageType(Packet& packet)
case MessageType::ComponentDeleted:
parseComponentDeletion(packet);
break;
case MessageType::OnPlayerDamage:
parsePlayerDamage(packet);
break;
default:
break;
}
}
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 +170,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 +179,41 @@ 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)) {
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,10 +289,15 @@ 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>()));
e.Command = packet.ReadString();
e.Value = packet.ReadPrimitive<float>();
m_EventBroker->Publish(e);
EntityID player = packet.ReadPrimitive<EntityID>();
std::string command = packet.ReadString();
float value = packet.ReadPrimitive<float>();
if (m_ServerIDToClientID.find(player) != m_ServerIDToClientID.end()) {
e.Player = EntityWrapper(m_World, m_ServerIDToClientID.at(player));
e.Command = command;
e.Value = value;
m_EventBroker->Publish(e);
}
}
// Read world state
@@ -297,56 +356,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 +377,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 +401,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;
}
@@ -389,12 +412,17 @@ bool Client::OnInputCommand(const Events::InputCommand & e)
bool Client::OnPlayerDamage(const Events::PlayerDamage & e)
{
if (e.Inflictor != m_LocalPlayer) {
return false;
}
Packet packet(MessageType::OnPlayerDamage, m_SendPacketID);
packet.WritePrimitive(m_ClientIDToServerID.at(e.Inflictor.ID));
packet.WritePrimitive(m_ClientIDToServerID.at(e.Victim.ID));
packet.WritePrimitive(e.Damage);
send(packet);
return false;
m_Reliable.Send(packet);
return true;
}
bool Client::OnPlayerSpawned(const Events::PlayerSpawned& e)
@@ -405,23 +433,45 @@ bool Client::OnPlayerSpawned(const Events::PlayerSpawned& e)
return true;
}
void Client::parsePlayerDamage(Packet& packet)
{
Events::PlayerDamage e;
e.Inflictor = EntityWrapper(m_World, m_ServerIDToClientID.at(packet.ReadPrimitive<EntityID>()));
e.Victim = EntityWrapper(m_World, m_ServerIDToClientID.at(packet.ReadPrimitive<EntityID>()));
e.Damage = packet.ReadPrimitive<double>();
// Don't rebroadcast our own player damage events or we'll have an infinite loop!
if (e.Inflictor != m_LocalPlayer) {
m_EventBroker->Publish(e);
}
}
void Client::sendLocalPlayerTransform()
{
if (!m_LocalPlayer.Valid()) {
return;
}
Packet packet(MessageType::PlayerTransform, m_SendPacketID);
ComponentWrapper cTransform = m_LocalPlayer["Transform"];
glm::vec3& position = cTransform["Position"];
glm::vec3& orientation = cTransform["Orientation"];
Packet packet(MessageType::PlayerTransform, m_SendPacketID);
packet.WritePrimitive(position.x);
packet.WritePrimitive(position.y);
packet.WritePrimitive(position.z);
packet.WritePrimitive(orientation.x);
packet.WritePrimitive(orientation.y);
packet.WritePrimitive(orientation.z);
send(packet);
bool hasAssaultWeapon = m_LocalPlayer.HasComponent("AssaultWeapon");
packet.WritePrimitive(hasAssaultWeapon);
if (hasAssaultWeapon) {
ComponentWrapper cAssaultWeapon = m_LocalPlayer["AssaultWeapon"];
packet.WritePrimitive((int)cAssaultWeapon["MagazineAmmo"]);
packet.WritePrimitive((int)cAssaultWeapon["Ammo"]);
}
m_Unreliable.Send(packet);
}
void Client::identifyPacketLoss()
@@ -433,17 +483,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()
@@ -464,7 +512,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();
}
}
@@ -472,7 +520,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)
@@ -503,7 +551,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)
+10
View File
@@ -0,0 +1,10 @@
#include "Network/HybridClient.h"
HybridClient::HybridClient()
{
}
HybridClient::~HybridClient()
{
}
+9
View File
@@ -0,0 +1,9 @@
#include "Network/HybridServer.h"
HybridServer::HybridServer()
{
}
HybridServer::~HybridServer()
{
}
+15
View File
@@ -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;
+48 -11
View File
@@ -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;
}
+259 -207
View File
@@ -6,19 +6,18 @@ 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);
EVENT_SUBSCRIBE_MEMBER(m_EEntityDeleted, &Server::OnEntityDeleted);
EVENT_SUBSCRIBE_MEMBER(m_EComponentDeleted, &Server::OnComponentDeleted);
EVENT_SUBSCRIBE_MEMBER(m_EPlayerDamage, &Server::OnPlayerDamage);
// Bind
if (port == 0) {
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 +28,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 +87,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 +126,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 +148,7 @@ void Server::sendSnapshot()
Packet packet(MessageType::Snapshot);
addInputCommandsToPacket(packet);
addChildrenToPacket(packet, EntityID_Invalid);
broadcast(packet);
unreliableBroadcast(packet);
}
void Server::addInputCommandsToPacket(Packet& packet)
@@ -190,6 +171,12 @@ void Server::addChildrenToPacket(Packet & packet, EntityID entityID)
// Loop through every child
for (auto it = itPair.first; it != itPair.second; it++) {
EntityID childEntityID = it->second;
// HACK: Only sync players for now, since the map turned out to be TOO LARGE to send in one snapshot and Simon's computer shits itself
EntityWrapper childEntity(m_World, childEntityID);
if (!shouldSendToClient(childEntity)) {
continue;
}
// Write EntityID and parentsID and Entity name
packet.WritePrimitive(childEntityID);
packet.WritePrimitive(entityID);
@@ -241,7 +228,7 @@ void Server::sendPing()
// Time message
m_StartPingTime = std::clock();
// Send message
broadcast(packet);
reliableBroadcast(packet);
}
void Server::checkForTimeOuts()
@@ -249,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)
@@ -267,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") {
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)
@@ -306,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
@@ -388,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)
@@ -428,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;
}
@@ -437,7 +400,7 @@ bool Server::OnEntityDeleted(const Events::EntityDeleted & e)
if (!e.Cascaded) {
Packet packet = Packet(MessageType::EntityDeleted);
packet.WritePrimitive<EntityID>(e.DeletedEntity);
broadcast(packet);
reliableBroadcast(packet);
}
return false;
}
@@ -445,14 +408,72 @@ bool Server::OnEntityDeleted(const Events::EntityDeleted & e)
bool Server::OnComponentDeleted(const Events::ComponentDeleted & e)
{
if (!e.Cascaded) {
Packet packet = Packet(MessageType::ComponentDeleted);
packet.WritePrimitive<EntityID>(e.Entity);
packet.WriteString(e.ComponentType);
broadcast(packet);
if (shouldSendToClient(EntityWrapper(m_World, e.Entity))) {
Packet packet = Packet(MessageType::ComponentDeleted);
packet.WritePrimitive<EntityID>(e.Entity);
packet.WriteString(e.ComponentType);
reliableBroadcast(packet);
}
}
return false;
}
bool Server::OnPlayerDamage(const Events::PlayerDamage& e)
{
Packet packet(MessageType::OnPlayerDamage);
packet.WritePrimitive(e.Inflictor.ID);
packet.WritePrimitive(e.Victim.ID);
packet.WritePrimitive(e.Damage);
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" || 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);
}
}
}
void Server::parsePlayerTransform(Packet& packet)
{
glm::vec3 position;
@@ -464,11 +485,42 @@ void Server::parsePlayerTransform(Packet& packet)
orientation.y = packet.ReadPrimitive<float>();
orientation.z = packet.ReadPrimitive<float>();
PlayerID playerID = GetPlayerIDFromEndpoint(m_ReceiverEndpoint);
EntityWrapper player(m_World, m_ConnectedPlayers.at(playerID).EntityID);
PlayerID playerID = GetPlayerIDFromEndpoint();
bool hasAssaultWeapon = packet.ReadPrimitive<bool>();
int magazineAmmo;
int ammo;
if (hasAssaultWeapon) {
magazineAmmo = packet.ReadPrimitive<int>();
ammo = packet.ReadPrimitive<int>();
}
EntityWrapper player(m_World, m_ConnectedPlayers.at(playerID).EntityID);
if (player.Valid()) {
player["Transform"]["Position"] = position;
player["Transform"]["Orientation"] = orientation;
if (hasAssaultWeapon) {
player["AssaultWeapon"]["MagazineAmmo"] = magazineAmmo;
player["AssaultWeapon"]["Ammo"] = ammo;
}
}
}
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;
}
+107
View File
@@ -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();
}
+110
View File
@@ -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;
}
+66
View File
@@ -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();
}
+62
View File
@@ -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)
{ }
+26 -28
View File
@@ -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");
+5 -2
View File
@@ -79,7 +79,6 @@ void RenderSystem::fillSprites(std::list<std::shared_ptr<RenderJob>>& jobs, Worl
bool RenderSystem::isEntityVisible(EntityWrapper& entity)
{
// Only render children of a camera if that camera is currently active
if (isChildOfACamera(entity) && !isChildOfCurrentCamera(entity)) {
return false;
@@ -87,7 +86,11 @@ bool RenderSystem::isEntityVisible(EntityWrapper& entity)
// Hide things parented to local player if they have the HiddenFromLocalPlayer component
bool outOfBodyExperience = ResourceManager::Load<ConfigFile>("Config.ini")->Get<bool>("Debug.OutOfBodyExperience", false);
if (entity.HasComponent("HiddenForLocalPlayer") && (entity == m_LocalPlayer || entity.IsChildOf(m_LocalPlayer)) && !outOfBodyExperience) {
if (
(entity.HasComponent("HiddenForLocalPlayer") || entity.FirstParentWithComponent("HiddenForLocalPlayer").Valid())
&& (entity == m_LocalPlayer || entity.IsChildOf(m_LocalPlayer))
&& !outOfBodyExperience
) {
return false;
}
+1
View File
@@ -168,6 +168,7 @@ void Renderer::SortRenderJobsByDepth(RenderScene &scene)
//Sort all forward jobs so transparency is good.
scene.Jobs.TransparentObjects.sort(Renderer::DepthSort);
scene.Jobs.SpriteJob.sort(Renderer::DepthSort);
scene.Jobs.Text.sort(Renderer::DepthSort);
}
void Renderer::GenerateTexture(GLuint* texture, GLenum wrapping, GLenum filtering, glm::vec2 dimensions, GLint internalFormat, GLint format, GLenum type)
+7 -2
View File
@@ -18,12 +18,15 @@
#include "Game/Systems/DamageIndicatorSystem.h"
#include "Game/Systems/Weapon/WeaponSystem.h"
#include "Rendering/AnimationSystem.h"
#include "Game/Systems/PlayerHUDSystem.h"
#include "Game/Systems/HealthHUDSystem.h"
#include "Rendering/BoneAttachmentSystem.h"
#include "Game/Systems/LifetimeSystem.h"
#include "../Engine/Core/UniformScaleSystem.h"
#include "Rendering/AnimationSystem.h"
#include "Network/MultiplayerSnapshotFilter.h"
#include "Game/Systems/AmmunitionHUDSystem.h"
#include "Game/Systems/KillFeedSystem.h"
Game::Game(int argc, char* argv[])
{
@@ -127,6 +130,8 @@ Game::Game(int argc, char* argv[])
m_SystemPipeline->AddSystem<PickupSpawnSystem>(updateOrderLevel);
m_SystemPipeline->AddSystem<AmmoPickupSystem>(updateOrderLevel);
m_SystemPipeline->AddSystem<DamageIndicatorSystem>(updateOrderLevel);
m_SystemPipeline->AddSystem<AmmunitionHUDSystem>(updateOrderLevel);
m_SystemPipeline->AddSystem<KillFeedSystem>(updateOrderLevel);
// Populate Octree with collidables
++updateOrderLevel;
m_SystemPipeline->AddSystem<FillOctreeSystem>(updateOrderLevel, m_OctreeCollision, "Collidable");
@@ -134,8 +139,8 @@ Game::Game(int argc, char* argv[])
m_SystemPipeline->AddSystem<FillFrustumOctreeSystem>(updateOrderLevel, m_OctreeFrustrumCulling);
m_SystemPipeline->AddSystem<AnimationSystem>(updateOrderLevel);
m_SystemPipeline->AddSystem<UniformScaleSystem>(updateOrderLevel);
m_SystemPipeline->AddSystem<HealthHUDSystem>(updateOrderLevel);
m_SystemPipeline->AddSystem<PlayerDeathSystem>(updateOrderLevel);
m_SystemPipeline->AddSystem<PlayerHUDSystem>(updateOrderLevel);
// Collision and TriggerSystem should update after player.
++updateOrderLevel;
m_SystemPipeline->AddSystem<BoneAttachmentSystem>(updateOrderLevel);
+110
View File
@@ -0,0 +1,110 @@
/*
Author: Vladimir Sedach.
Purpose: demo of Call Stack creation by our own means,
and with MiniDumpWriteDump() function of DbgHelp.dll.
*/
#include <iostream>
#include <ctime>
#include <windows.h>
#include <tlhelp32.h>
//#include "dbghelp.h"
//#define DEBUG_DPRINTF 1 //allow d()
//#include "wfun.h"
#pragma optimize("y", off) //generate stack frame pointers for all functions - same as /Oy- in the project
#pragma warning(disable: 4200) //nonstandard extension used : zero-sized array in struct/union
#pragma warning(disable: 4100) //unreferenced formal parameter
// In case you don't have dbghelp.h.
#ifndef _DBGHELP_
typedef struct _MINIDUMP_EXCEPTION_INFORMATION {
DWORD ThreadId;
PEXCEPTION_POINTERS ExceptionPointers;
BOOL ClientPointers;
} MINIDUMP_EXCEPTION_INFORMATION, *PMINIDUMP_EXCEPTION_INFORMATION;
typedef enum _MINIDUMP_TYPE {
MiniDumpNormal = 0x00000000,
MiniDumpWithDataSegs = 0x00000001,
} MINIDUMP_TYPE;
typedef BOOL (WINAPI * MINIDUMP_WRITE_DUMP)(
IN HANDLE hProcess,
IN DWORD ProcessId,
IN HANDLE hFile,
IN MINIDUMP_TYPE DumpType,
IN CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, OPTIONAL
IN PVOID UserStreamParam, OPTIONAL
IN PVOID CallbackParam OPTIONAL
);
#else
typedef BOOL (WINAPI * MINIDUMP_WRITE_DUMP)(
IN HANDLE hProcess,
IN DWORD ProcessId,
IN HANDLE hFile,
IN MINIDUMP_TYPE DumpType,
IN CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, OPTIONAL
IN PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, OPTIONAL
IN PMINIDUMP_CALLBACK_INFORMATION CallbackParam OPTIONAL
);
#endif //#ifndef _DBGHELP_
HMODULE hDbgHelp;
MINIDUMP_WRITE_DUMP MiniDumpWriteDump_;
// Tool Help functions.
typedef HANDLE (WINAPI * CREATE_TOOL_HELP32_SNAPSHOT)(DWORD dwFlags, DWORD th32ProcessID);
//*************************************************************************************
void WINAPI Create_Dump(PEXCEPTION_POINTERS pException, BOOL File_Flag, BOOL Show_Flag)
//*************************************************************************************
// Create dump.
// pException can be either GetExceptionInformation() or NULL.
// If File_Flag = TRUE - write dump files (.dmz and .dmp) with the name of the current process.
// If Show_Flag = TRUE - show message with Get_Exception_Info() dump.
{
// Try to get MiniDumpWriteDump() address.
hDbgHelp = LoadLibrary("DBGHELP.DLL");
MiniDumpWriteDump_ = (MINIDUMP_WRITE_DUMP)GetProcAddress(hDbgHelp, "MiniDumpWriteDump");
// If MiniDumpWriteDump() of DbgHelp.dll available.
if (MiniDumpWriteDump_)
{
HANDLE hDump_File;
CHAR Dump_Path[MAX_PATH];
GetModuleFileName(NULL, Dump_Path, sizeof(Dump_Path)); //path of current process
std::time_t t = std::time(NULL);
char tStr[16];
std::strftime(tStr, 32, " %a %H-%M-%S", std::localtime(&t));
std::string time(tStr);
std::string path(Dump_Path);
path = path.substr(0, path.length() - 4);
path += time + ".dmp";
MINIDUMP_EXCEPTION_INFORMATION M;
M.ThreadId = GetCurrentThreadId();
M.ExceptionPointers = pException;
M.ClientPointers = 0;
hDump_File = CreateFile(path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
MiniDumpWriteDump_(GetCurrentProcess(), GetCurrentProcessId(), hDump_File,
MiniDumpNormal, (pException) ? &M : NULL, NULL, NULL);
CloseHandle(hDump_File);
std::cout << "Memory dumped to: \"" << path.c_str() << "\"";
MessageBox(NULL, ("Application crashed, memory dumped to: " + path).c_str(), "MiniDump", MB_ICONHAND | MB_OK);
} else {
MessageBox(NULL, "Application crashed, memory dump failed.", "MiniDump", MB_ICONHAND | MB_OK);
}
}
@@ -9,7 +9,15 @@ MultiplayerSnapshotFilter::MultiplayerSnapshotFilter(EventBroker* eventBroker)
bool MultiplayerSnapshotFilter::FilterComponent(EntityWrapper entity, SharedComponentWrapper& component)
{
if (entity == m_LocalPlayer || entity.IsChildOf(m_LocalPlayer)) {
return false;
if (
component.Info.Name == "Transform"
|| component.Info.Name == "Physics"
|| component.Info.Name == "AssaultWeapon"
|| component.Info.Name == "Animation"
|| component.Info.Name == "AnimationOffset"
) {
return false;
}
}
if (component.Info.Name == "Physics") {
+36
View File
@@ -0,0 +1,36 @@
#include "Game/Systems/AmmunitionHUDSystem.h"
void AmmunitionHUDSystem::Update(double dt)
{
//Hud element for tracking ammunition from parent with AssaultWeapon component.Child with the name "MagazineAmmo" tracks clip ammunition.Child with the name "Ammo" tracks ammo.</xs:documentation>
auto ammunitionHUDs = m_World->GetComponents("AmmunitionHUD");
if (ammunitionHUDs == nullptr) {
return;
}
for (auto& ammunitionHUDComponent : *ammunitionHUDs) {
EntityWrapper entity = EntityWrapper(m_World, ammunitionHUDComponent.EntityID);
EntityWrapper playerEntity = entity.FirstParentWithComponent("AssaultWeapon");
if (!playerEntity.Valid()) {
return;
}
EntityWrapper magazineAmmo = entity.FirstChildByName("MagazineAmmo");
if(magazineAmmo.Valid()) {
if(magazineAmmo.HasComponent("Text")) {
(std::string&)magazineAmmo["Text"]["Content"] = std::to_string((int)playerEntity["AssaultWeapon"]["MagazineAmmo"]);
}
}
EntityWrapper ammo = entity.FirstChildByName("Ammo");
if (ammo.Valid()) {
if (ammo.HasComponent("Text")) {
(std::string&)ammo["Text"]["Content"] = std::to_string((int)playerEntity["AssaultWeapon"]["Ammo"]);
}
}
}
}
@@ -20,6 +20,10 @@ void CapturePointHUDSystem::Update(double dt)
return;
}
if(!CapturePointHUDElements) {
return;
}
for (auto& cCapturePointHUD : *CapturePointHUDElements) {
int HUD_ID = cCapturePointHUD["CapturePointNumber"];
EntityWrapper entityHUD = EntityWrapper(m_World, cCapturePointHUD.EntityID);
+9 -3
View File
@@ -6,15 +6,21 @@ CapturePointSystem::CapturePointSystem(SystemParams params)
, PureSystem("CapturePoint")
{
//subscribe/listenTo playerdamage,healthpickup events (using the eventBroker)
EVENT_SUBSCRIBE_MEMBER(m_ETriggerTouch, &CapturePointSystem::OnTriggerTouch);
EVENT_SUBSCRIBE_MEMBER(m_ETriggerLeave, &CapturePointSystem::OnTriggerLeave);
EVENT_SUBSCRIBE_MEMBER(m_ECaptured, &CapturePointSystem::OnCaptured);
if (IsClient) {
EVENT_SUBSCRIBE_MEMBER(m_ETriggerTouch, &CapturePointSystem::OnTriggerTouch);
EVENT_SUBSCRIBE_MEMBER(m_ETriggerLeave, &CapturePointSystem::OnTriggerLeave);
EVENT_SUBSCRIBE_MEMBER(m_ECaptured, &CapturePointSystem::OnCaptured);
}
}
//here all capturepoints will update their component
//NOTE: needs to run each frame, since we're possibly modifying the captureTimer for the capturePoints by dt
void CapturePointSystem::UpdateComponent(EntityWrapper& capturePointEntity, ComponentWrapper& cCapturePoint, double dt)
{
if (!IsClient) {
return;
}
if (m_WinnerWasFound) {
return;
}
+5 -2
View File
@@ -18,12 +18,15 @@ bool DamageIndicatorSystem::OnPlayerDamage(Events::PlayerDamage& e)
return false;
}
if (e.Victim != LocalPlayer) {
//if (e.Victim != LocalPlayer) {
// return false;
//}
if (e.Victim != LocalPlayer && !e.Victim.IsChildOf(LocalPlayer)) {
return false;
}
if (!e.Inflictor.Valid() || !e.Victim.Valid()) {
return false;
return false;
}
//grab players direction
@@ -1,6 +1,6 @@
#include "Game/Systems/PlayerHUDSystem.h"
#include "Game/Systems/HealthHUDSystem.h"
void PlayerHUDSystem::Update(double dt)
void HealthHUDSystem::Update(double dt)
{
auto healthHUDs = m_World->GetComponents("HealthHUD");
if (healthHUDs == nullptr) {
@@ -27,13 +27,13 @@ void PlayerHUDSystem::Update(double dt)
s = s + "/";
s = s + std::to_string((int)(double)entityIDParent["Health"]["MaxHealth"]);
float healthPercentage = (double)entityIDParent["Health"]["Health"]/(double)entityIDParent["Health"]["MaxHealth"];
(glm::vec4&)entity["Text"]["Color"] = glm::vec4(1.0 - healthPercentage, 0.f, healthPercentage, 1.f);
//(glm::vec4&)entity["Text"]["Color"] = glm::vec4(1.0 - healthPercentage, 0.f, healthPercentage, glm::vec4(entity["Text"]["Color"]).a);
entity["Text"]["Content"] = s;
}
if(entity.HasComponent("Fill")) {
float healthPercentage = (double)entityIDParent["Health"]["Health"]/(double)entityIDParent["Health"]["MaxHealth"];
(glm::vec4&)entity["Fill"]["Color"] = glm::vec4(1.0 - healthPercentage, 0.f, healthPercentage, 0.f);
(glm::vec4&)entity["Fill"]["Color"] = glm::vec4(1.0 - healthPercentage, 0.f, healthPercentage, glm::vec4(entity["Fill"]["Color"]).a);
(double&)entity["Fill"]["Percentage"] = healthPercentage;
}
+13 -8
View File
@@ -8,25 +8,30 @@ HealthSystem::HealthSystem(SystemParams params)
EVENT_SUBSCRIBE_MEMBER(m_EPlayerDamage, &HealthSystem::OnPlayerDamaged);
EVENT_SUBSCRIBE_MEMBER(m_EPlayerHealthPickup, &HealthSystem::OnPlayerHealthPickup);
EVENT_SUBSCRIBE_MEMBER(m_InputCommand, &HealthSystem::OnInputCommand);
m_NetworkEnabled = ResourceManager::Load<ConfigFile>("Config.ini")->Get("Networking.StartNetwork", false);
}
void HealthSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt)
void HealthSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& cHealth, double dt)
{
double& health = cHealth["Health"];
if (health <= 0.0) {
Events::PlayerDeath ePlayerDeath;
ePlayerDeath.Player = entity;
m_EventBroker->Publish(ePlayerDeath);
//Note: we will delete the entity in PlayerDeathSystem
}
}
bool HealthSystem::OnPlayerDamaged(Events::PlayerDamage& e)
{
if (!IsServer && m_NetworkEnabled) {
return false;
}
ComponentWrapper cHealth = e.Victim["Health"];
double& health = cHealth["Health"];
health -= e.Damage;
if (health <= 0.0) {
Events::PlayerDeath ePlayerDeath;
ePlayerDeath.Player = e.Victim;
m_EventBroker->Publish(ePlayerDeath);
//Note: we will delete the entity in PlayerDeathSystem
}
return true;
}
+80
View File
@@ -0,0 +1,80 @@
#include "Game/Systems/KillFeedSystem.h"
void KillFeedSystem::Update(double dt)
{
auto killFeeds = m_World->GetComponents("KillFeed");
if (killFeeds == nullptr) {
return;
}
for (auto& killFeedComponent : *killFeeds) {
EntityWrapper entity = EntityWrapper(m_World, killFeedComponent.EntityID);
for (int i = 1; i <= 3; i++) {
EntityWrapper child = entity.FirstChildByName("KillFeed" + std::to_string(i));
if (child.HasComponent("Text")) {
(std::string&)child["Text"]["Content"] = "";
}
}
int feedIndex = 1;
for (auto it = m_DeathQueue.begin(); it != m_DeathQueue.end(); ) {
bool remove = false;
EntityWrapper child = entity.FirstChildByName("KillFeed" + std::to_string(feedIndex));
if (child.HasComponent("Text")) {
(std::string&)child["Text"]["Content"] = (*it).Content;
(glm::vec4&)child["Text"]["Color"] = (*it).Color;
(*it).TimeToLive -= dt;
if ((*it).TimeToLive <= 0.f) {
(std::string&)child["Text"]["Content"] = "";
(glm::vec4&)child["Text"]["Color"] = (*it).Color;
remove = true;
}
}
feedIndex++;
if(feedIndex > 3) {
break;
}
if(remove) {
it = m_DeathQueue.erase(it);
} else {
it++;
}
}
}
}
bool KillFeedSystem::OnPlayerDeath(Events::PlayerDeath& e)
{
KillFeedInfo kfInfo;
if (e.Player.HasComponent("Team")) {
int red = e.Player["Team"].Enum("Team", "Red");
int blue = e.Player["Team"].Enum("Team", "Blue");
if ((int)e.Player["Team"]["Team"] == red) {
kfInfo.Content = "Blue Player killed Red Player";
kfInfo.Color = glm::vec4(0.f, 0.2f, 1.f, 0.8f);
m_DeathQueue.push_back(kfInfo);
} else if ((int)e.Player["Team"]["Team"] == blue) {
kfInfo.Content = "Red Player killed blue Player";
kfInfo.Color = glm::vec4(1.f, 0.f, 0.f, 0.8f);
m_DeathQueue.push_back(kfInfo);
}
}
if(m_DeathQueue.size() > 3) {
m_DeathQueue.pop_front();
}
return true;
}
+13 -10
View File
@@ -40,7 +40,8 @@ void PlayerMovementSystem::updateMovementControllers(double dt)
EntityWrapper playerModel = player.FirstChildByName("PlayerModel");
if (playerModel.Valid()) {
ComponentWrapper cAnimationOffset = playerModel["AnimationOffset"];
double time = (cameraOrientation.x + glm::half_pi<float>()) / glm::pi<float>();
float pitch = cameraOrientation.x + 0.2;
double time = (pitch + glm::half_pi<float>()) / glm::pi<float>();
cAnimationOffset["Time"] = time;
}
}
@@ -113,15 +114,17 @@ void PlayerMovementSystem::updateMovementControllers(double dt)
if (isOnGround) {
controller->SetDoubleJumping(false);
} else {
//put a hexagon at the players feet
auto hexagonEffect = ResourceManager::Load<EntityFile>("Schema/Entities/DoubleJumpHexagon.xml");
EntityFileParser parser(hexagonEffect);
EntityID hexagonEffectID = parser.MergeEntities(m_World);
EntityWrapper hexagonEW = EntityWrapper(m_World, hexagonEffectID);
hexagonEW["Transform"]["Position"] = (glm::vec3)player["Transform"]["Position"];
controller->SetDoubleJumping(true);
Events::DoubleJump e;
m_EventBroker->Publish(e);
if (IsClient) {
//put a hexagon at the players feet
auto hexagonEffect = ResourceManager::Load<EntityFile>("Schema/Entities/DoubleJumpHexagon.xml");
EntityFileParser parser(hexagonEffect);
EntityID hexagonEffectID = parser.MergeEntities(m_World);
EntityWrapper hexagonEW = EntityWrapper(m_World, hexagonEffectID);
hexagonEW["Transform"]["Position"] = (glm::vec3)player["Transform"]["Position"];
controller->SetDoubleJumping(true);
Events::DoubleJump e;
m_EventBroker->Publish(e);
}
}
velocity.y = 4.f;
}
+11 -6
View File
@@ -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);
@@ -175,11 +176,15 @@ bool PlayerSpawnSystem::OnPlayerDeath(Events::PlayerDeath& e)
if ((ComponentInfo::EnumType)cTeam["Team"] == cTeam["Team"].Enum("Spectator")) {
return false;
}
if (m_PlayerIDs.find(e.Player.ID) == m_PlayerIDs.end()) {
if (m_PlayerIDs.count(e.Player.ID) == 0) {
return false;
}
SpawnRequest req;
req.PlayerID = m_PlayerIDs.at(e.Player.ID);
req.Team = cTeam["Team"];
m_SpawnRequests.push_back(req);
SpawnRequest req;
req.PlayerID = m_PlayerIDs.at(e.Player.ID);
req.Team = cTeam["Team"];
m_SpawnRequests.push_back(req);
return true;
}
+13 -7
View File
@@ -6,13 +6,15 @@ SoundSystem::SoundSystem(SystemParams params)
{
ConfigFile* config = ResourceManager::Load<ConfigFile>("Config.ini");
m_Announcer = ResourceManager::Load<ConfigFile>("Config.ini")->Get<std::string>("Sound.Announcer", "female");
EVENT_SUBSCRIBE_MEMBER(m_EPlayerSpawned, &SoundSystem::OnPlayerSpawned);
EVENT_SUBSCRIBE_MEMBER(m_InputCommand, &SoundSystem::OnInputCommand);
EVENT_SUBSCRIBE_MEMBER(m_EDoubleJump, &SoundSystem::OnDoubleJump);
EVENT_SUBSCRIBE_MEMBER(m_EDashAbility, &SoundSystem::OnDashAbility);
EVENT_SUBSCRIBE_MEMBER(m_EPlayerDamage, &SoundSystem::OnPlayerDamage);
EVENT_SUBSCRIBE_MEMBER(m_ECaptured, &SoundSystem::OnCaptured);
EVENT_SUBSCRIBE_MEMBER(m_ETriggerTouch, &SoundSystem::OnTriggerTouch);
if (IsClient) {
EVENT_SUBSCRIBE_MEMBER(m_EPlayerSpawned, &SoundSystem::OnPlayerSpawned);
EVENT_SUBSCRIBE_MEMBER(m_InputCommand, &SoundSystem::OnInputCommand);
EVENT_SUBSCRIBE_MEMBER(m_EDoubleJump, &SoundSystem::OnDoubleJump);
EVENT_SUBSCRIBE_MEMBER(m_EDashAbility, &SoundSystem::OnDashAbility);
EVENT_SUBSCRIBE_MEMBER(m_EPlayerDamage, &SoundSystem::OnPlayerDamage);
EVENT_SUBSCRIBE_MEMBER(m_ECaptured, &SoundSystem::OnCaptured);
EVENT_SUBSCRIBE_MEMBER(m_ETriggerTouch, &SoundSystem::OnTriggerTouch);
}
}
void SoundSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& cComponent, double dt)
@@ -20,6 +22,10 @@ void SoundSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& cComp
void SoundSystem::Update(double dt)
{
if (!IsClient) {
return;
}
// Temp for play test.
if (m_DrumsIsPlaying) {
m_DrumsIsPlaying = !drumTimer(dt);
@@ -4,6 +4,7 @@ AssaultWeaponBehaviour::AssaultWeaponBehaviour(SystemParams systemParams, IRende
: WeaponBehaviour(systemParams, renderer, collisionOctree, player)
{
m_FirstPersonModel = m_Player.FirstChildByName("Hands");
m_ThirdPersonModel = m_Player.FirstChildByName("PlayerModel");
EVENT_SUBSCRIBE_MEMBER(m_EAnimationComplete, &AssaultWeaponBehaviour::OnAnimationComplete);
}
@@ -56,9 +57,14 @@ void AssaultWeaponBehaviour::Update(double dt)
if (m_Reloading) {
m_ReloadTimer -= dt;
// Re-enable glow on reload impersonator half-way through the animation
if (m_ReloadTimer <= (double)m_Player["AssaultWeapon"]["ReloadTime"] / 2.0) {
if (m_ReloadImpersonator.Valid()) {
m_ReloadImpersonator["Model"]["GlowMap"] = true;
if (IsClient) {
if (m_ReloadTimer <= (double)m_Player["AssaultWeapon"]["ReloadTime"] / 2.0) {
if (m_FirstPersonReloadImpersonator.Valid()) {
m_FirstPersonReloadImpersonator["Model"]["GlowMap"] = true;
}
if (m_ThirdPersonReloadImpersonator.Valid()) {
m_ThirdPersonReloadImpersonator["Model"]["GlowMap"] = true;
}
}
}
if (m_ReloadTimer <= 0) {
@@ -75,14 +81,18 @@ void AssaultWeaponBehaviour::Update(double dt)
}
if (!m_Firing && !m_Reloading) {
playIdleAnimation();
if (IsClient) {
playIdleAnimation();
}
}
// Disable glow map on weapon if it's out of ammo
// Make real first person weapon model visible again
EntityWrapper firstPersonWeaponModel = m_Player.FirstChildByName("WeaponModel");
if (firstPersonWeaponModel.Valid()) {
firstPersonWeaponModel["Model"]["GlowMap"] = hasAmmo();
if (IsClient) {
EntityWrapper firstPersonWeaponModel = m_Player.FirstChildByName("WeaponModel");
if (firstPersonWeaponModel.Valid()) {
firstPersonWeaponModel["Model"]["GlowMap"] = hasAmmo();
}
}
}
@@ -127,16 +137,19 @@ void AssaultWeaponBehaviour::fireRound()
// Fire
magAmmo -= 1;
spawnTracer();
playFireSound();
viewPunch();
playShootAnimation();
bool hit = shoot(cAssaultWeapon["BaseDamage"]);
if (hit) {
showHitMarker();
}
m_TimeSinceLastFire = 0.0;
// Effects
if (IsClient) {
spawnTracer();
playFireSound();
viewPunch();
playShootAnimation();
bool hit = shoot(cAssaultWeapon["BaseDamage"]);
if (hit) {
showHitMarker();
}
}
}
void AssaultWeaponBehaviour::spawnTracer()
@@ -146,7 +159,8 @@ void AssaultWeaponBehaviour::spawnTracer()
}
EntityWrapper spawner;
if (m_Player == LocalPlayer) {
bool outOfBodyExperience = ResourceManager::Load<ConfigFile>("Config.ini")->Get<bool>("Debug.OutOfBodyExperience", false);
if (m_Player == LocalPlayer && !outOfBodyExperience) {
spawner = m_Player.FirstChildByName("WeaponMuzzle");
} else {
spawner = m_Player.FirstChildByName("ThirdPersonWeaponMuzzle");
@@ -225,7 +239,13 @@ void AssaultWeaponBehaviour::finishReload()
// Make real first person weapon model visible again
EntityWrapper firstPersonWeaponModel = m_Player.FirstChildByName("WeaponModel");
firstPersonWeaponModel["Model"]["Visible"] = true;
if (firstPersonWeaponModel.Valid()) {
firstPersonWeaponModel["Model"]["Visible"] = true;
}
EntityWrapper thirdPersonWeaponModel = m_Player.FirstChildByName("ThirdPersonWeaponModel");
if (thirdPersonWeaponModel.Valid()) {
thirdPersonWeaponModel["Model"]["Visible"] = true;
}
m_Reloading = false;
}
@@ -278,19 +298,45 @@ void AssaultWeaponBehaviour::playIdleAnimation()
void AssaultWeaponBehaviour::playReloadAnimation()
{
// Play animation
ComponentWrapper cAnimation = m_FirstPersonModel["Animation"];
cAnimation["AnimationName1"] = "ReloadSwitch";
cAnimation["Weight1"] = 1.0;
cAnimation["Time1"] = 0.0;
cAnimation["Speed1"] = 0.5;
cAnimation["Loop1"] = true;
// First person
if (IsClient)
{
ComponentWrapper cAnimation = m_FirstPersonModel["Animation"];
cAnimation["AnimationName1"] = "ReloadSwitch";
cAnimation["Weight1"] = 1.0;
cAnimation["Time1"] = 0.0;
cAnimation["Speed1"] = 0.5;
cAnimation["Loop1"] = true;
}
// TODO: Third person
//{
// ComponentWrapper cAnimation = m_ThirdPersonModel["Animation"];
// cAnimation["AnimationName1"] = "ReloadSwitch";
// cAnimation["Weight1"] = 1.0;
// cAnimation["Time1"] = 0.0;
// cAnimation["Speed1"] = 0.5;
// cAnimation["Loop1"] = true;
//}
// Hide weapon model and spawn the exploding version
EntityWrapper firstPersonWeaponModel = m_Player.FirstChildByName("WeaponModel");
EntityWrapper reloadSpawner = m_Player.FirstChildByName("FirstPersonReloadSpawner");
m_ReloadImpersonator = SpawnerSystem::Spawn(reloadSpawner, reloadSpawner);
firstPersonWeaponModel["Model"].Copy(m_ReloadImpersonator["Model"]);
firstPersonWeaponModel["Model"]["Visible"] = false;
{
EntityWrapper firstPersonWeaponModel = m_Player.FirstChildByName("WeaponModel");
EntityWrapper reloadSpawner = m_Player.FirstChildByName("FirstPersonReloadSpawner");
if (IsClient) {
m_FirstPersonReloadImpersonator = SpawnerSystem::Spawn(reloadSpawner, reloadSpawner);
firstPersonWeaponModel["Model"].Copy(m_FirstPersonReloadImpersonator["Model"]);
}
firstPersonWeaponModel["Model"]["Visible"] = false;
}
{
EntityWrapper thirdPersonWeaponModel = m_Player.FirstChildByName("ThirdPersonWeaponModel");
EntityWrapper reloadSpawner = m_Player.FirstChildByName("ThirdPersonReloadSpawner");
if (IsClient) {
m_ThirdPersonReloadImpersonator = SpawnerSystem::Spawn(reloadSpawner, reloadSpawner);
thirdPersonWeaponModel["Model"].Copy(m_ThirdPersonReloadImpersonator["Model"]);
}
thirdPersonWeaponModel["Model"]["Visible"] = false;
}
}
bool AssaultWeaponBehaviour::shoot(double damage)
@@ -321,6 +367,9 @@ bool AssaultWeaponBehaviour::shoot(double damage)
}
EntityWrapper victim(m_World, pickData.Entity);
if (!victim.Valid()) {
return false;
}
// Don't let us shoot ourselves in the foot
if (victim == LocalPlayer) {
+18 -4
View File
@@ -1,11 +1,25 @@
#include "Game.h"
#include "MiniDump.h"
LONG WINAPI CrashHandler(EXCEPTION_POINTERS* pException);
int main(int argc, char* argv[])
{
Game game(argc, argv);
while (game.Running()) {
game.Tick();
}
::SetUnhandledExceptionFilter(CrashHandler);
Game game(argc, argv);
while (game.Running()) {
game.Tick();
}
return 0;
}
LONG WINAPI CrashHandler(EXCEPTION_POINTERS* pException)
{
//Take minidump. path should be bin/TacticalZ.dmp
//Then show MessageBox, and exit application.
Create_Dump(pException, 1, 1);
return EXCEPTION_EXECUTE_HANDLER;// EXCEPTION_CONTINUE_SEARCH
}