Skip to content

Commit

Permalink
Some extra random indev networking code
Browse files Browse the repository at this point in the history
  • Loading branch information
nerudaj committed Feb 18, 2024
1 parent 7b5a169 commit 0abc13d
Show file tree
Hide file tree
Showing 10 changed files with 269 additions and 141 deletions.
3 changes: 2 additions & 1 deletion src/client-test/Main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import Network;

int main(int, char*[])
{
auto&& client = Client::create("127.0.0.1", 10666);
auto&& client = Client::create(
"127.0.0.1", 10666, [](auto, auto) {}, [](auto, auto) {});
if (!client)
{
std::println(std::cerr, "{}", client.error());
Expand Down
125 changes: 109 additions & 16 deletions src/lib-network/src/Client.ixx
Original file line number Diff line number Diff line change
Expand Up @@ -7,31 +7,57 @@ module;
#include <concepts>
#include <expected>
#include <format>
#include <functional>
#include <print>
#include <stdexcept>
#include <string>

export module Client;

import Message;
import ClientMessage;
import ServerMessage;
import Error;
import Memory;

export class Client
export struct PlayerConfig
{
std::string name;
};

export using UpdatePlayerConfigCallback =
std::function<void(PlayerIdType, PlayerConfig)>;
export using UpdatePlayerInputCallback =
std::function<void(PlayerIdType, std::string)>;

export class [[nodiscard]] Client
{
public:
Client(const sf::IpAddress& address, unsigned short port)
: remoteAddress(address), remotePort(port)
Client(
const sf::IpAddress& address,
unsigned short port,
UpdatePlayerConfigCallback updatePlayerConfigCallback,
UpdatePlayerInputCallback updatePlayerInputCallback)
: remoteAddress(address)
, remotePort(port)
, updatePlayerConfigCallback(updatePlayerConfigCallback)
, updatePlayerInputCallback(updatePlayerInputCallback)
{
}

public:
static [[nodiscard]] std::expected<Client, ErrorMessage>
create(const sf::IpAddress& address, unsigned short port)
static [[nodiscard]] std::expected<Client, ErrorMessage> create(
const sf::IpAddress& address,
unsigned short port,
UpdatePlayerConfigCallback updatePlayerConfigCallback,
UpdatePlayerInputCallback updatePlayerInputCallback)
{
try
{
auto&& client = Client(address, port);
auto&& client = Client(
address,
port,
updatePlayerConfigCallback,
updatePlayerInputCallback);
if (auto&& result = client.bindToAnyPort(); !result)
return std::unexpected(result.error());

Expand All @@ -47,6 +73,43 @@ public:
}
}

void readIncomingPackets()
{
sf::Packet packet;
sf::IpAddress address;
unsigned short port;

while (socket->receive(packet, address, port)
== sf::Socket::Status::Done)
{
auto&& result =
handleIncomingMessage(ServerMessage::fromPacket(packet));
}
}

void updatePlayerName(const std::string& newName)
{ // TODO: this
}

ExpectSuccess sendMapReadySignal()
{
auto&& packet = ClientMessage { .type = ClientMessageType::MapLoaded,
.clientId = myClientId }
.toPacket();
if (socket->send(packet, remoteAddress, remotePort)
!= sf::Socket::Status::Done)
{
return std::unexpected(
std::format("Could not send MapLoaded message to server"));
}

return ReturnFlag::Success;
}

void sendInputUpdate(const std::string& json)
{ // TODO: this
}

private:
ExpectSuccess bindToAnyPort()
{
Expand All @@ -69,12 +132,14 @@ private:

auto&& message = getConnectResponse();
if (!message) return std::unexpected(message.error());
return message->playerId;
return message->clientId;
}

ExpectSuccess sendConnectPacket()
{
auto&& packet = Message { .type = MessageType::Connect }.toPacket();
auto&& packet =
ClientMessage { .type = ClientMessageType::ConnectionRequest }
.toPacket();
if (socket->send(packet, remoteAddress, remotePort)
!= sf::Socket::Status::Done)
{
Expand All @@ -83,34 +148,62 @@ private:
remoteAddress.toString(),
remotePort));
}

return ReturnFlag::Success;
}

std::expected<Message, ErrorMessage> getConnectResponse()
std::expected<ServerMessage, ErrorMessage> getConnectResponse()
{
auto&& packet = sf::Packet();
if (socket->receive(packet, remoteAddress, remotePort)
!= sf::Socket::Status::Done)
sf::Packet packet;
sf::IpAddress address;
unsigned short port;

if (socket->receive(packet, address, port) != sf::Socket::Status::Done)
{
return std::unexpected(
std::format("Got no response from remote server"));
}

auto&& message = Message::parseMessage(packet);
if (message.type != MessageType::ConnectConfirmed)
auto&& message = ServerMessage::fromPacket(packet);
if (message.type != ServerMessageType::ConnectionAccepted)
{
return std::unexpected(std::format(
"Expected ConnectConfirmed from the server, got {}",
static_cast<std::underlying_type_t<MessageType>>(
static_cast<std::underlying_type_t<ServerMessageType>>(
message.type)));
}

return message;
}

ExpectSuccess handleIncomingMessage(const ServerMessage& message)
{
switch (message.type)
{
using enum ServerMessageType;

case ConnectionAccepted:
case ConnectionRefused:
case LobbyCommited:
case StartGame:
case UpdateInput:
break;
default:
return std::unexpected(std::format(
"Got invalid message code {}",
static_cast<std::underlying_type_t<ServerMessageType>>(
message.type)));
}

return ReturnFlag::Success;
}

private:
sf::IpAddress remoteAddress;
unsigned short remotePort;
mem::Box<sf::UdpSocket> socket;
unsigned short myPort;
PlayerIdType myClientId;
UpdatePlayerConfigCallback updatePlayerConfigCallback;
UpdatePlayerInputCallback updatePlayerInputCallback;
};
40 changes: 40 additions & 0 deletions src/lib-network/src/ClientMessage.ixx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
module;

#include <SFML/Network.hpp>
#include <string>

export module ClientMessage;

export import ClientMessageType;
export import NetworkTypes;

export struct [[nodiscard]] ClientMessage
{
ClientMessageType type;
PlayerIdType clientId;
std::string clientName;
std::string jsonData; // either map configuration JSON or input JSON

// tick?

static ClientMessage fromPacket(sf::Packet& packet)
{
std::underlying_type_t<ClientMessageType> messageType;

packet >> messageType;

ClientMessage message;
message.type = static_cast<ClientMessageType>(messageType);
packet >> message.clientId;

return message;
}

[[nodiscard]] sf::Packet toPacket() const
{
sf::Packet packet;
packet << static_cast<std::underlying_type_t<ClientMessageType>>(type);
packet << clientId;
return packet;
}
};
15 changes: 15 additions & 0 deletions src/lib-network/src/ClientMessageType.ixx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
module;

#include <cstdint>

export module ClientMessageType;

export enum class [[nodiscard]] ClientMessageType : uint8_t {
ConnectionRequest,
PeerSettingsUpdate,
GameSettingsUpdate,
CommitLobby,
MapLoaded,
ReportInput,
Disconnect
};
99 changes: 0 additions & 99 deletions src/lib-network/src/Message.ixx

This file was deleted.

3 changes: 1 addition & 2 deletions src/lib-network/src/Network.ixx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
export module Network;

export import Message;
export import ClientData;
export import Client;
export import Server;
export import Server;
8 changes: 8 additions & 0 deletions src/lib-network/src/NetworkTypes.ixx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module;

#include <cstdint>

export module NetworkTypes;

export using PlayerIdType = std::uint8_t;
export using ChecksumType = std::uint64_t;
Loading

0 comments on commit 0abc13d

Please sign in to comment.