Presentation
Welcome to the documentation of my network code for my turn-based game.
This project was carried out as part of an exercise for SAE Institute Geneva during the Computer Network module of the Game Programming course.
I've created this little API based on TCP sockets from the SFML-Network library.
My API provides two network managers, one for the client and one for the server (ClientNetworkManager & ServerNetworkManager), inheriting interfaces so they can be easily mocked.
The same principle applies to the HttpManager class, which enables HTTP GET and POST requests.
This page contains examples and explanations of the various API classes. Feel free to have a look before downloading my project.
Installation
To start using my network code, I encourage you to build my game project to see how it's implemented and used in the game code, and also to see the CMake environment variables: Here the steps to build my project:
Requierements :
- Git installed
- CMake installed
- Vcpkg installed
- Visual Studio 17 2022 installed
Build steps:
- Git clone my turn-based game repository: https://github.com/Chocolive24/network_turn_based_game.git
- Go to the project root and run this cmake command (or use CMake GUI):
cmake -S . -B <build_directory_name> -DCMAKE_BUILD_TYPE=Release -DPORT="<a port number greater than 1024>"-DHOST_NAME="<an IP adress>"
-DCMAKE_TOOLCHAIN_FILE=<path_to_your_vcpkg_directory>/scripts/buildsystems/vcpkg.cmake -G "Visual Studio 17 2022"
- Then run this command:
cmake --build <build_directory_name>
- Go to the build directory and open the turn_based_game.sln solution file.
If you want to reuse my network classes, just copy the network directoy and link it to your project.
Packet types
The basis of my network code is an enum called PacketType, which differentiates the different packets and allows correct interaction with each of them.
PacketType:
- kNone
- kClientIdentification,
- kJoinLobby,
- KStartGame,
- kNewTurn,
- KCueBallVelocity,
- kEndGame,
- kEloUpdated,
You can create any type of packet you like for your application.
The first piece of data contained in a packet is always a PacketType so that the way in which the rest of the packet's data is read can be adapted.
Here is a small example in pseudo-code for sending a packet:
sf::Packet my_packet{};
client_network_interface_->SendPacket(my_packet);
PacketType
Definition packet.h:7
And here is a small example in pseudo-code for receiving and decoding a packet:
sf::Packet received_packet;
const auto packet_type = client_network_interface_->ReceivePacket(received_packet);
switch (packet_type) {
std::cerr << "Packet received has no type. \n";
break;
break;
default:
break;
}
These examples don't use the ClientNetworkManager class directly but rather a pointer to a ClientNetworkInterface for more flexibility and to have the ability to mock up the interface (to test your app withotu network for example).
Of course, you can also use the ClientNetworkManager class directly.
ClientPacket
ClientPacket is an object containing data that a client wishes to send to the server and its remote port. This struct must be used in the server side only to be able to know which client has sent a packet.
Types
Here's a collection of useful types and typedefs used by the API.
};
};
using Port = std::uint16_t;
PlayerData is a struct containing the username of a player and its elo.
Definition types.h:14
std::string username
Definition types.h:15
int elo
Definition types.h:16
std::uint16_t Port
Definition types.h:19
ReturnStatus
Definition types.h:6
ClientNetworkManager
ClientNetworkManager is an implementation of the ClientNetworkInterface using a sf::TcpSocket to communicates to the server on the network. Here's a short example of how to use this class:
int main() {
std::cerr << "Could not connect to server.\n";
return EXIT_FAILURE;
}
std::cout << "Connected to the server.\n";
sf::Packet join_lobby_packet;
bool is_running = true;
while(is_running) {
sf::Packet received_packet;
switch (packet_type) {
std::cerr << "Packet received has no type. \n";
break;
std::cout << "Client successfuly joinded a lobby.\n";
break;
break;
is_running = false;
break;
default:
break;
}
}
return EXIT_SUCCESS;
}
ClientNetworkManager is the implementation of the ClientNetworkInterface. It manages the communicatio...
Definition client_network_manager.h:12
PacketType ReceivePacket(sf::Packet &packet) noexcept override
void DisconnectFromServer() noexcept
ReturnStatus ConnectToServer(const sf::IpAddress &remote_address, unsigned short remote_port, bool blocking=true) noexcept
void SendPacket(sf::Packet &packet) noexcept override
ServerNetworkManager
ServerNetworkManager is an implementation of the ServerNetworkInterface using a sf::TcpSocket per client with a sf::SocketSelector and a sf::TcpListener to handle communications between all clients connected to the server. The client's socket are stored in an array of unique_ptr of sf::TcpSocket.
To receive network events from customers, you need to create two functions and give them as callbacks to the ServerNetworkManager. The first callback occurs when a client has sent a packet.
The second callback occurs when a client disconnects from the server.
The PollEvents() method handle the client connections and detects which client send a packet based on its port number.
Here's a short example of how to use this class:
#include <iostream>
void OnPacketReceived(
ClientPacket* client_packet)
noexcept;
void OnClientDisconnection(
const Port client_port)
noexcept;
int main() {
std::cerr << "Could not listen to port: " << PORT << '\n';
return EXIT_FAILURE;
}
std::cout << "Server is listening to port: " << PORT << '\n';
OnPacketReceived(client_packet);
}
);
server_network_manager.RegisterClientDisconnectionCallback(
[](
const Port client_port) {
OnClientDisconnection(client_port);
}
);
while (true){
server_network_manager.PollEvents();
}
return EXIT_SUCCES;
}
void OnPacketReceived(
ClientPacket* client_packet)
noexcept {
client_packet->
data >> packet_type;
switch (packet_type) {
std::cerr << "Packet received has no type. \n";
break;
server_network_manager.SendPacket(client_packet->
data, client_packet->
client_port)
break;
default:
break;
}
}
void OnClientDisconnection(
const Port client_port)
noexcept {
std::cout << "Client on port: " << client_port << " has disconnected from server.\n";
}
void RegisterPacketReceivedCallback(const std::function< void(ClientPacket *client_packet)> &callback)
Definition server_network_interface.h:33
ServerNetworkManager is an implementation of the NetworkInterface which manages network communication...
Definition server_network_manager.h:16
ClientPacket is an object containing data that a client wishes to send to the server and its remote p...
Definition packet.h:24
sf::Packet data
Definition packet.h:25
Port client_port
Definition packet.h:26
HttpManager
HttpManager is an implementation of the HttpInterface which enable to send Http GET and POST requests with a string that can be a json body using a sf::Http object. Here's a short example of how to use this class:
#include <iostream>
int main() {
const std::string uri = "/hello";
const std::string response = http_manager.Get(uri);
if (response.empty()){
std::cerr << "Could not Get an answer.\n";
}
else {
std::cout << response << '\n';
}
std::string uri = "/hello/message_place";
const std::string message_body = "My message";
http_manager.Post(uri, message_body);
return EXIT_SUCCES;
}
HttpManager is an implementation of the HttpInterface which enable to send Http GET and POST requests...
Definition http_manager.h:9
void RegisterHostAndPort(std::string_view host, Port port) noexcept override
Lobby
The Lobby class provides a simple, naive way of differentiating between the different clients connected to the server.
It uses a struct called ClientData containing a client's username and port number to simplify packet communications between two players in a game.
The class provides three methods:
- IsComplete() Returns true if the lobby is complete.
- AddClient(const ClientData& client_data) Adds a client to the lobby via the ClientData type.
- Clear() Removes all clients from the lobby. The lobby is now ready to be reused.