From b3fb0423268a56413a58064b2308c515e1818fdd Mon Sep 17 00:00:00 2001 From: pwalig Date: Thu, 9 Jan 2025 18:30:00 +0100 Subject: [PATCH 1/4] Address review in server.cpp --- src/net/server.cpp | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/src/net/server.cpp b/src/net/server.cpp index 2434679..3239c95 100644 --- a/src/net/server.cpp +++ b/src/net/server.cpp @@ -69,34 +69,31 @@ void server::deleteClient(client* client_){ void server::loop(const int& millis){ epoll_event ee; - int remaining = millis; + auto end = std::chrono::steady_clock::now() + std::chrono::milliseconds(millis); while (true) { - auto begin = std::chrono::steady_clock::now(); - int ready = epoll_wait(_epollFd, &ee, 1, remaining); + int ready = epoll_wait(_epollFd, &ee, 1, + std::chrono::duration_cast( + end - std::chrono::steady_clock::now()).count()); + if (ready == 1) { if (ee.data.ptr == nullptr){ newClient(); } else { client* client_ = (client*)(ee.data.ptr); - if (ee.events & EPOLLIN) { - client_->receive(); - } if (ee.events & EPOLLOUT) { client_->sendFromBuffer(); } + if (ee.events & EPOLLIN) { + client_->receive(); + } } } - auto end = std::chrono::steady_clock::now(); - remaining -= std::chrono::duration_cast(end - begin).count(); - if (remaining <= 0) { - auto begin = std::chrono::steady_clock::now(); + if (end <= std::chrono::steady_clock::now()) { loopLogic(); - remaining = millis; - auto end = std::chrono::steady_clock::now(); - remaining -= std::chrono::duration_cast(end - begin).count(); + end += std::chrono::milliseconds(millis); } } From da6d1bdd0dea459cc39a78aa1e2a2f4076a7210b Mon Sep 17 00:00:00 2001 From: pwalig Date: Thu, 9 Jan 2025 19:31:48 +0100 Subject: [PATCH 2/4] Fix typos in README.md and handle situation when board is full of resources --- README.md | 4 ++-- src/rts/board.cpp | 4 +++- src/rts/game.cpp | 7 ++++++- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 38fc801..b50441f 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@ Some messages consist of only type character others contain more data. - `j` - request join (player will be sent to game room or queue) - `q` - request quit (player will be removed from game room or queue, can still rejoin with `j`) - `m` `` ` ` `` ` ` `` ` ` `` `\n` - request unit to move (`` are coordinates of the unit, `` designate destination) -- `a` `` ` ` `` ` ` `` ` ` `` `\n` - request unit to move (`` are coordinates of the unit, `` coordinates of the target unit) (possible to attack own units) +- `a` `` ` ` `` ` ` `` ` ` `` `\n` - request unit to attack another unit (`` are coordinates of the unit, `` coordinates of the target unit) (possible to attack own units) - `d` `` ` ` `` `\n` - request unit to mine the resource (`` are coordinates of the unit) (unit can only mine resource that it is standing on) ### From server @@ -116,7 +116,7 @@ Structure as follows: Numbers are represented as strings of characters (97 ---> "97" not 'a'). -### Communication order (client`s perspective) +### Communication order (client's perspective) **1:** server sends `c` **2:** client sends `n` diff --git a/src/rts/board.cpp b/src/rts/board.cpp index 039cb0f..cefb462 100644 --- a/src/rts/board.cpp +++ b/src/rts/board.cpp @@ -84,7 +84,9 @@ rts::field* rts::board::closestEmptyField(const field* source) { } rts::field* rts::board::spawnResource(unsigned int hp) { - return randomResourceField(false)->spawnResource(hp); + field* f = randomResourceField(false); + if (f) f->spawnResource(hp); + return f; } void rts::board::spawnResources(unsigned int amount, unsigned int hp) { diff --git a/src/rts/game.cpp b/src/rts/game.cpp index ac29ac2..bb2342b 100644 --- a/src/rts/game.cpp +++ b/src/rts/game.cpp @@ -121,7 +121,12 @@ void rts::game::handleNewClient(client* client_) { void rts::game::loopLogic(){ // spawn resource and inform players - if (rand() % 10 == 0) sendToPlayers(activePlayers, newResourceMessage(_board.spawnResource(resourceHp))); + if (rand() % 10 == 0) { + field* f = _board.spawnResource(resourceHp); + if (f) { + sendToPlayers(activePlayers, newResourceMessage(f)); + } + } // allow units to move again for (player* p : activePlayers) { From 1f35286904f32a35b3023400e75202a8b9aeb0d5 Mon Sep 17 00:00:00 2001 From: pwalig Date: Thu, 9 Jan 2025 20:02:44 +0100 Subject: [PATCH 3/4] Rename board::getConstField to getField and reject empty names --- src/msg/addressUnit.cpp | 2 +- src/msg/fromServerTypes.h | 19 +++++++++++++++++++ src/rts/board.cpp | 2 +- src/rts/board.hpp | 2 +- src/rts/game.cpp | 1 + 5 files changed, 23 insertions(+), 3 deletions(-) create mode 100644 src/msg/fromServerTypes.h diff --git a/src/msg/addressUnit.cpp b/src/msg/addressUnit.cpp index 3cf1f6c..19af8fe 100644 --- a/src/msg/addressUnit.cpp +++ b/src/msg/addressUnit.cpp @@ -7,7 +7,7 @@ message::addressUnitByCoordinates::addressUnitByCoordinates( ) : addressUnit(), x(xpos), y(ypos) {} rts::unit* message::addressUnitByCoordinates::getUnit(const rts::game* g) const{ - const rts::field* f = g->_board.getConstField(x, y); + const rts::field* f = g->_board.getField(x, y); if (!f) return nullptr; return f->_unit; } diff --git a/src/msg/fromServerTypes.h b/src/msg/fromServerTypes.h new file mode 100644 index 0000000..0a19680 --- /dev/null +++ b/src/msg/fromServerTypes.h @@ -0,0 +1,19 @@ +namespace message +{ + enum class fromServer : char { + config = 'c', + join = 'j', + left = 'l', + move = 'm', + attack = 'a', + mine = 'd', + new_unit = 'u', + new_resource = 'f', + tick = 't', + queue = 'q', + yes = 'y', + no = 'n', + lost = 'L', + won = 'W' + }; +} diff --git a/src/rts/board.cpp b/src/rts/board.cpp index cefb462..f7edd50 100644 --- a/src/rts/board.cpp +++ b/src/rts/board.cpp @@ -17,7 +17,7 @@ rts::field* rts::board::getField(unsigned int xpos, unsigned int ypos) { return &fields[xpos][ypos]; else return nullptr; } -const rts::field* rts::board::getConstField(unsigned int xpos, unsigned int ypos) const { +const rts::field* rts::board::getField(unsigned int xpos, unsigned int ypos) const { if (xpos < getXdim() && ypos < getYdim()) return &fields[xpos][ypos]; else return nullptr; diff --git a/src/rts/board.hpp b/src/rts/board.hpp index 88e4dd5..1d5d4a9 100644 --- a/src/rts/board.hpp +++ b/src/rts/board.hpp @@ -15,7 +15,7 @@ namespace rts { board(unsigned int x = 256, unsigned int y = 256); field* getField(unsigned int xpos, unsigned int ypos); - const field* getConstField(unsigned int xpos, unsigned int ypos) const; + const field* getField(unsigned int xpos, unsigned int ypos) const; std::vector resourceFields(bool resource); std::vector constResourceFields(bool resource) const; diff --git a/src/rts/game.cpp b/src/rts/game.cpp index bb2342b..5441933 100644 --- a/src/rts/game.cpp +++ b/src/rts/game.cpp @@ -263,6 +263,7 @@ unsigned int rts::game::getNextUnitId() { } bool rts::game::nameValid(const std::string& name) const { + if (name.empty()) return false; for (char c : name){ if (allowedNameCharacters.find(c) == std::string::npos) return false; } From 3a208ef366bd21a22105f2bc1599368499d0ede8 Mon Sep 17 00:00:00 2001 From: pwalig Date: Thu, 9 Jan 2025 21:02:06 +0100 Subject: [PATCH 4/4] Handle accept failure and dont store sockaddr in client --- src/msg/fromServerTypes.h | 19 ------------------- src/net/client.cpp | 39 ++++++++++++++++++++------------------- src/net/client.hpp | 14 ++++++++++---- src/net/server.cpp | 12 ++++++++---- 4 files changed, 38 insertions(+), 46 deletions(-) delete mode 100644 src/msg/fromServerTypes.h diff --git a/src/msg/fromServerTypes.h b/src/msg/fromServerTypes.h deleted file mode 100644 index 0a19680..0000000 --- a/src/msg/fromServerTypes.h +++ /dev/null @@ -1,19 +0,0 @@ -namespace message -{ - enum class fromServer : char { - config = 'c', - join = 'j', - left = 'l', - move = 'm', - attack = 'a', - mine = 'd', - new_unit = 'u', - new_resource = 'f', - tick = 't', - queue = 'q', - yes = 'y', - no = 'n', - lost = 'L', - won = 'W' - }; -} diff --git a/src/net/client.cpp b/src/net/client.cpp index 065a45d..b545a08 100644 --- a/src/net/client.cpp +++ b/src/net/client.cpp @@ -6,12 +6,22 @@ const unsigned long client::bufsiz = 256; -client::client(server* server_) : owner(server_), clientAddr(), clientAddrSize(sizeof(clientAddr)) { +client::client(server* server_) : owner(server_) { + + sockaddr_storage clientAddr; + socklen_t clientAddrSize(sizeof(clientAddr)); // accept new connection _fd = accept(server_->fd(), (sockaddr *)&clientAddr, &clientAddrSize); - if (_fd == -1) + if (_fd == -1) { perror("accept failed"); + throw connectException("accept failed"); + } + + char host_[NI_MAXHOST], port_[NI_MAXSERV]; + getnameinfo((sockaddr *)&clientAddr, clientAddrSize, host_, NI_MAXHOST, port_, NI_MAXSERV, 0); + _hostname = std::string(host_); + _port = stoi(std::string(port_)); // tell who has connected printf("new connection from: "); @@ -25,28 +35,16 @@ client::client(server* server_) : owner(server_), clientAddr(), clientAddrSize(s int client::fd() const {return _fd;} -std::string client::host() const { - std::string host; - name(&host, nullptr); - return host; +std::string client::hostname() const { + return _hostname; } unsigned int client::port() const { - unsigned int port; - name(nullptr, &port); - return port; -} - -void client::name(std::string* host, unsigned int* port) const { - char host_[NI_MAXHOST], port_[NI_MAXSERV]; - getnameinfo((sockaddr *)&clientAddr, clientAddrSize, host_, NI_MAXHOST, port_, NI_MAXSERV, 0); - if (host) *host = std::string(host_); - if (port) *port = stoi(std::string(port_)); + return _port; } void client::printName() const { - std::string host_ = host(); - printf("%s:%d (fd: %d)", host_.c_str(), port(), _fd); + printf("%s:%d (fd: %d)", _hostname.c_str(), _port, _fd); } epoll_event client::inEvent() { @@ -114,4 +112,7 @@ client::~client() { printf("closed client "); printName(); printf("\n"); -} \ No newline at end of file +} + +client::connectException::connectException(const char* _Message) : runtime_error(_Message) {} +client::connectException::connectException(const std::string& _Message) : runtime_error(_Message) {} diff --git a/src/net/client.hpp b/src/net/client.hpp index a4530d6..59411c3 100644 --- a/src/net/client.hpp +++ b/src/net/client.hpp @@ -5,15 +5,16 @@ #include #include #include +#include class server; class client { private: int _fd; + unsigned int _port; server* owner; // server to which this client is connected to - sockaddr_storage clientAddr; - socklen_t clientAddrSize; + std::string _hostname; static const unsigned long bufsiz; std::vector buffer; @@ -42,13 +43,18 @@ class client { public: + class connectException : public std::runtime_error { + public: + connectException(const char* _Message); + connectException(const std::string& _Message); + }; + std::function&)> onReceive = [](const std::vector&){}; std::function onDisconnect = [](){}; int fd() const; - std::string host() const; + std::string hostname() const; unsigned int port() const; - void name(std::string* host, unsigned int* port) const; void printName() const; // @brief copies data to buffer and sets servers' epoll to wait for EPOLLOUT event. diff --git a/src/net/server.cpp b/src/net/server.cpp index 3239c95..06d5fb3 100644 --- a/src/net/server.cpp +++ b/src/net/server.cpp @@ -55,10 +55,14 @@ int server::fd() const {return _fd;} int server::epollFd() const {return _epollFd;} client* server::newClient() { - client* client_ = new client(this); - clients.insert(client_); - onNewClient(client_); - return client_; + try { + client* client_ = new client(this); + clients.insert(client_); + onNewClient(client_); + return client_; + } catch (client::connectException& cce){ + return nullptr; + } } void server::deleteClient(client* client_){