Skip to content

Commit 7b5a169

Browse files
committed
Add some random networking code
1 parent fdfc6ef commit 7b5a169

File tree

11 files changed

+491
-18
lines changed

11 files changed

+491
-18
lines changed

CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ add_subdirectory ( "src/lib-game" )
3939
add_subdirectory ( "src/lib-app" )
4040
add_subdirectory ( "src/bin" )
4141
add_subdirectory ( "src/demo-ordered-dither" )
42+
add_subdirectory ( "src/server-test" )
43+
add_subdirectory ( "src/client-test" )
4244

4345
if ( NOT ${DISABLE_TESTING} )
4446
add_subdirectory ( "src/tests" )

src/client-test/.clang-format

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
Language: Cpp
2+
IndentWidth: 4
3+
ColumnLimit: '80'
4+
NamespaceIndentation: All
5+
AccessModifierOffset: -4
6+
ConstructorInitializerIndentWidth: 4
7+
ContinuationIndentWidth: 4
8+
AlignAfterOpenBracket: 'AlwaysBreak'
9+
BinPackArguments: 'false'
10+
BinPackParameters: 'false'
11+
PointerAlignment: Left
12+
ReferenceAlignment: Pointer
13+
SortIncludes: CaseSensitive
14+
SortUsingDeclarations: true
15+
SpaceAfterCStyleCast: false
16+
SpaceAfterLogicalNot: false
17+
SpaceAfterTemplateKeyword: false
18+
SpaceBeforeAssignmentOperators: true
19+
SpaceBeforeCaseColon: false
20+
SpaceBeforeCpp11BracedList: true
21+
SpaceBeforeCtorInitializerColon: true
22+
SpaceBeforeInheritanceColon: true
23+
SpaceBeforeRangeBasedForLoopColon: true
24+
SpaceBeforeSquareBrackets: false
25+
SpacesInAngles: Never
26+
AllowShortBlocksOnASingleLine: Empty
27+
AllowShortCaseLabelsOnASingleLine: false
28+
AllowShortFunctionsOnASingleLine: Empty
29+
AllowShortIfStatementsOnASingleLine: WithoutElse
30+
AlwaysBreakAfterReturnType: None
31+
AlwaysBreakBeforeMultilineStrings: true
32+
AlwaysBreakTemplateDeclarations: Yes
33+
# BreakAfterAttributes: Always
34+
BreakBeforeConceptDeclarations: Always
35+
BreakBeforeBinaryOperators: NonAssignment
36+
CompactNamespaces: false
37+
BreakStringLiterals: true
38+
Cpp11BracedListStyle: false
39+
EmptyLineBeforeAccessModifier: Always
40+
FixNamespaceComments: true
41+
IncludeBlocks: Merge
42+
QualifierAlignment: Left # Left - west const, Right - east const
43+
ReflowComments: true
44+
RequiresClausePosition: OwnLine
45+
SeparateDefinitionBlocks: Always
46+
PackConstructorInitializers: NextLine #NextLineOnly is better
47+
BreakConstructorInitializers: BeforeComma
48+
BreakInheritanceList: BeforeComma
49+
BreakBeforeBraces: Custom
50+
BraceWrapping:
51+
AfterClass: true
52+
AfterControlStatement: true
53+
AfterEnum: true
54+
AfterFunction: true
55+
AfterNamespace: true
56+
AfterObjCDeclaration: true
57+
AfterStruct: true
58+
AfterUnion: true
59+
AfterExternBlock: true
60+
BeforeCatch: true
61+
BeforeElse: true
62+
BeforeLambdaBody: true
63+
BeforeWhile: false
64+
IndentBraces: false
65+
SplitEmptyFunction: true
66+
SplitEmptyRecord: true
67+
SplitEmptyNamespace: true
68+
69+
# Unsupported in MSVC 17.5.2
70+
# LanguageStandard: Cpp20
71+
# SpaceBeforeJsonColon: false
72+
# QualifierOrder: ['inline', 'static', 'constexpr', 'volatile', 'const', 'type', ]
73+
# RequiresExpressionIndentation: OuterScope
74+
# NextLineOnly for PackConstructorInitializers
75+
# BreakAfterAttributes: Always

src/client-test/CMakeLists.txt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
cmake_minimum_required ( VERSION 3.26 )
2+
3+
file (
4+
COPY "${CMAKE_BINARY_DIR}/.clang-format"
5+
DESTINATION "${CMAKE_CURRENT_SOURCE_DIR}"
6+
)
7+
8+
project ( client-test )
9+
10+
add_executable ( ${PROJECT_NAME} Main.cpp )
11+
12+
target_link_libraries ( ${PROJECT_NAME} lib-network lib-misc )
13+
14+
autoset_target_compile_options ( ${PROJECT_NAME} FALSE )

src/client-test/Main.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#include <SFML/Network.hpp>
2+
#include <format>
3+
#include <iostream>
4+
5+
import Network;
6+
7+
int main(int, char*[])
8+
{
9+
auto&& client = Client::create("127.0.0.1", 10666);
10+
if (!client)
11+
{
12+
std::println(std::cerr, "{}", client.error());
13+
return 1;
14+
}
15+
16+
return 0;
17+
}

src/lib-network/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,6 @@ glob_modules ( SRCS )
1111

1212
add_library ( ${PROJECT_NAME} ${SRCS} )
1313

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

1616
autoset_target_compile_options ( ${PROJECT_NAME} FALSE )

src/lib-network/src/Client.ixx

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,116 @@
11
module;
22

3+
#pragma warning(push, 0)
4+
#include <SFML/Network.hpp>
5+
#pragma warning(pop)
6+
#include <cassert>
7+
#include <concepts>
8+
#include <expected>
9+
#include <format>
10+
#include <print>
11+
#include <stdexcept>
12+
#include <string>
13+
314
export module Client;
15+
16+
import Message;
17+
import Error;
18+
import Memory;
19+
20+
export class Client
21+
{
22+
public:
23+
Client(const sf::IpAddress& address, unsigned short port)
24+
: remoteAddress(address), remotePort(port)
25+
{
26+
}
27+
28+
public:
29+
static [[nodiscard]] std::expected<Client, ErrorMessage>
30+
create(const sf::IpAddress& address, unsigned short port)
31+
{
32+
try
33+
{
34+
auto&& client = Client(address, port);
35+
if (auto&& result = client.bindToAnyPort(); !result)
36+
return std::unexpected(result.error());
37+
38+
auto&& id = client.registerToServer();
39+
if (!id) return std::unexpected(id.error());
40+
client.myClientId = *id;
41+
42+
return client;
43+
}
44+
catch (std::exception& e)
45+
{
46+
return std::unexpected(e.what());
47+
}
48+
}
49+
50+
private:
51+
ExpectSuccess bindToAnyPort()
52+
{
53+
if (socket->bind(sf::Socket::AnyPort) != sf::Socket::Status::Done)
54+
{
55+
return std::unexpected(
56+
std::format("Cannot bind socket to any port"));
57+
}
58+
59+
myPort = socket->getLocalPort();
60+
std::println("Socket bound to port {}", myPort);
61+
62+
return ReturnFlag::Success;
63+
}
64+
65+
std::expected<PlayerIdType, ErrorMessage> registerToServer()
66+
{
67+
if (auto&& result = sendConnectPacket(); !result)
68+
return std::unexpected(result.error());
69+
70+
auto&& message = getConnectResponse();
71+
if (!message) return std::unexpected(message.error());
72+
return message->playerId;
73+
}
74+
75+
ExpectSuccess sendConnectPacket()
76+
{
77+
auto&& packet = Message { .type = MessageType::Connect }.toPacket();
78+
if (socket->send(packet, remoteAddress, remotePort)
79+
!= sf::Socket::Status::Done)
80+
{
81+
return std::unexpected(std::format(
82+
"Could not send message to {}:{}",
83+
remoteAddress.toString(),
84+
remotePort));
85+
}
86+
}
87+
88+
std::expected<Message, ErrorMessage> getConnectResponse()
89+
{
90+
auto&& packet = sf::Packet();
91+
if (socket->receive(packet, remoteAddress, remotePort)
92+
!= sf::Socket::Status::Done)
93+
{
94+
return std::unexpected(
95+
std::format("Got no response from remote server"));
96+
}
97+
98+
auto&& message = Message::parseMessage(packet);
99+
if (message.type != MessageType::ConnectConfirmed)
100+
{
101+
return std::unexpected(std::format(
102+
"Expected ConnectConfirmed from the server, got {}",
103+
static_cast<std::underlying_type_t<MessageType>>(
104+
message.type)));
105+
}
106+
107+
return message;
108+
}
109+
110+
private:
111+
sf::IpAddress remoteAddress;
112+
unsigned short remotePort;
113+
mem::Box<sf::UdpSocket> socket;
114+
unsigned short myPort;
115+
PlayerIdType myClientId;
116+
};

src/lib-network/src/Message.ixx

Lines changed: 55 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,57 @@ export
1010
using PlayerIdType = std::uint8_t;
1111
using ChecksumType = std::uint64_t;
1212

13+
enum class [[nodiscard]] ClientMessageType : uint8_t
14+
{
15+
ConnectionRequest,
16+
PeerSettingsUpdate,
17+
GameSettingsUpdate,
18+
CommitLobby,
19+
MapLoaded,
20+
ReportInput,
21+
Disconnect
22+
};
23+
24+
struct [[nodiscard]] ClientMessage
25+
{
26+
};
27+
28+
enum class [[nodiscard]] ServerMessageType : uint8_t
29+
{
30+
ConnectionAccepted,
31+
ConnectionRefused,
32+
LobbyCommited,
33+
StartGame,
34+
UpdateInput
35+
};
36+
37+
struct [[nodiscard]] ServerMessage
38+
{
39+
};
40+
1341
enum class MessageType : std::uint8_t
1442
{
1543
Connect,
44+
ConnectConfirmed,
45+
ConnectionRefused,
46+
PeerSettingsUpdate,
47+
GameSettingsUpdate,
1648
Update,
1749
Disconnect
1850
};
1951

20-
struct Message
52+
struct [[nodiscard]] Message
2153
{
22-
PlayerIdType playerId;
2354
MessageType type;
55+
PlayerIdType playerId;
2456
std::string playerName;
2557
std::string inputJson;
2658
std::size_t tick;
2759
ChecksumType checksum;
60+
61+
static Message parseMessage(sf::Packet& packet);
62+
63+
[[nodiscard]] sf::Packet toPacket() const;
2864
};
2965

3066
sf::Packet& operator<<(sf::Packet& packet, const Message& message)
@@ -44,4 +80,20 @@ export
4480
message.type = static_cast<MessageType>(type);
4581
return packet;
4682
}
47-
}
83+
}
84+
85+
module :private;
86+
87+
Message Message::parseMessage(sf::Packet& packet)
88+
{
89+
auto&& result = Message();
90+
packet >> result;
91+
return result;
92+
}
93+
94+
sf::Packet Message::toPacket() const
95+
{
96+
auto&& packet = sf::Packet();
97+
packet << *this;
98+
return packet;
99+
}

0 commit comments

Comments
 (0)