R-Type
Distributed multiplayer game engine in C++
Loading...
Searching...
No Matches
ConnectionMessages.hpp
Go to the documentation of this file.
1/*
2** EPITECH PROJECT, 2025
3** Created by mael on 08/12/2025.
4** File description:
5** ConnectionMessages.hpp
6*/
7
8#pragma once
9
10#include <cstdint>
11#include <string>
12#include <vector>
13
21
22 // ============================================================================
23 // HANDSHAKE
24 // ============================================================================
25
27 std::string clientVersion;
28 std::string playerName;
29 std::string username; // For authentication
30 std::string password; // For authentication
31 uint64_t timestamp;
32 };
33
35 std::string username;
36 std::string password;
37 };
38
40 bool success;
41 std::string message;
42 };
43
46 std::string sessionId;
47 std::string serverId;
48 std::string message;
49 std::string serverVersion;
50 };
51
52 inline std::vector<uint8_t> createHandshakeRequest(const HandshakeRequestData &data) {
53 // Format: [4:version_len][version][4:name_len][name][4:username_len][username][4:password_len][password][8:timestamp]
54 std::vector<uint8_t> packet;
55
56 // Client version
57 uint32_t versionLen = static_cast<uint32_t>(data.clientVersion.size());
58 packet.push_back(static_cast<uint8_t>(versionLen & 0xFF));
59 packet.push_back(static_cast<uint8_t>((versionLen >> 8) & 0xFF));
60 packet.push_back(static_cast<uint8_t>((versionLen >> 16) & 0xFF));
61 packet.push_back(static_cast<uint8_t>((versionLen >> 24) & 0xFF));
62 packet.insert(packet.end(), data.clientVersion.begin(), data.clientVersion.end());
63
64 // Player name
65 uint32_t nameLen = static_cast<uint32_t>(data.playerName.size());
66 packet.push_back(static_cast<uint8_t>(nameLen & 0xFF));
67 packet.push_back(static_cast<uint8_t>((nameLen >> 8) & 0xFF));
68 packet.push_back(static_cast<uint8_t>((nameLen >> 16) & 0xFF));
69 packet.push_back(static_cast<uint8_t>((nameLen >> 24) & 0xFF));
70 packet.insert(packet.end(), data.playerName.begin(), data.playerName.end());
71
72 // Username
73 uint32_t usernameLen = static_cast<uint32_t>(data.username.size());
74 packet.push_back(static_cast<uint8_t>(usernameLen & 0xFF));
75 packet.push_back(static_cast<uint8_t>((usernameLen >> 8) & 0xFF));
76 packet.push_back(static_cast<uint8_t>((usernameLen >> 16) & 0xFF));
77 packet.push_back(static_cast<uint8_t>((usernameLen >> 24) & 0xFF));
78 packet.insert(packet.end(), data.username.begin(), data.username.end());
79
80 // Password
81 uint32_t passwordLen = static_cast<uint32_t>(data.password.size());
82 packet.push_back(static_cast<uint8_t>(passwordLen & 0xFF));
83 packet.push_back(static_cast<uint8_t>((passwordLen >> 8) & 0xFF));
84 packet.push_back(static_cast<uint8_t>((passwordLen >> 16) & 0xFF));
85 packet.push_back(static_cast<uint8_t>((passwordLen >> 24) & 0xFF));
86 packet.insert(packet.end(), data.password.begin(), data.password.end());
87
88 // Timestamp
89 for (int i = 0; i < 8; ++i) {
90 packet.push_back(static_cast<uint8_t>((data.timestamp >> (i * 8)) & 0xFF));
91 }
92
93 return packet;
94 }
95
96 inline HandshakeRequestData parseHandshakeRequest(const std::vector<uint8_t> &data) {
98 size_t offset = 0;
99
100 if (data.size() < 4)
101 return result;
102
103 // Read version
104 uint32_t versionLen =
105 data[offset] | (data[offset + 1] << 8) | (data[offset + 2] << 16) | (data[offset + 3] << 24);
106 offset += 4;
107 if (data.size() < offset + versionLen)
108 return result;
109 result.clientVersion = std::string(data.begin() + offset, data.begin() + offset + versionLen);
110 offset += versionLen;
111
112 // Read name
113 if (data.size() < offset + 4)
114 return result;
115 uint32_t nameLen =
116 data[offset] | (data[offset + 1] << 8) | (data[offset + 2] << 16) | (data[offset + 3] << 24);
117 offset += 4;
118 if (data.size() < offset + nameLen)
119 return result;
120 result.playerName = std::string(data.begin() + offset, data.begin() + offset + nameLen);
121 offset += nameLen;
122
123 // Read username
124 if (data.size() < offset + 4)
125 return result;
126 uint32_t usernameLen =
127 data[offset] | (data[offset + 1] << 8) | (data[offset + 2] << 16) | (data[offset + 3] << 24);
128 offset += 4;
129 if (data.size() < offset + usernameLen)
130 return result;
131 result.username = std::string(data.begin() + offset, data.begin() + offset + usernameLen);
132 offset += usernameLen;
133
134 // Read password
135 if (data.size() < offset + 4)
136 return result;
137 uint32_t passwordLen =
138 data[offset] | (data[offset + 1] << 8) | (data[offset + 2] << 16) | (data[offset + 3] << 24);
139 offset += 4;
140 if (data.size() < offset + passwordLen)
141 return result;
142 result.password = std::string(data.begin() + offset, data.begin() + offset + passwordLen);
143 offset += passwordLen;
144
145 // Read timestamp
146 if (data.size() < offset + 8)
147 return result;
148 result.timestamp = 0;
149 for (int i = 0; i < 8; ++i) {
150 result.timestamp |= static_cast<uint64_t>(data[offset + i]) << (i * 8);
151 }
152
153 return result;
154 }
155
156 // ============================================================================
157 // REGISTER
158 // ============================================================================
159
160 inline std::vector<uint8_t> createRegisterRequest(const RegisterRequestData &data) {
161 // Format: [4:username_len][username][4:password_len][password]
162 std::vector<uint8_t> packet;
163
164 // Username
165 uint32_t usernameLen = static_cast<uint32_t>(data.username.size());
166 packet.push_back(static_cast<uint8_t>(usernameLen & 0xFF));
167 packet.push_back(static_cast<uint8_t>((usernameLen >> 8) & 0xFF));
168 packet.push_back(static_cast<uint8_t>((usernameLen >> 16) & 0xFF));
169 packet.push_back(static_cast<uint8_t>((usernameLen >> 24) & 0xFF));
170 packet.insert(packet.end(), data.username.begin(), data.username.end());
171
172 // Password
173 uint32_t passwordLen = static_cast<uint32_t>(data.password.size());
174 packet.push_back(static_cast<uint8_t>(passwordLen & 0xFF));
175 packet.push_back(static_cast<uint8_t>((passwordLen >> 8) & 0xFF));
176 packet.push_back(static_cast<uint8_t>((passwordLen >> 16) & 0xFF));
177 packet.push_back(static_cast<uint8_t>((passwordLen >> 24) & 0xFF));
178 packet.insert(packet.end(), data.password.begin(), data.password.end());
179
180 return packet;
181 }
182
183 inline RegisterRequestData parseRegisterRequest(const std::vector<uint8_t> &data) {
184 RegisterRequestData result;
185 size_t offset = 0;
186
187 if (data.size() < 4)
188 return result;
189
190 // Read username
191 uint32_t usernameLen =
192 data[offset] | (data[offset + 1] << 8) | (data[offset + 2] << 16) | (data[offset + 3] << 24);
193 offset += 4;
194 if (data.size() < offset + usernameLen)
195 return result;
196 result.username = std::string(data.begin() + offset, data.begin() + offset + usernameLen);
197 offset += usernameLen;
198
199 // Read password
200 if (data.size() < offset + 4)
201 return result;
202 uint32_t passwordLen =
203 data[offset] | (data[offset + 1] << 8) | (data[offset + 2] << 16) | (data[offset + 3] << 24);
204 offset += 4;
205 if (data.size() < offset + passwordLen)
206 return result;
207 result.password = std::string(data.begin() + offset, data.begin() + offset + passwordLen);
208
209 return result;
210 }
211
212 inline std::vector<uint8_t> createRegisterResponse(const RegisterResponseData &data) {
213 std::vector<uint8_t> packet;
214
215 // Success flag
216 packet.push_back(data.success ? 1 : 0);
217
218 // Message
219 uint32_t msgLen = static_cast<uint32_t>(data.message.size());
220 packet.push_back(static_cast<uint8_t>(msgLen & 0xFF));
221 packet.push_back(static_cast<uint8_t>((msgLen >> 8) & 0xFF));
222 packet.push_back(static_cast<uint8_t>((msgLen >> 16) & 0xFF));
223 packet.push_back(static_cast<uint8_t>((msgLen >> 24) & 0xFF));
224 packet.insert(packet.end(), data.message.begin(), data.message.end());
225
226 return packet;
227 }
228
229 inline RegisterResponseData parseRegisterResponse(const std::vector<uint8_t> &data) {
231 size_t offset = 0;
232
233 if (data.size() < 1)
234 return result;
235
236 // Success flag
237 result.success = (data[offset] != 0);
238 offset += 1;
239
240 // Message
241 if (data.size() < offset + 4)
242 return result;
243 uint32_t msgLen =
244 data[offset] | (data[offset + 1] << 8) | (data[offset + 2] << 16) | (data[offset + 3] << 24);
245 offset += 4;
246 if (data.size() < offset + msgLen)
247 return result;
248 result.message = std::string(data.begin() + offset, data.begin() + offset + msgLen);
249
250 return result;
251 }
252
253 inline std::vector<uint8_t> createHandshakeResponse(const HandshakeResponseData &data) {
254 std::vector<uint8_t> packet;
255
256 // Accepted flag
257 packet.push_back(data.accepted ? 1 : 0);
258
259 // Session ID
260 uint32_t sessionLen = static_cast<uint32_t>(data.sessionId.size());
261 packet.push_back(static_cast<uint8_t>(sessionLen & 0xFF));
262 packet.push_back(static_cast<uint8_t>((sessionLen >> 8) & 0xFF));
263 packet.push_back(static_cast<uint8_t>((sessionLen >> 16) & 0xFF));
264 packet.push_back(static_cast<uint8_t>((sessionLen >> 24) & 0xFF));
265 packet.insert(packet.end(), data.sessionId.begin(), data.sessionId.end());
266
267 // Server ID
268 uint32_t serverLen = static_cast<uint32_t>(data.serverId.size());
269 packet.push_back(static_cast<uint8_t>(serverLen & 0xFF));
270 packet.push_back(static_cast<uint8_t>((serverLen >> 8) & 0xFF));
271 packet.push_back(static_cast<uint8_t>((serverLen >> 16) & 0xFF));
272 packet.push_back(static_cast<uint8_t>((serverLen >> 24) & 0xFF));
273 packet.insert(packet.end(), data.serverId.begin(), data.serverId.end());
274
275 // Message
276 uint32_t msgLen = static_cast<uint32_t>(data.message.size());
277 packet.push_back(static_cast<uint8_t>(msgLen & 0xFF));
278 packet.push_back(static_cast<uint8_t>((msgLen >> 8) & 0xFF));
279 packet.push_back(static_cast<uint8_t>((msgLen >> 16) & 0xFF));
280 packet.push_back(static_cast<uint8_t>((msgLen >> 24) & 0xFF));
281 packet.insert(packet.end(), data.message.begin(), data.message.end());
282
283 // Server version
284 uint32_t versionLen = static_cast<uint32_t>(data.serverVersion.size());
285 packet.push_back(static_cast<uint8_t>(versionLen & 0xFF));
286 packet.push_back(static_cast<uint8_t>((versionLen >> 8) & 0xFF));
287 packet.push_back(static_cast<uint8_t>((versionLen >> 16) & 0xFF));
288 packet.push_back(static_cast<uint8_t>((versionLen >> 24) & 0xFF));
289 packet.insert(packet.end(), data.serverVersion.begin(), data.serverVersion.end());
290
291 return packet;
292 }
293
294 // ============================================================================
295 // DISCONNECT
296 // ============================================================================
297
298 enum class DisconnectReason : uint8_t {
299 CLIENT_REQUEST = 0,
300 SERVER_SHUTDOWN = 1,
301 TIMEOUT = 2,
302 KICKED = 3,
303 ERROR = 4
304 };
305
308 std::string message;
309 uint64_t timestamp;
310 };
311
312 inline std::vector<uint8_t> createDisconnect(const DisconnectData &data) {
313 std::vector<uint8_t> packet;
314
315 // Reason
316 packet.push_back(static_cast<uint8_t>(data.reason));
317
318 // Message
319 uint32_t msgLen = static_cast<uint32_t>(data.message.size());
320 packet.push_back(static_cast<uint8_t>(msgLen & 0xFF));
321 packet.push_back(static_cast<uint8_t>((msgLen >> 8) & 0xFF));
322 packet.push_back(static_cast<uint8_t>((msgLen >> 16) & 0xFF));
323 packet.push_back(static_cast<uint8_t>((msgLen >> 24) & 0xFF));
324 packet.insert(packet.end(), data.message.begin(), data.message.end());
325
326 // Timestamp
327 for (int i = 0; i < 8; ++i) {
328 packet.push_back(static_cast<uint8_t>((data.timestamp >> (i * 8)) & 0xFF));
329 }
330
331 return packet;
332 }
333
334 // ============================================================================
335 // KICK
336 // ============================================================================
337
338 struct KickData {
339 std::string reason;
340 uint64_t duration; // 0 = permanent
342 };
343
344 inline std::vector<uint8_t> createKick(const KickData &data) {
345 std::vector<uint8_t> packet;
346
347 // Reason
348 uint32_t reasonLen = static_cast<uint32_t>(data.reason.size());
349 packet.push_back(static_cast<uint8_t>(reasonLen & 0xFF));
350 packet.push_back(static_cast<uint8_t>((reasonLen >> 8) & 0xFF));
351 packet.push_back(static_cast<uint8_t>((reasonLen >> 16) & 0xFF));
352 packet.push_back(static_cast<uint8_t>((reasonLen >> 24) & 0xFF));
353 packet.insert(packet.end(), data.reason.begin(), data.reason.end());
354
355 // Duration
356 for (int i = 0; i < 8; ++i) {
357 packet.push_back(static_cast<uint8_t>((data.duration >> (i * 8)) & 0xFF));
358 }
359
360 // Timestamp
361 for (int i = 0; i < 8; ++i) {
362 packet.push_back(static_cast<uint8_t>((data.timestamp >> (i * 8)) & 0xFF));
363 }
364
365 return packet;
366 }
367
368 // ============================================================================
369 // PING/PONG
370 // ============================================================================
371
372 struct PingData {
373 uint64_t timestamp;
375 };
376
377 inline std::vector<uint8_t> createPing(const PingData &data) {
378 std::vector<uint8_t> packet;
379
380 // Timestamp
381 for (int i = 0; i < 8; ++i) {
382 packet.push_back(static_cast<uint8_t>((data.timestamp >> (i * 8)) & 0xFF));
383 }
384
385 // Sequence number
386 for (int i = 0; i < 4; ++i) {
387 packet.push_back(static_cast<uint8_t>((data.sequenceNumber >> (i * 8)) & 0xFF));
388 }
389
390 return packet;
391 }
392
393} // namespace ConnectionMessages
Helper functions for connection protocol messages.
HandshakeRequestData parseHandshakeRequest(const std::vector< uint8_t > &data)
std::vector< uint8_t > createKick(const KickData &data)
std::vector< uint8_t > createRegisterResponse(const RegisterResponseData &data)
std::vector< uint8_t > createRegisterRequest(const RegisterRequestData &data)
std::vector< uint8_t > createHandshakeResponse(const HandshakeResponseData &data)
std::vector< uint8_t > createDisconnect(const DisconnectData &data)
RegisterResponseData parseRegisterResponse(const std::vector< uint8_t > &data)
RegisterRequestData parseRegisterRequest(const std::vector< uint8_t > &data)
std::vector< uint8_t > createPing(const PingData &data)
std::vector< uint8_t > createHandshakeRequest(const HandshakeRequestData &data)