Skip to content

Commit

Permalink
Add some random networking code
Browse files Browse the repository at this point in the history
  • Loading branch information
nerudaj committed Feb 17, 2024
1 parent fdfc6ef commit 7b5a169
Show file tree
Hide file tree
Showing 11 changed files with 491 additions and 18 deletions.
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ add_subdirectory ( "src/lib-game" )
add_subdirectory ( "src/lib-app" )
add_subdirectory ( "src/bin" )
add_subdirectory ( "src/demo-ordered-dither" )
add_subdirectory ( "src/server-test" )
add_subdirectory ( "src/client-test" )

if ( NOT ${DISABLE_TESTING} )
add_subdirectory ( "src/tests" )
Expand Down
75 changes: 75 additions & 0 deletions src/client-test/.clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
Language: Cpp
IndentWidth: 4
ColumnLimit: '80'
NamespaceIndentation: All
AccessModifierOffset: -4
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
AlignAfterOpenBracket: 'AlwaysBreak'
BinPackArguments: 'false'
BinPackParameters: 'false'
PointerAlignment: Left
ReferenceAlignment: Pointer
SortIncludes: CaseSensitive
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: true
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeRangeBasedForLoopColon: true
SpaceBeforeSquareBrackets: false
SpacesInAngles: Never
AllowShortBlocksOnASingleLine: Empty
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Empty
AllowShortIfStatementsOnASingleLine: WithoutElse
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: true
AlwaysBreakTemplateDeclarations: Yes
# BreakAfterAttributes: Always
BreakBeforeConceptDeclarations: Always
BreakBeforeBinaryOperators: NonAssignment
CompactNamespaces: false
BreakStringLiterals: true
Cpp11BracedListStyle: false
EmptyLineBeforeAccessModifier: Always
FixNamespaceComments: true
IncludeBlocks: Merge
QualifierAlignment: Left # Left - west const, Right - east const
ReflowComments: true
RequiresClausePosition: OwnLine
SeparateDefinitionBlocks: Always
PackConstructorInitializers: NextLine #NextLineOnly is better
BreakConstructorInitializers: BeforeComma
BreakInheritanceList: BeforeComma
BreakBeforeBraces: Custom
BraceWrapping:
AfterClass: true
AfterControlStatement: true
AfterEnum: true
AfterFunction: true
AfterNamespace: true
AfterObjCDeclaration: true
AfterStruct: true
AfterUnion: true
AfterExternBlock: true
BeforeCatch: true
BeforeElse: true
BeforeLambdaBody: true
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true

# Unsupported in MSVC 17.5.2
# LanguageStandard: Cpp20
# SpaceBeforeJsonColon: false
# QualifierOrder: ['inline', 'static', 'constexpr', 'volatile', 'const', 'type', ]
# RequiresExpressionIndentation: OuterScope
# NextLineOnly for PackConstructorInitializers
# BreakAfterAttributes: Always
14 changes: 14 additions & 0 deletions src/client-test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
cmake_minimum_required ( VERSION 3.26 )

file (
COPY "${CMAKE_BINARY_DIR}/.clang-format"
DESTINATION "${CMAKE_CURRENT_SOURCE_DIR}"
)

project ( client-test )

add_executable ( ${PROJECT_NAME} Main.cpp )

target_link_libraries ( ${PROJECT_NAME} lib-network lib-misc )

autoset_target_compile_options ( ${PROJECT_NAME} FALSE )
17 changes: 17 additions & 0 deletions src/client-test/Main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#include <SFML/Network.hpp>
#include <format>
#include <iostream>

import Network;

int main(int, char*[])
{
auto&& client = Client::create("127.0.0.1", 10666);
if (!client)
{
std::println(std::cerr, "{}", client.error());
return 1;
}

return 0;
}
2 changes: 1 addition & 1 deletion src/lib-network/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ glob_modules ( SRCS )

add_library ( ${PROJECT_NAME} ${SRCS} )

target_link_libraries ( ${PROJECT_NAME} Dep_json Dep_sfml Dep_dgm )
target_link_libraries ( ${PROJECT_NAME} Dep_json Dep_sfml Dep_dgm lib-misc lib-memory )

