Skip to content

Commit

Permalink
Merge pull request #25 from pwalig/send-only-updates
Browse files Browse the repository at this point in the history
Send only updates
  • Loading branch information
pwalig authored Dec 21, 2024
2 parents d1f1c09 + c5cabb1 commit 0c3aeef
Show file tree
Hide file tree
Showing 11 changed files with 137 additions and 32 deletions.
32 changes: 27 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,26 +68,32 @@ Some messages consist of only type character others contain more data.
### From client

- `n` `<name>` `\n` - set name or rename self
- `j` `\n` - request join (player will be sent to game room or queue)
- `q` `\n` - request quit (player will be removed from game room or queue, can still rejoin with `j`)
- `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` `<x1>` ` ` `<y1>` ` ` `<x2>` ` ` `<y2>` `\n` - request unit to move (`<x1><y1>` are coordinates of the unit, `<x2><y2>` designate destination)
- `a` `<x1>` ` ` `<y1>` ` ` `<x2>` ` ` `<y2>` `\n` - request unit to move (`<x1><y1>` are coordinates of the unit, `<x2><y2>` coordinates of the target unit) (possible to attack own units)
- `d` `<x1>` ` ` `<y1>` `\n` - request unit to mine the resource (`<x1><y1>` are coordinates of the unit) (unit can only mine resource that it is standing on)

### From server

- `g` `\n` - player was sent to game room (in response to: `j`), `<board x dim>`, `<board y dim>` and `<unitsToWin>` same as in `[config file]`
- `c` `<millis>` ` ` `<maxPlayers>` ` ` `<boardX>` ` ` `<boardY>` ` ` `<unitsToWin>` ` ` `<startResources>` ` ` `<resourceHp>` ` ` `<unitHp>` ` ` `<unitDamage>` ` ` `<allowedNameCharacters>` `\n` - whole server configuration sent to newly joined clients
- `j` `<player name>` `\n` - new player has joined the game room
- `l` `<player name>` `\n` - player `<player name>` has either left or lost the game
- `m` `<id>` ` ` `<x>` ` ` `<y>` `\n` - unit of id `<id>` has moved to `<x>;<y>`
- `a` `<id1>` ` ` `<id2>` `\n` - unit of id `<id1>` attacked unit of id `<id2>`
- `d` `<id>` `\n` - unit of id `<id>` mined a resource
- `u` `<player name>` ` ` `<id>` ` ` `<x>` ` ` `<y>` - player `<player name>` has aquired unit of id `<id>` on field `<x>;<y>`
- `f` `<x>` ` ` `<y>` ` ` `<hp>` `\n` - new resource spawned on field `<x>;<y>`
- `t` `\n` - sent to all players in game room in regular time intervals, marks the and of each tick and a start of the next one
- `q` `\n` - player was sent to queue (in response to: `j`)
- `y` `\n` - client request accepted (in response to: `n`)
- `n` `\n` - client request denied (in response to: `j` or `n`)
- `L` `\n` - client lost the game (and was moved out of game room)
- `W` `\n` - client won the game (and was moved out of game room)

### Board state update
### Board state message

Board state update is sent to all players in the game room in regular time intervals
Board state update is sent to every player that joins the game room

Structure as follows:

Expand All @@ -109,3 +115,19 @@ Structure as follows:
...

Numbers are represented as strings of characters (97 ---> "97" not 'a').

### Communication order (client`s perspective)

