Skip to content

Commit

Permalink
Merge pull request #2 from mlugg/master
Browse files Browse the repository at this point in the history
Linux support & bugfixes
  • Loading branch information
Blenderiste09 committed Feb 14, 2021
2 parents ef34d3b + 99abc14 commit dde683b
Show file tree
Hide file tree
Showing 5 changed files with 146 additions and 9 deletions.
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,9 @@
GhostServer/Debug/
GhostServer/Release/
.vs/GhostServer/v16/.suo

# Linux build artifacts
GhostServer/ui_mainwindow.h
GhostServer/*_qt.cpp
config.mk
ghost_server
88 changes: 79 additions & 9 deletions GhostServer/networkmanager.cpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
#include "networkmanager.h"

#include <memory>
#include <chrono>
#include <cstdlib>
#include <queue>

#include <SFML/Network.hpp>

#include <QVector>

#define HEARTBEAT_RATE 1000

static std::chrono::time_point<std::chrono::steady_clock> lastHeartbeat;

//DataGhost

sf::Packet& operator>>(sf::Packet& packet, Vector& vec)
Expand Down Expand Up @@ -97,8 +104,8 @@ void NetworkManager::StopServer()
return;
}

for (auto& client : this->clients) {
this->DisconnectPlayer(client);
while (this->clients.size() > 0) {
this->DisconnectPlayer(this->clients.back());
}

this->isRunning = false;
Expand All @@ -110,18 +117,23 @@ void NetworkManager::StopServer()
void NetworkManager::DisconnectPlayer(Client& c)
{
sf::Packet packet;
packet << c.IP.toInteger() << HEADER::DISCONNECT;
packet << HEADER::DISCONNECT << c.ID;
int id = 0;
int toErase = -1;
for (; id < this->clients.size(); ++id) {
if (this->clients[id].IP != c.IP) {
this->clients[id].tcpSocket->send(packet);
} else {
emit this->OnNewEvent("Player " + QString::fromStdString(this->clients[id].name) + " has disconnected !");
this->selector.remove(*this->clients[id].tcpSocket);
this->clients[id].tcpSocket->disconnect();
this->clients.erase(this->clients.begin() + id);
toErase = id;
}
}

if (toErase != -1) {
this->clients.erase(this->clients.begin() + toErase);
}
}

void NetworkManager::DisconnectPlayer(sf::Uint32 ID)
Expand Down Expand Up @@ -196,6 +208,7 @@ void NetworkManager::CheckConnection()
client.modelName = model_name;
client.currentMap = level_name;
client.TCP_only = TCP_only;
client.returnedHeartbeat = true; // Make sure they don't get immediately disconnected; their heartbeat starts on next beat

this->selector.add(*client.tcpSocket);

Expand Down Expand Up @@ -292,13 +305,24 @@ void NetworkManager::TreatTCP(sf::Packet& packet)
if (client) {
std::string map;
packet >> map;
client->currentMap = map;
emit this->OnNewEvent(QString::fromStdString(client->name) + " is now on " + QString::fromStdString(map));
}

break;
}
case HEADER::HEART_BEAT:
break;
case HEADER::HEART_BEAT: {
auto client = this->GetClientByID(ID);
if (client) {
uint32_t token;
packet >> token;
if (token == client->heartbeatToken) {
// Good heartbeat!
client->returnedHeartbeat = true;
}
break;
}
}
case HEADER::MESSAGE: {
for (auto& client : this->clients) {
client.tcpSocket->send(packet);
Expand All @@ -321,8 +345,14 @@ void NetworkManager::TreatTCP(sf::Packet& packet)
break;
}
case HEADER::MODEL_CHANGE: {
for (auto& client : this->clients) {
client.tcpSocket->send(packet);
std::string modelName;
packet >> modelName;
auto client = this->GetClientByID(ID);
if (client) {
client->modelName = modelName;
for (auto& other : this->clients) {
other.tcpSocket->send(packet);
}
}
break;
}
Expand Down Expand Up @@ -350,6 +380,11 @@ void NetworkManager::RunServer()
this->clock.restart();

while (this->isRunning) {
auto now = std::chrono::steady_clock::now();
if (now > lastHeartbeat + std::chrono::milliseconds(HEARTBEAT_RATE)) {
this->DoHeartbeats();
lastHeartbeat = now;
}

//UDP
std::vector<sf::Packet> buffer;
Expand All @@ -360,20 +395,55 @@ void NetworkManager::RunServer()
if (this->selector.isReady(this->listener)) {
this->CheckConnection(); //A player wants to connect
} else {
std::queue<Client*> toDisconnect;

for (int i = 0; i < this->clients.size(); ++i) {
if (this->selector.isReady(*this->clients[i].tcpSocket)) {
sf::Packet packet;
sf::Socket::Status status = this->clients[i].tcpSocket->receive(packet);
if (status == sf::Socket::Disconnected) {
this->DisconnectPlayer(this->clients[i]);
toDisconnect.push(&this->clients[i]);
continue;
}
this->TreatTCP(packet);
}
}

while (!toDisconnect.empty()) {
this->DisconnectPlayer(*toDisconnect.front());
toDisconnect.pop();
}
}
}
}

this->StopServer();
}

void NetworkManager::DoHeartbeats()
{
// We don't disconnect clients in the loop; else, the loop will have
// UB
std::queue<Client*> toDisconnect;

for (auto& client : this->clients) {
if (!client.returnedHeartbeat) {
// Client didn't return heartbeat in time; sever connection
toDisconnect.push(&client);
} else {
// Send a heartbeat
client.heartbeatToken = rand();
client.returnedHeartbeat = false;
sf::Packet packet;
packet << HEADER::HEART_BEAT << sf::Uint32(client.ID) << sf::Uint32(client.heartbeatToken);
if (client.tcpSocket->send(packet) == sf::Socket::Disconnected) {
toDisconnect.push(&client);
}
}
}

while (!toDisconnect.empty()) {
this->DisconnectPlayer(*toDisconnect.front());
toDisconnect.pop();
}
}
5 changes: 5 additions & 0 deletions GhostServer/networkmanager.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <mutex>
#include <atomic>
#include <thread>
#include <cstdint>

#include <QObject>

Expand Down Expand Up @@ -46,6 +47,8 @@ struct Client {
std::string currentMap;
std::unique_ptr<sf::TcpSocket> tcpSocket;
bool TCP_only;
uint32_t heartbeatToken;
bool returnedHeartbeat;
};

class NetworkManager : public QObject
Expand All @@ -70,6 +73,8 @@ class NetworkManager : public QObject

sf::Clock clock;

void DoHeartbeats();

public:
sf::UdpSocket udpSocket;
NetworkManager();
Expand Down
36 changes: 36 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
.PHONY: all clean

CXX=clang++
SDIR=GhostServer
ODIR=obj

SRCS=$(SDIR)/main.cpp $(SDIR)/mainwindow.cpp $(SDIR)/networkmanager.cpp $(SDIR)/mainwindow_qt.cpp $(SDIR)/networkmanager_qt.cpp

OBJS=$(patsubst $(SDIR)/%.cpp, $(ODIR)/%.o, $(SRCS))

DEPS=$(OBJS:%.o=%.d)

CXXFLAGS=-std=c++17 -fPIC
LDFLAGS=-lpthread

include config.mk

all: ghost_server
clean:
rm -rf $(ODIR) ghost_server
rm -rf $(SDIR)/ui_mainwindow.h $(SDIR)/mainwindow_qt.cpp $(SDIR)/networkmanager_qt.cpp

-include $(DEPS)

ghost_server: $(SDIR)/ui_mainwindow.h $(OBJS)
$(CXX) $(LDFLAGS) $(OBJS) -o $@

$(ODIR)/%.o: $(SDIR)/%.cpp
@mkdir -p $(dir $@)
$(CXX) $(CXXFLAGS) -MMD -c $< -o $@

$(SDIR)/ui_mainwindow.h: $(SDIR)/mainwindow.ui
uic $< >$@

$(SDIR)/%_qt.cpp: $(SDIR)/%.h
cd $(SDIR); moc $(notdir $<) -o $(notdir $@)
20 changes: 20 additions & 0 deletions configure
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/bin/sh

PKGS='Qt5Core Qt5Gui Qt5Widgets sfml-network'

pkg_not_found() {
echo 'pkg-config could not find a required package.'
exit 1
}

pkg-config $PKGS || pkg_not_found

set -f
cxxflags=$(pkg-config --cflags $PKGS)
ldflags=$(pkg-config --libs $PKGS)
set +f

{
echo "CXXFLAGS+=$cxxflags"
echo "LDFLAGS+=$ldflags"
} >config.mk

0 comments on commit dde683b

Please sign in to comment.