autoset_target_compile_options ( ${PROJECT_NAME} FALSE )
113 changes: 113 additions & 0 deletions src/lib-network/src/Client.ixx
Original file line number Diff line number Diff line change
@@ -1,3 +1,116 @@
module;

#pragma warning(push, 0)
#include <SFML/Network.hpp>
#pragma warning(pop)
#include <cassert>
#include <concepts>
#include <expected>
#include <format>
#include <print>
#include <stdexcept>
#include <string>

export module Client;

import Message;
import Error;
import Memory;

export class Client
{
public:
Client(const sf::IpAddress& address, unsigned short port)
: remoteAddress(address), remotePort(port)
{
}

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

auto&& id = client.registerToServer();
if (!id) return std::unexpected(id.error());
client.myClientId = *id;

return client;
}
catch (std::exception& e)
{
return std::unexpected(e.what());
}
}

private:
ExpectSuccess bindToAnyPort()
{
if (socket->bind(sf::Socket::AnyPort) != sf::Socket::Status::Done)
{
return std::unexpected(
std::format("Cannot bind socket to any port"));
}

myPort = socket->getLocalPort();
std::println("Socket bound to port {}", myPort);

return ReturnFlag::Success;
}

std::expected<PlayerIdType, ErrorMessage> registerToServer()
{
if (auto&& result = sendConnectPacket(); !result)
return std::unexpected(result.error());

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

ExpectSuccess sendConnectPacket()
{
auto&& packet = Message { .type = MessageType::Connect }.toPacket();
if (socket->send(packet, remoteAddress, remotePort)
!= sf::Socket::Status::Done)
{
return std::unexpected(std::format(
"Could not send message to {}:{}",
remoteAddress.toString(),
remotePort));
}
}

std::expected<Message, ErrorMessage> getConnectResponse()
{
auto&& packet = sf::Packet();
if (socket->receive(packet, remoteAddress, remotePort)
!= 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)
{
return std::unexpected(std::format(
"Expected ConnectConfirmed from the server, got {}",
static_cast<std::underlying_type_t<MessageType>>(
message.type)));
}

return message;
}

private:
sf::IpAddress remoteAddress;
unsigned short remotePort;
mem::Box<sf::UdpSocket> socket;
unsigned short myPort;
PlayerIdType myClientId;
};
58 changes: 55 additions & 3 deletions src/lib-network/src/Message.ixx
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,57 @@ export
using PlayerIdType = std::uint8_t;
using ChecksumType = std::uint64_t;

enum class [[nodiscard]] ClientMessageType : uint8_t
{
ConnectionRequest,
PeerSettingsUpdate,
GameSettingsUpdate,
CommitLobby,
MapLoaded,
ReportInput,
Disconnect
};

struct [[nodiscard]] ClientMessage
{
};

enum class [[nodiscard]] ServerMessageType : uint8_t
{
ConnectionAccepted,
ConnectionRefused,
LobbyCommited,
StartGame,
UpdateInput
};

struct [[nodiscard]] ServerMessage
{
};

enum class MessageType : std::uint8_t
{
Connect,
ConnectConfirmed,
ConnectionRefused,
PeerSettingsUpdate,
GameSettingsUpdate,
Update,
Disconnect
};

struct Message
struct [[nodiscard]] Message
{
PlayerIdType playerId;
MessageType type;
PlayerIdType playerId;
std::string playerName;
std::string inputJson;
std::size_t tick;
ChecksumType checksum;

static Message parseMessage(sf::Packet& packet);

[[nodiscard]] sf::Packet toPacket() const;
};

sf::Packet& operator<<(sf::Packet& packet, const Message& message)
Expand All @@ -44,4 +80,20 @@ export
message.type = static_cast<MessageType>(type);
return packet;
}
}
}

module :private;

Message Message::parseMessage(sf::Packet& packet)
{
auto&& result = Message();
packet >> result;
return result;
}

sf::Packet Message::toPacket() const
{
auto&& packet = sf::Packet();
packet << *this;
return packet;
}
Loading

0 comments on commit 7b5a169

Please sign in to comment.