Bomberman Multiplayer
Authoritative multiplayer networking layer for Bomberman.
Loading...
Searching...
No Matches
NetClient.h
Go to the documentation of this file.
1
7#ifndef BOMBERMAN_NET_NETCLIENT_H
8#define BOMBERMAN_NET_NETCLIENT_H
9
10#include <memory>
11#include <optional>
12#include <string>
13#include <string_view>
14
15#include "Net/NetCommon.h"
16
17namespace bomberman::net
18{
19 class ClientDiagnostics;
20
21 // ----- Connection state -----
22
37
39 [[nodiscard]] constexpr bool isFailedState(EConnectState state)
40 {
41 return state >= EConnectState::FailedResolve;
42 }
43
45 constexpr std::string_view connectStateName(EConnectState state)
46 {
47 switch (state)
48 {
49 using enum EConnectState;
50
51 case Disconnected: return "Disconnected";
52 case Connecting: return "Connecting";
53 case Handshaking: return "Handshaking";
54 case Connected: return "Connected";
55 case Disconnecting: return "Disconnecting";
56 case FailedResolve: return "FailedResolve";
57 case FailedConnect: return "FailedConnect";
58 case FailedHandshake: return "FailedHandshake";
59 case FailedProtocol: return "FailedProtocol";
60 case FailedInit: return "FailedInit";
61 default: return "Unknown";
62 }
63 }
64
75 {
76 public:
79 {
80 uint32_t rttMs = 0;
81 uint32_t rttVarianceMs = 0;
82 uint32_t lossPermille = 0;
83 uint32_t lastSnapshotTick = 0;
84 uint32_t lastCorrectionTick = 0;
85 uint32_t snapshotAgeMs = 0;
86 uint32_t gameplaySilenceMs = 0;
87
88 bool predictionActive = false;
89 bool recoveryActive = false;
90 uint32_t correctionCount = 0;
91 uint32_t mismatchCount = 0;
92 uint32_t lastCorrectionDeltaQ = 0;
93 uint32_t maxPendingInputDepth = 0;
94 };
95
97 NetClient();
98
100 ~NetClient() noexcept;
101
103 NetClient(const NetClient&) = delete;
104 NetClient& operator=(const NetClient&) = delete;
105
107 NetClient(NetClient&&) = delete;
108 NetClient& operator=(NetClient&&) = delete;
109
110 // ----- Connection lifecycle -----
111
125 void beginConnect(const std::string& host, uint16_t port, std::string_view playerName);
126
138 bool disconnectBlocking();
139
150 void disconnectAsync();
151
159 void cancelConnect();
160
161 // ----- Runtime API -----
162
170 void pumpNetwork(uint16_t timeoutMs = 0);
171
179 [[nodiscard]]
180 std::optional<uint32_t> sendInput(uint8_t buttons);
181
190 [[nodiscard]]
191 bool sendLobbyReady(bool ready);
192
201 [[nodiscard]]
202 bool sendMatchLoaded(uint32_t matchId);
203
205 void flushOutgoing() const;
206
208 [[nodiscard]]
209 bool isConnected() const { return state_ == EConnectState::Connected; }
210
212 [[nodiscard]]
213 EConnectState connectState() const { return state_; }
214
216 [[nodiscard]]
217 const std::optional<MsgReject::EReason>& lastRejectReason() const { return lastRejectReason_; }
218
220 void setDiagnosticsConfig(bool enabled, bool predictionEnabled, bool remoteSmoothingEnabled);
221
223 [[nodiscard]]
226 [[nodiscard]]
228
230 void updateLiveTransportStats(uint32_t rttMs,
231 uint32_t rttVarianceMs,
232 uint32_t lossPermille,
233 uint32_t lastSnapshotTick,
234 uint32_t lastCorrectionTick,
235 uint32_t snapshotAgeMs,
236 uint32_t gameplaySilenceMs);
237
239 void updateLivePredictionStats(bool predictionActive,
240 bool recoveryActive,
241 uint32_t correctionCount,
242 uint32_t mismatchCount,
243 uint32_t lastCorrectionDeltaQ,
244 uint32_t maxPendingInputDepth);
245
247 [[nodiscard]]
248 const ClientLiveStats& liveStats() const;
249
251 [[nodiscard]]
252 uint8_t playerId() const { return playerId_; }
253
255 static constexpr uint8_t kInvalidPlayerId = 0xFF;
256
258 [[nodiscard]]
259 uint16_t serverTickRate() const { return serverTickRate_; }
260
267 [[nodiscard]]
268 bool tryGetLatestLobbyState(MsgLobbyState& out) const;
269
276 [[nodiscard]]
277 uint32_t lobbySilenceMs() const;
278
286 [[nodiscard]]
288
295 [[nodiscard]]
296 bool tryGetLatestSnapshot(MsgSnapshot& out) const;
297
299 [[nodiscard]]
300 uint32_t lastSnapshotTick() const;
301
308 [[nodiscard]]
309 bool tryGetLatestCorrection(MsgCorrection& out) const;
310
312 [[nodiscard]]
313 uint32_t lastCorrectionTick() const;
314
322 {
323 enum class EType : uint8_t
324 {
327 };
328
329 [[nodiscard]]
330 static GameplayEvent fromBombPlaced(const MsgBombPlaced& bombPlaced)
331 {
332 GameplayEvent event{};
333 event.type = EType::BombPlaced;
334 event.bombPlaced = bombPlaced;
335 return event;
336 }
337
338 [[nodiscard]]
339 static GameplayEvent fromExplosionResolved(const MsgExplosionResolved& explosionResolved)
340 {
341 GameplayEvent event{};
342 event.type = EType::ExplosionResolved;
343 event.explosionResolved = explosionResolved;
344 return event;
345 }
346
347 EType type = EType::BombPlaced;
348 MsgBombPlaced bombPlaced{};
349 MsgExplosionResolved explosionResolved{};
350 };
351
358 [[nodiscard]]
360
368 [[nodiscard]]
369 bool hasBrokenGameplayEventStream() const;
370
377 [[nodiscard]]
378 uint32_t gameplaySilenceMs() const;
379
381 [[nodiscard]]
382 bool tryGetLatestMatchStart(MsgMatchStart& out) const;
383
385 [[nodiscard]]
386 bool hasMatchStarted(uint32_t matchId) const;
387
389 [[nodiscard]]
390 bool isMatchCancelled(uint32_t matchId) const;
391
393 [[nodiscard]]
395
402 [[nodiscard]]
403 bool tryGetMapSeed(uint32_t& outSeed) const;
404
405 private:
406 // ----- Private state -----
407
408 struct Impl;
419 std::unique_ptr<Impl> impl_;
420
421 bool initialized_ = false;
423
424 uint8_t playerId_ = kInvalidPlayerId;
425 uint16_t serverTickRate_ = 0;
426 std::optional<MsgReject::EReason> lastRejectReason_;
427
428 // ----- ENet lifecycle -----
429
430 bool initializeENet();
431 void shutdownENet();
432
433 void finalizeDiagnosticsSession(EConnectState finalState);
434
435 // ----- Disconnect helpers -----
436
438 [[nodiscard]]
439 bool drainGracefulDisconnect();
440
442 void startGracefulDisconnect();
443
445 void destroyTransport();
446
448 void resetLocalInputStream();
449
455 void resetLocalMatchBootstrapState();
456
458 void resetCurrentMatchSession();
459
464 void resetSessionState(bool clearRejectReason = true);
465
471 void failConnection(EConnectState failureState, bool clearRejectReason = true);
472
474 void transitionToDisconnected();
475
477 void resetState();
478
479 // ----- Protocol handlers -----
480
481 void handleWelcome(const uint8_t* payload, std::size_t payloadSize);
482 void handleReject(const uint8_t* payload, std::size_t payloadSize);
483 void handleLevelInfo(const uint8_t* payload, std::size_t payloadSize);
484 void handleLobbyState(const uint8_t* payload, std::size_t payloadSize);
485 void handleMatchStart(const uint8_t* payload, std::size_t payloadSize);
486 void handleMatchCancelled(const uint8_t* payload, std::size_t payloadSize);
487 void handleMatchResult(const uint8_t* payload, std::size_t payloadSize);
488 void handleSnapshot(const uint8_t* payload, std::size_t payloadSize);
489 void handleCorrection(const uint8_t* payload, std::size_t payloadSize);
490 void handleBombPlaced(const uint8_t* payload, std::size_t payloadSize);
491 void handleExplosionResolved(const uint8_t* payload, std::size_t payloadSize);
492 void enqueueGameplayEvent(const GameplayEvent& event);
493
494 // ----- pumpNetwork() helpers -----
495
496 bool checkConnectTimeouts();
497 bool checkDisconnectTimeout();
498
503 bool handleConnectEvent();
504
509 bool handleReceiveEvent(const uint8_t* data, std::size_t dataLength, uint8_t channelID);
510
512 void handleDisconnectEvent();
513 };
514
515} // namespace bomberman::net
516
517#endif // BOMBERMAN_NET_NETCLIENT_H
Shared client/server wire contract for the multiplayer protocol.
Client-side multiplayer diagnostics recorder owned by NetClient.
Definition ClientDiagnostics.h:104
ENet client connection and protocol endpoint.
Definition NetClient.h:75
bool isConnected() const
Returns true when an active session is connected.
Definition NetClient.h:209
bool tryGetMapSeed(uint32_t &outSeed) const
Returns the cached map seed from the current session's latest LevelInfo.
Definition NetClient.Protocol.cpp:161
bool tryGetLatestSnapshot(MsgSnapshot &out) const
Copies the newest cached snapshot for the current session.
Definition NetClient.Protocol.cpp:15
const std::optional< MsgReject::EReason > & lastRejectReason() const
Returns the last explicit server reject reason, if any.
Definition NetClient.h:217
ClientDiagnostics & clientDiagnostics()
Returns the client diagnostics recorder.
Definition NetClient.cpp:57
uint32_t lastSnapshotTick() const
Returns the server tick of the newest cached snapshot, or 0 if none is cached.
Definition NetClient.Protocol.cpp:26
bool sendLobbyReady(bool ready)
Sends an authoritative lobby ready-state request for the local accepted seat.
Definition NetClient.Runtime.cpp:313
void pumpNetwork(uint16_t timeoutMs=0)
Pumps ENet events for this client host.
Definition NetClient.Runtime.cpp:106
~NetClient() noexcept
Disconnects locally if needed and releases ENet resources.
Definition NetClient.cpp:30
bool hasMatchStarted(uint32_t matchId) const
Returns true after the server has explicitly started matchId for this session.
Definition NetClient.Protocol.cpp:134
EConnectState connectState() const
Returns the current connection state.
Definition NetClient.h:213
void updateLiveTransportStats(uint32_t rttMs, uint32_t rttVarianceMs, uint32_t lossPermille, uint32_t lastSnapshotTick, uint32_t lastCorrectionTick, uint32_t snapshotAgeMs, uint32_t gameplaySilenceMs)
Updates the live transport portion of the multiplayer HUD state.
Definition NetClient.cpp:67
bool tryDequeueGameplayEvent(GameplayEvent &out)
Pops the oldest pending reliable gameplay event for the current session.
Definition NetClient.Protocol.cpp:90
bool tryGetLatestLobbyState(MsgLobbyState &out) const
Copies the newest cached lobby state for the current session.
Definition NetClient.Protocol.cpp:57
bool hasBrokenGameplayEventStream() const
Returns true once the reliable gameplay-event stream can no longer be trusted.
Definition NetClient.Protocol.cpp:105
bool isMatchCancelled(uint32_t matchId) const
Returns true after the server has explicitly cancelled matchId back to the lobby.
Definition NetClient.Protocol.cpp:142
uint32_t lastCorrectionTick() const
Returns the server tick of the newest cached correction, or 0 if none is cached.
Definition NetClient.Protocol.cpp:47
uint32_t gameplaySilenceMs() const
Returns milliseconds since the last snapshot or correction.
Definition NetClient.Protocol.cpp:113
void setDiagnosticsConfig(bool enabled, bool predictionEnabled, bool remoteSmoothingEnabled)
Configures client diagnostics behavior for future connect sessions.
Definition NetClient.cpp:45
void beginConnect(const std::string &host, uint16_t port, std::string_view playerName)
Starts a non-blocking connect attempt.
Definition NetClient.Connection.cpp:19
uint8_t playerId() const
Returns the server-assigned player id, or NetClient::kInvalidPlayerId before connect.
Definition NetClient.h:252
bool tryGetLatestMatchResult(MsgMatchResult &out) const
Copies the newest cached authoritative match result for the current session.
Definition NetClient.Protocol.cpp:150
bool tryGetLatestCorrection(MsgCorrection &out) const
Copies the newest cached owner correction for the current session.
Definition NetClient.Protocol.cpp:36
bool tryGetLatestMatchStart(MsgMatchStart &out) const
Copies the newest cached match-start timing edge for the current session.
Definition NetClient.Protocol.cpp:123
uint16_t serverTickRate() const
Returns negotiated server tick rate. Valid only after a successful handshake.
Definition NetClient.h:259
std::optional< uint32_t > sendInput(uint8_t buttons)
Records a button bitmask and queues a batched input packet.
Definition NetClient.Runtime.cpp:250
const ClientLiveStats & liveStats() const
Returns the current live multiplayer HUD state.
Definition NetClient.cpp:105
void disconnectAsync()
Starts a non-blocking graceful disconnect for an active session.
Definition NetClient.Connection.cpp:101
NetClient()
Constructs an idle client with no active transport.
Definition NetClient.cpp:11
static constexpr uint8_t kInvalidPlayerId
Sentinel value indicating no player id has been assigned yet.
Definition NetClient.h:255
bool consumePendingLevelInfo(MsgLevelInfo &out)
Consumes the newest unhandled round-start LevelInfo for the current session.
Definition NetClient.Protocol.cpp:78
bool disconnectBlocking()
Attempts a blocking graceful disconnect, then releases local transport resources.
Definition NetClient.Connection.cpp:130
void updateLivePredictionStats(bool predictionActive, bool recoveryActive, uint32_t correctionCount, uint32_t mismatchCount, uint32_t lastCorrectionDeltaQ, uint32_t maxPendingInputDepth)
Updates the live prediction portion of the multiplayer HUD state.
Definition NetClient.cpp:87
void cancelConnect()
Cancels an in-progress connect or handshake attempt.
Definition NetClient.Connection.cpp:90
void flushOutgoing() const
Flushes any queued outgoing ENet packets immediately.
Definition NetClient.Runtime.cpp:369
uint32_t lobbySilenceMs() const
Returns milliseconds since the last authoritative lobby-state update.
Definition NetClient.Protocol.cpp:68
bool sendMatchLoaded(uint32_t matchId)
Acknowledges that the gameplay scene for matchId has been constructed locally.
Definition NetClient.Runtime.cpp:341
Shared multiplayer protocol types and transport-facing wire helpers.
Definition ClientPrediction.cpp:13
constexpr bool isFailedState(EConnectState state)
Returns true if the state represents a terminal failure.
Definition NetClient.h:39
constexpr std::string_view connectStateName(EConnectState state)
Returns a human-readable label for a connection state.
Definition NetClient.h:45
@ BombPlaced
Server message indicating that a bomb has been placed by a player.
@ ExplosionResolved
Server message containing the authoritative result of a bomb explosion.
EConnectState
Client connection lifecycle state.
Definition NetClient.h:25
@ Disconnecting
Graceful disconnect requested, awaiting ENet completion.
@ Connected
Session accepted and ready for lobby flow or the next round-start message.
@ FailedHandshake
Handshake timed out or was rejected for a non-protocol reason.
@ FailedConnect
Connect attempt timed out or transport failed before handshake.
@ FailedInit
ENet initialization or host creation failed.
@ FailedResolve
Host address could not be resolved.
@ FailedProtocol
Protocol version mismatch during handshake.
@ Connecting
ENet connect in progress, waiting for a CONNECT event.
@ Handshaking
Transport connected and Hello sent, awaiting Welcome or Reject.
@ Disconnected
Not connected and holding no transport resources.
Reliable discrete bomb-placement event sent by the server.
Definition NetCommon.h:757
Owner-only correction payload sent by the server.
Definition NetCommon.h:738
Reliable authoritative explosion-resolution event sent by the server.
Definition NetCommon.h:776
Round-start payload sent reliably by the server when a match begins.
Definition NetCommon.h:546
Passive lobby seat snapshot sent reliably by the server.
Definition NetCommon.h:599
Reliable end-of-match result edge sent before the automatic return to lobby.
Definition NetCommon.h:579
Explicit reliable start edge sent once all current match participants have loaded.
Definition NetCommon.h:565
Snapshot payload broadcast by the server to all clients.
Definition NetCommon.h:673
Live multiplayer/network HUD state updated during gameplay.
Definition NetClient.h:79
One reliable gameplay event dequeued in original receive order.
Definition NetClient.h:322
Definition NetClientInternal.h:117