Further implementation and some documentation
This commit is contained in:
parent
45afcdee07
commit
a76c40d876
6 changed files with 170 additions and 4 deletions
|
@ -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
27
generic.txt
Normal 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
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue