https://github.com/libsdl-org/Maelstrom/commit/655883923d2e30b55bbb82d4b6776af51cf015a8
From 655883923d2e30b55bbb82d4b6776af51cf015a8 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Sun, 20 Nov 2011 14:03:40 -0500
Subject: [PATCH] Differentiate between timeout and sync corruption cases in
the network sync code.
---
game/game.cpp | 26 ++++++++++++++++++++++----
game/netplay.cpp | 39 +++++++++++++++++++++------------------
game/netplay.h | 14 +++++++++++++-
3 files changed, 56 insertions(+), 23 deletions(-)
diff --git a/game/game.cpp b/game/game.cpp
index ea09726c..c7a04770 100644
--- a/game/game.cpp
+++ b/game/game.cpp
@@ -236,6 +236,7 @@ void
GamePanelDelegate::OnTick()
{
int i, j;
+ SYNC_RESULT syncResult;
if (!gGameOn) {
// This generally shouldn't happen, but could if there were
@@ -251,14 +252,31 @@ GamePanelDelegate::OnTick()
gGameOn = 0;
return;
}
- int syncResult = SyncNetwork();
+
+ syncResult = SyncNetwork();
+
+ // Update state and see if the local player aborted
if ( !UpdateGameState() ) {
gGameOn = 0;
return;
}
- if (syncResult < 0) {
- // We didn't get a full frame yet, don't process it
- return;
+ switch (syncResult) {
+ case SYNC_TIMEOUT:
+ // The other players might be minimized or doing
+ // the bonus screen and may not be able to respond.
+ return;
+ case SYNC_CORRUPT:
+ // Uh oh...
+ error("Network sync error, game aborted!\r\n");
+ gGameOn = 0;
+ return;
+ case SYNC_NETERROR:
+ // Uh oh...
+ error("Network socket error, game aborted!\r\n");
+ gGameOn = 0;
+ return;
+ case SYNC_COMPLETE:
+ break;
}
gReplay.HandleRecording();
diff --git a/game/netplay.cpp b/game/netplay.cpp
index 5592a833..c4eeaf25 100644
--- a/game/netplay.cpp
+++ b/game/netplay.cpp
@@ -199,7 +199,7 @@ static bool ProcessSync(int index, DynamicPacket &packet)
return true;
}
-static int AwaitSync()
+static SYNC_RESULT AwaitSync()
{
int i;
int timeout;
@@ -209,7 +209,7 @@ static int AwaitSync()
for (i = 0; i < MAX_NODES; ++i) {
if (CachedPacket[i].len > 0 && WaitingAcks[i]) {
if (!ProcessSync(i, CachedPacket[i])) {
- return -1;
+ return SYNC_CORRUPT;
}
WaitingAcks[i] = 0;
}
@@ -229,7 +229,7 @@ static int AwaitSync()
int ready = SDLNet_CheckSockets(SocketSet, 100);
if (ready < 0) {
error("Network error: SDLNet_CheckSockets()\r\n");
- return(-1);
+ return SYNC_NETERROR;
}
if (ready == 0) {
#if DEBUG_NETWORK >= 1
@@ -245,7 +245,7 @@ error("Timed out waiting for frame %ld\r\n", NextFrame);
/* Don't wait forever */
++timeout;
if ( timeout == (PING_TIMEOUT/100) ) {
- return(-1);
+ return SYNC_TIMEOUT;
}
}
if ( ready <= 0 ) {
@@ -256,7 +256,7 @@ error("Timed out waiting for frame %ld\r\n", NextFrame);
Packet.Reset();
if ( SDLNet_UDP_Recv(gNetFD, &Packet) <= 0 ) {
error("Network error: SDLNet_UDP_Recv()\r\n");
- return(-1);
+ return SYNC_NETERROR;
}
/* We have a packet! */
@@ -322,7 +322,7 @@ error("Ignoring duplicate packet for frame %lu from player %d\r\n", frame, index
/* Do a consistency check!! */
if (!ProcessSync(index, Packet)) {
- return -1;
+ return SYNC_CORRUPT;
}
WaitingAcks[index] = 0;
} else if (frame == (NextFrame-1)) {
@@ -352,16 +352,15 @@ error("Received packet for really old frame! (%lu, current = %lu)\r\n",
frame, NextFrame);
#endif
}
- return 0;
+ return SYNC_COMPLETE;
}
-static int AdvanceFrame()
+static void AdvanceFrame()
{
CurrOut = !CurrOut;
QueuedInput.Reset();
++NextFrame;
AdvancedFrame = true;
- return 0;
}
/* This function is called every frame, and is used to flush the network
@@ -373,16 +372,18 @@ static int AdvanceFrame()
otherwise we lose consistency.
*/
-int SyncNetwork(void)
+SYNC_RESULT SyncNetwork(void)
{
+ SYNC_RESULT result = SYNC_COMPLETE;
int i;
if (!AdvancedFrame) {
// We still have some nodes we're waiting on...
- if (AwaitSync() < 0) {
- return -1;
+ result = AwaitSync();
+ if (result == SYNC_COMPLETE) {
+ AdvanceFrame();
}
- return AdvanceFrame();
+ return result;
}
FrameInput.Reset();
@@ -410,13 +411,15 @@ int SyncNetwork(void)
CurrPacket.Write(QueuedInput);
// Wait for sync packets from them
- if (AwaitSync() < 0) {
- AdvancedFrame = false;
- return -1;
- }
+ result = AwaitSync();
}
- return AdvanceFrame();
+ if (result == SYNC_COMPLETE) {
+ AdvanceFrame();
+ } else {
+ AdvancedFrame = false;
+ }
+ return result;
}
/* This function retrieves the input for the frame */
diff --git a/game/netplay.h b/game/netplay.h
index 0754bfd9..75c088c8 100644
--- a/game/netplay.h
+++ b/game/netplay.h
@@ -20,17 +20,29 @@
slouken@libsdl.org
*/
+#ifndef _netplay_h
+#define _netplay_h
+
#include "SDL_net.h"
+enum SYNC_RESULT {
+ SYNC_COMPLETE,
+ SYNC_TIMEOUT,
+ SYNC_CORRUPT,
+ SYNC_NETERROR,
+};
+
/* Functions in netplay.cpp */
extern int InitNetData(bool hosting);
extern void HaltNetData(void);
extern int CheckPlayers(void);
extern void QueueInput(Uint8 value);
-extern int SyncNetwork(void);
+extern SYNC_RESULT SyncNetwork(void);
extern int GetSyncBuf(Uint8 **bufptr);
extern int Send_NewGame();
/* Variables from netplay.cpp */
extern UDPsocket gNetFD;
extern Uint32 NextFrame; // Exposed for debugging purposes
+
+#endif // _netplay_h