1
0
Fork 0
mirror of synced 2025-03-06 20:53:27 +01:00

Further implementation and some documentation

This commit is contained in:
niansa/tuxifan 2022-05-11 11:16:43 +02:00
parent 45afcdee07
commit a76c40d876
6 changed files with 170 additions and 4 deletions

View file

@ -17,6 +17,7 @@ message Error {
OutOfRange = 8;
NotYourTurn = 9;
RoomNotAvailable = 10;
RoomFull = 11;
}
Code code = 2;
}
@ -32,13 +33,15 @@ message Operation {
OK = 2;
SimpleAuth = 3;
_MinAuth = 4;
SettingsSync = 5;
RoomInfoSync = 5;
PlayfieldSync = 6;
RobotUpdate = 7;
YourTurn = 8;
MakeRoom = 9;
JoinRoom = 10;
JoinRandomRoom = 11;
LeaveRoom = 12;
UserInfoSync = 13;
}
Code code = 1;
}
@ -58,11 +61,17 @@ message Settings {
optional uint32 protectCooldown = 5;
optional uint32 healCooldown = 6;
optional uint32 healPerTurn = 7;
optional uint32 maxPlayers = 8;
}
message UserReference {
uint64 clientId = 2;
uint64 userId = 3;
}
message PublicUserInfo {
string name = 1;
UserReference reference = 2;
}
message UserInfo {
PublicUserInfo publicInfo = 1;

27
generic.txt Normal file
View file

@ -0,0 +1,27 @@
Server
void Disconnect() // client closes connection
void Error(Error)
void OK()
SimpleAuth(SimpleAuth) -> UserInfoSync // client wants to authenticate anonymously
RobotUpdate(Robot) -> RobotUpdate // client wants to change robot
void RoomInfoSync(RoomInfo) <- TODO // client wants to change room info
MakeRoom() -> RoomInfoSync // client creates a room
JoinRoom(???) -> RoomInfoSync // client joins specific room
JoinRandomRoom() -> RoomInfoSync // client joins random room
LeaveRoom() -> LeaveRoom // client leaves current room
Client
Disconnect() // server closes connection
Error(Error)
OK()
RobotUpdate(Robot) // this robot has changed
RoomInfoSync(RoomInfo) // your current rooms info has changed
UserInfoSync(UserInfo) // your user info has been changed
PlayfielSync(PlayfieldSync) // playfield has been created
RoomInfoSync(RoomInfo) // room info has changed
YourTurn() -> RobotUpdate // it's your turn
JoinRoom(PublicUserInfo) // player joins your current room
LeaveRoom(UserReference) // player leaves your current room

View file

@ -1,4 +1,5 @@
#include "Connection.hpp"
#include "World.hpp"
#include <optional>
#include <algorithm>
@ -19,6 +20,12 @@ asio::awaitable<Packet> Client::receivePacket() {
case Generic::Operation::SimpleAuth: {
packet.data = std::make_unique<Generic::SimpleAuth>(co_await receiveProtobuf<Generic::SimpleAuth>(30));
} break;
case Generic::Operation::RobotUpdate: {
packet.data = std::make_unique<Generic::Robot>(co_await receiveProtobuf<Generic::Robot>());
} break;
case Generic::Operation::UserInfoSync:
case Generic::Operation::MakeRoom:
case Generic::Operation::JoinRandomRoom:
case Generic::Operation::Disconnect:
case Generic::Operation::OK:
break;
@ -65,14 +72,45 @@ asio::awaitable<void> Client::handlePacket(const Packet& packet) {
//TODO...
// Set username
userInfo.mutable_publicinfo()->set_name(std::move(authData.username()));
// Set temporary user and client id
auto userRef = userInfo.mutable_publicinfo()->mutable_reference();
userRef->set_userid(global.getTemporaryId());
userRef->set_clientid(global.getTemporaryId());
// Mark as authed
authed = true;
// Send OK
co_await sendOK();
// Send user info
Packet userInfoSync;
userInfoSync.op.set_code(Generic::Operation::UserInfoSync);
userInfoSync.data = std::make_unique<Generic::UserInfo>(userInfo);
} break;
case Generic::Operation::MakeRoom: {
// Create room
auto room = std::make_shared<World::Room>(global);
global.rooms.push_back(room);
co_await room->addClient(shared_from_this());
} break;
case Generic::Operation::JoinRandomRoom: {
// Get random room
auto room = global.getRandomRoom();
// Check that room was found
if (!room) {
throw Error("No available room could be found", Generic::Error::RoomNotAvailable);
}
// Add client to it
co_await room->addClient(shared_from_this());
} break;
case Generic::Operation::LeaveRoom: {
// Check that client is in any room
if (!currentRoom) {
throw Error("You are not in any room", Generic::Error::IllegalOperation);
}
// Remove client from room
co_await currentRoom->removeClient(shared_from_this());
} break;
default: {}
}
co_return;
// Send OK
co_await sendOK();
}
asio::awaitable<void> Client::connect() {
@ -111,6 +149,16 @@ asio::awaitable<void> Client::connect() {
socket.close(ec);
}
std::shared_ptr<World::Room> Global::getRandomRoom() const {
//TODO: Real rng
for (const auto& room : rooms) {
if (room->isOpen()) {
return room;
}
}
return nullptr;
}
asio::awaitable<void> Server::listen(int port) {
try {
// Create acceptor

View file

@ -56,6 +56,8 @@ class Client : public std::enable_shared_from_this<Client> {
bool good = true;
public:
World::Room *currentRoom = nullptr;
Client(asio::io_context& ioc, Global& global) : socket(ioc), global(global) {}
asio::awaitable<Packet> receivePacket();
@ -109,6 +111,13 @@ public:
struct Global {
std::vector<std::shared_ptr<Client>> clients;
std::vector<std::shared_ptr<World::Room>> rooms;
uint64_t highestTemporaryId = 0;
std::shared_ptr<World::Room> getRandomRoom() const;
uint64_t getTemporaryId() {
return ++highestTemporaryId;
}
};

View file

@ -29,6 +29,9 @@ void fillSettings(Generic::Settings& settings) {
if (!settings.has_healperturn()) {
settings.set_healperturn(2);
}
if (!settings.has_maxplayers()) {
settings.set_maxplayers(4);
}
}
boost::asio::awaitable<void> Playfield::reset() {
@ -138,4 +141,56 @@ Generic::RoomInfo Room::getFullRoomInfo() const {
}
return fres;
}
boost::asio::awaitable<void> Room::addClient(const std::shared_ptr<Connection::Client>& client) {
// Check that room is not full
if (isFull()) {
throw Connection::Error("Room is full", Generic::Error::RoomFull);
}
// Check that room has no game running
if (isRunning()) {
throw Connection::Error("Room is in game", Generic::Error::RoomNotAvailable);
}
// Broadcast join
Connection::Packet packet;
packet.op.set_code(Generic::Operation::JoinRoom);
packet.data = std::make_unique<Generic::PublicUserInfo>(client->getUserInfo().publicinfo());
for (auto& client : clients) {
co_await client->sendPacket(packet);
}
// Add client
clients.push_back(client);
client->currentRoom = this;
// Send room info to client
packet.op.set_code(Generic::Operation::RoomInfoSync);
packet.data = std::make_unique<Generic::RoomInfo>(getFullRoomInfo());
co_await client->sendPacket(packet);
}
boost::asio::awaitable<void> Room::removeClient(const std::shared_ptr<Connection::Client>& client) {
// Broadcast leave
Connection::Packet packet;
packet.op.set_code(Generic::Operation::LeaveRoom);
packet.data = std::make_unique<Generic::UserReference>(client->getUserInfo().publicinfo().reference());
for (auto& client : clients) {
co_await client->sendPacket(packet);
}
// Remove client from list
clients.erase(std::find(clients.begin(), clients.end(), client));
client->currentRoom = nullptr;
// Remove room if now empty
if (clients.empty()) {
removeRoom();
}
}
void Room::removeRoom() {
global.rooms.erase(std::find_if(global.rooms.begin(), global.rooms.end(), [this] (auto o) {return o.get() == this;}));
}
boost::asio::awaitable<void> Room::removeAllClients() {
for (auto& client : clients) {
co_await removeClient(client);
}
}
}

View file

@ -11,6 +11,7 @@
namespace Connection {
class Client;
class Global;
}
namespace World {
@ -92,15 +93,32 @@ public:
};
struct Room {
Connection::Global &global;
Generic::RoomInfo info;
std::vector<std::shared_ptr<Connection::Client>> clients;
std::unique_ptr<Playfield> playfield = nullptr;
Room(Connection::Global& global)
: global(global) {}
Generic::RoomInfo getFullRoomInfo() const;
boost::asio::awaitable<void> addClient(const std::shared_ptr<Connection::Client>& client);
boost::asio::awaitable<void> removeClient(const std::shared_ptr<Connection::Client>& client);
void removeRoom();
boost::asio::awaitable<void> removeAllClients();
bool isMasterClient(const Connection::Client *client) const {
return client == clients.front().get();
}
bool isFull() const {
return clients.size() >= info.settings().maxplayers();
}
bool isRunning() const {
return bool(playfield);
}
bool isOpen() const {
return !isFull() && !isRunning();
}
};
}
#endif