**1:** server sends `c`
**2:** client sends `n`
**3:** if server responds `n` => go to step **2**
**3:** else server responds `y`
**4:** if client sends `n` => go to step **3**
**4:** else client sends `j`
**5:** if server responds `q` => wait until server sends `p`, then `r`
**5:** else server reponds `p`, then `r`
**6:** server can send multiple: `j` `l` `m` `a` `d` `u` `f` messages
**6:** client can send multiple: `m` `a` `d` messages
**6:** if client sends `q` => go to step **4**
**6:** if server sends `W` or `L` => go to step **4**
**7:** server sends `t` => go to step **6**
3 changes: 1 addition & 2 deletions src/net/server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,7 @@ void server::loop(const int& millis){
else {
client* client_ = (client*)(ee.data.ptr);
if (ee.events & EPOLLIN) {
std::vector<char> data = client_->receive();
write(0, data.data(), data.size());
client_->receive();
}
if (ee.events & EPOLLOUT) {
client_->sendFromBuffer();
Expand Down
12 changes: 9 additions & 3 deletions src/rts/board.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,19 @@ rts::field* rts::board::closestEmptyField(const field* source) {
return candidate;
}

void rts::board::spawnResource(unsigned int hp) {
randomResourceField(false)->spawnResource(hp);
rts::field* rts::board::spawnResource(unsigned int hp) {
return randomResourceField(false)->spawnResource(hp);
}

void rts::board::spawnResources(unsigned int amount, unsigned int hp) {
std::vector<field*> resFields = resourceFields(false);
for (unsigned int i = 0; i < amount; ++i) {
spawnResource(hp);
if (resFields.empty()) return;
std::uniform_int_distribution<> distrib(0, resFields.size() - 1);
int fid = distrib(gen);
field* f = resFields[fid];
f->spawnResource(hp);
resFields.erase(resFields.begin() + fid);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/rts/board.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ namespace rts {
field* randomResourceField(bool resource);
field* closestEmptyField(const field* source);

void spawnResource(unsigned int hp);
field* spawnResource(unsigned int hp);
void spawnResources(unsigned int amount, unsigned int hp);

unsigned int getXdim() const;
Expand Down
8 changes: 6 additions & 2 deletions src/rts/field.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <cassert>
#include <limits>
#include <algorithm>
#include <stdio.h>

#include <rts/unit.hpp>

Expand All @@ -16,13 +17,16 @@ bool rts::field::hasResource() const {
return (resourceHp > 0);
}

void rts::field::spawnResource(unsigned int hp) {
rts::field* rts::field::spawnResource(unsigned int hp) {
assert(!hasResource());
resourceHp = (int)hp;
printf("spawned resource at: %d, %d\n", x, y);
return this;
}

void rts::field::mine(int dmg) {
rts::field* rts::field::mine(int dmg) {
resourceHp -= dmg;
return this;
}

int rts::field::getHp() const {
Expand Down
8 changes: 6 additions & 2 deletions src/rts/field.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,12 @@ namespace rts {

bool empty() const;
bool hasResource() const;
void spawnResource(unsigned int hp);
void mine(int dmg);

// @returns this field
rts::field* spawnResource(unsigned int hp);

// @returns this field
rts::field* mine(int dmg);

int getHp() const;

Expand Down
52 changes: 43 additions & 9 deletions src/rts/game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ rts::game::game(const char *port, const char* configFile) : _server(port) {
}
}

// ========== MESSAGES =========

std::vector<char> rts::game::configMessage() const {
std::vector<char> buff = {'c'};
message::appendNumberWDelim(buff, millis, ' ');
Expand Down Expand Up @@ -72,7 +74,6 @@ std::vector<char> rts::game::boardStateMessage() const {
buff.push_back(';');
}
buff.push_back('\n');

// resources
buff.push_back('r');
std::vector<const rts::field*> resources = _board.constResourceFields(true);
Expand All @@ -86,19 +87,41 @@ std::vector<char> rts::game::boardStateMessage() const {
return buff;
}

std::vector<char> rts::game::newPlayerMessage(const player* p) const{
std::vector<char> buff = {'j'};

message::appendStringWDelim(buff, p->getName(), '\n'); // player name

return buff;
}

std::vector<char> rts::game::playerLeftMessage(const player* p) const{
std::vector<char> buff = {'l'};

message::appendStringWDelim(buff, p->getName(), '\n'); // player name

return buff;
}

std::vector<char> rts::game::newResourceMessage(const field* f) const{
std::vector<char> buff = {'f'};
message::appendNumberWDelim(buff, f->x, ' ');
message::appendNumberWDelim(buff, f->y, ' ');
message::appendNumberWDelim(buff, f->getHp(), '\n');
return buff;
}

// ========== GAME LOGIC ==========

void rts::game::handleNewClient(client* client_) {
player* pl = new player(this, client_);
allPlayers.insert(pl);
pl->getClient()->sendToClient(configMessage());
}

void rts::game::loopLogic(){
// spawn resource
if (rand() % 10 == 0) _board.spawnResource(resourceHp);


// sent updates to clients
sendToPlayers(activePlayers, boardStateMessage());
// spawn resource and inform players
if (rand() % 10 == 0) sendToPlayers(activePlayers, newResourceMessage(_board.spawnResource(resourceHp)));

// allow units to move again
for (player* p : activePlayers) {
Expand All @@ -116,11 +139,14 @@ void rts::game::clearRoom() {
pl->removeAllUnits();
}
activePlayers.clear();
nextUnitId = 0;
_server.loopLogic = [](){};
printf("room cleared\n");
}

void rts::game::startGame() {
_board = board(boardX, boardY); // reset board
printf("game start\n");
_board.spawnResources(startResources, resourceHp);
while(!queuedPlayers.empty() && activePlayers.size() < maxPlayers){
moveQueuedPlayerToRoom();
Expand All @@ -130,9 +156,10 @@ void rts::game::startGame() {

void rts::game::addPlayerToRoom(player* pl) {
assert(activePlayers.size() < maxPlayers);
activePlayers.insert(pl);
sendToPlayers(activePlayers, newPlayerMessage(pl));
pl->newUnit(_board.randomEmptyField(true)); // add first unit for the player to control
pl->getClient()->sendToClient({'g', '\n'}); // joined active group
activePlayers.insert(pl);
pl->getClient()->sendToClient(boardStateMessage());
}

void rts::game::addPlayerToQueue(player* pl) {
Expand All @@ -151,6 +178,7 @@ void rts::game::removePlayerFromRoomOrQueue(player* pl) {
if (activePlayers.find(pl) != activePlayers.end()) {
activePlayers.erase(pl);
pl->removeAllUnits();
sendToPlayers(activePlayers, playerLeftMessage(pl));
if (!queuedPlayers.empty()) moveQueuedPlayerToRoom();
if (activePlayers.empty()) clearRoom();
}
Expand All @@ -170,6 +198,10 @@ void rts::game::sendToPlayers(const std::unordered_set<rts::player*>& players, c
}
}

void rts::game::sendToPlayers(const std::vector<char>& message) const {
sendToPlayers(activePlayers, message);
}

void rts::game::run() {
_server.loop(millis);
}
Expand Down Expand Up @@ -216,6 +248,8 @@ void rts::game::tryWin(player* pl){
}
}

// ========== GETTERS ==========

unsigned int rts::game::getUnitDamage() const {return unitDamage;}
unsigned int rts::game::getUnitHp() const {return unitHp;}

Expand Down
5 changes: 5 additions & 0 deletions src/rts/game.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ namespace rts {

std::vector<char> configMessage() const;
std::vector<char> boardStateMessage() const;
std::vector<char> newPlayerMessage(const player* p) const;
std::vector<char> playerLeftMessage(const player* p) const;
std::vector<char> newResourceMessage(const field* f) const;

void handleNewClient(client* client_);
void loopLogic();
Expand All @@ -48,6 +51,8 @@ namespace rts {
board _board;

game(const char *port, const char* configFile);

void sendToPlayers(const std::vector<char>& message) const;

void run();

Expand Down
14 changes: 12 additions & 2 deletions src/rts/player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <rts/game.hpp>
#include <rts/unit.hpp>
#include <msg/state.hpp>
#include <msg/stringBuffer.hpp>

std::unordered_map<std::string, rts::player*> rts::player::playersByName;

Expand All @@ -29,7 +30,7 @@ void rts::player::handleNewMessage(const message::base* msg) {
}
else if (const message::state* cmsg = dynamic_cast<const message::state*>(msg)) {
if (cmsg->act == message::state::action::disconnect) {
_game->deletePlayer(this);
_game->deletePlayer(this);
}
else if (cmsg->act == message::state::action::joinRequest) {
_game->tryJoin(this);
Expand Down Expand Up @@ -96,7 +97,16 @@ void rts::player::removeAllUnits(){
}

void rts::player::newUnit(field* field_){
units.insert(new unit(this, field_, _game->getNextUnitId()));
unit* u = new unit(this, field_, _game->getNextUnitId());
units.insert(u);

std::vector<char> buff = {'u'};
message::appendStringWDelim(buff, _name, ' ');
message::appendNumberWDelim(buff, u->id, ' ');
message::appendNumberWDelim(buff, u->f->x, ' ');
message::appendNumberWDelim(buff, u->f->y, '\n');
_game->sendToPlayers(buff);

_game->tryWin(this);
}

Expand Down
27 changes: 24 additions & 3 deletions src/rts/unit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@
#include <rts/field.hpp>
#include <rts/player.hpp>
#include <rts/game.hpp>
#include <msg/stringBuffer.hpp>

rts::unit::unit(player* owner_, field* field_, unsigned int id_) :
owner(owner_),
f(field_), id(id_),
hp(owner_->getGame()->getUnitHp())
id(id_),
hp(owner_->getGame()->getUnitHp()),
f(field_),
owner(owner_)
{
printf("%s got new unit\n", owner->getName().c_str());
assert(f->empty());
Expand All @@ -19,6 +21,11 @@ rts::unit::unit(player* owner_, field* field_, unsigned int id_) :

void rts::unit::mine(){
if (!movedThisRound && f->hasResource()) {

std::vector<char> buff = {'d'};
message::appendNumberWDelim(buff, id, '\n');
owner->getGame()->sendToPlayers(buff);

f->mine(owner->getGame()->getUnitDamage());
if (f->getHp() <= 0) {
field* nf = owner->getGame()->_board.closestEmptyField(f);
Expand All @@ -29,6 +36,14 @@ void rts::unit::mine(){
}
void rts::unit::move(field* field_){
if (!movedThisRound && f->distance(*field_) <= 1 && field_->empty()) {

std::vector<char> buff = {'m'};
message::appendNumberWDelim(buff, id, ' ');
message::appendNumberWDelim(buff, field_->x, ' ');
message::appendNumberWDelim(buff, field_->y, '\n');
owner->getGame()->sendToPlayers(buff);


this->f->_unit = nullptr;
this->f = field_;
field_->_unit = this;
Expand All @@ -38,6 +53,12 @@ void rts::unit::move(field* field_){
void rts::unit::attack(unit* target){
if (target == nullptr) return;
if (!movedThisRound && f->distance(*(target->f)) <= 1) {

std::vector<char> buff = {'a'};
message::appendNumberWDelim(buff, id, ' ');
message::appendNumberWDelim(buff, target->id, '\n');
owner->getGame()->sendToPlayers(buff);

target->recvDamage(owner->getGame()->getUnitDamage());
movedThisRound = true;
}
Expand Down
6 changes: 3 additions & 3 deletions src/rts/unit.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ namespace rts {

class unit {
public:
bool movedThisRound = false;
player* const owner;
field* f;
const unsigned int id;
unsigned int hp;
field* f;
player* const owner;
bool movedThisRound = false;

unit(player* owner_, field* field_, unsigned int id_);

Expand Down

0 comments on commit 0c3aeef

Please sign in to comment.