foxygit / doom Log in
commit 4dac08c8694f9b347b2b5c0ca12a0d26b1ae6589
Author:     Simon Howard <fraggle@gmail.com>
AuthorDate: Sun Sep 26 01:21:02 2010 +0000
Commit:     Simon Howard <fraggle@gmail.com>
CommitDate: Sun Sep 26 01:21:02 2010 +0000

    Restructure player quit code to take place on the first tic after the
    player quit, to avoid possible desyncs. Further refactoring to split
    game-specific code from generic code.

    Subversion-branch: /branches/raven-branch
    Subversion-revision: 2141
---
 src/doom/d_main.c   |   5 +-
 src/doom/d_net.c    | 316 ++++++++++++++++++++++++++++++----------------------
 src/doom/doomstat.h |   2 +-
 src/doom/g_game.c   |   6 +-
 4 files changed, 192 insertions(+), 137 deletions(-)

diff --git a/src/doom/d_main.c b/src/doom/d_main.c
index f3a4b037..fed6a1b4 100644
--- a/src/doom/d_main.c
+++ b/src/doom/d_main.c
@@ -457,9 +457,12 @@ void D_DoomLoop (void)
 	// process one or more tics
 	if (singletics)
 	{
+            static ticcmd_t cmds[MAXPLAYERS];
+
 	    I_StartTic ();
 	    D_ProcessEvents ();
-	    G_BuildTiccmd (&netcmds[consoleplayer][maketic%BACKUPTICS]);
+            netcmds = cmds;
+	    G_BuildTiccmd(&cmds[consoleplayer]);
 	    if (advancedemo)
 		D_DoAdvanceDemo ();
 	    M_Ticker ();
diff --git a/src/doom/d_net.c b/src/doom/d_net.c
index a081b72a..a15d3b1a 100644
--- a/src/doom/d_net.c
+++ b/src/doom/d_net.c
@@ -49,19 +49,27 @@
 #include "net_sdl.h"
 #include "net_loop.h"

+// The complete set of data for a particular tic.
+
+typedef struct
+{
+    ticcmd_t cmds[MAXPLAYERS];
+    boolean ingame[MAXPLAYERS];
+} ticcmd_set_t;

 //
 // NETWORKING
 //
 // gametic is the tic about to (or currently being) run
-// maketic is the tick that hasn't had control made for it yet
-// nettics[] has the maketics for all players
+// maketic is the tic that hasn't had control made for it yet
+// recvtic is the latest tic received from the server.
 //
-// a gametic cannot be run until nettics[] > gametic for all players
+// a gametic cannot be run until ticcmds are received for it
+// from all players.
 //

-ticcmd_t        netcmds[MAXPLAYERS][BACKUPTICS];
-int         	nettics[MAXPLAYERS];
+ticcmd_set_t ticdata[BACKUPTICS];
+ticcmd_t *netcmds;

 int             maketic;
 int             recvtic;
@@ -208,10 +216,10 @@ void NetUpdate (void)
         }

 #endif
-        netcmds[consoleplayer][maketic % BACKUPTICS] = cmd;
+        ticdata[maketic % BACKUPTICS].cmds[consoleplayer] = cmd;
+        ticdata[maketic % BACKUPTICS].ingame[consoleplayer] = true;

 	++maketic;
-        nettics[consoleplayer] = maketic;
     }
 }

@@ -245,8 +253,6 @@ static void D_PlayerQuitGame(player_t *player)

 static void D_Disconnected(void)
 {
-    int i;
-
     // In drone mode, the game cannot continue once disconnected.

     if (drone)
@@ -257,14 +263,6 @@ static void D_Disconnected(void)
     // disconnected from server

     printf("Disconnected from server.\n");
-
-    for (i=0; i<MAXPLAYERS; ++i)
-    {
-        if (i != consoleplayer && playeringame[i])
-        {
-            D_PlayerQuitGame(&players[i]);
-        }
-    }
 }

 //
@@ -284,22 +282,16 @@ void D_ReceiveTic(ticcmd_t *ticcmds, boolean *players_mask)
         return;
     }

-    for (i=0; i<MAXPLAYERS; ++i)
+    for (i = 0; i < MAXPLAYERS; ++i)
     {
         if (!drone && i == consoleplayer)
         {
-            // This is us.
-        }
-        else if (players_mask[i])
-        {
-            netcmds[i][recvtic % BACKUPTICS] = ticcmds[i];
-            nettics[i] = recvtic;
+            // This is us.  Don't overwrite it.
         }
-        else if (playeringame[i])
+        else
         {
-            // Player quit the game.
-
-            D_PlayerQuitGame(&players[i]);
+            ticdata[recvtic % BACKUPTICS].cmds[i] = ticcmds[i];
+            ticdata[recvtic % BACKUPTICS].ingame[i] = players_mask[i];
         }
     }

@@ -345,9 +337,10 @@ void D_CheckNetGame (void)
     for (i=0; i<MAXPLAYERS; i++)
     {
         playeringame[i] = false;
-       	nettics[i] = 0;
     }

+    recvtic = 0;
+
     playeringame[0] = true;

 #ifdef FEATURE_MULTIPLAYER
@@ -503,62 +496,172 @@ void D_QuitNetGame (void)

 }

-// Returns true if there are currently any players in the game.
+static int GetLowTic(void)
+{
+    int lowtic;

-static boolean PlayersInGame(void)
+    lowtic = maketic;
+
+#ifdef FEATURE_MULTIPLAYER
+    if (net_client_connected)
+    {
+        if (drone || recvtic < lowtic)
+        {
+            lowtic = recvtic;
+        }
+    }
+#endif
+
+    return lowtic;
+}
+
+int	frametics[4];
+int	frameon;
+int	frameskip[4];
+int	oldnettics;
+
+static void OldNetSync(void)
 {
-    int i;
+    unsigned int i;
+    unsigned int keyplayer = -1;

-    for (i=0; i<MAXPLAYERS; ++i)
+    frameon++;
+
+    // ideally maketic should be 1 - 3 tics above lowtic
+    // if we are consistantly slower, speed up time
+
+    for (i=0 ; i<MAXPLAYERS ; i++)
     {
+        // TODO: playeringame should not be used here.
+
         if (playeringame[i])
         {
-            return true;
+            keyplayer = i;
+            break;
         }
     }

-    return false;
+    if (keyplayer < 0)
+    {
+        // If there are no players, we can never advance anyway
+
+        return;
+    }
+
+    if (consoleplayer == keyplayer)
+    {
+        // the key player does not adapt
+    }
+    else
+    {
+        if (maketic <= recvtic)
+        {
+            lasttime--;
+            // printf ("-");
+        }
+
+        frameskip[frameon & 3] = oldnettics > recvtic;
+        oldnettics = maketic;
+
+        if (frameskip[0] && frameskip[1] && frameskip[2] && frameskip[3])
+        {
+            skiptics = 1;
+            // printf ("+");
+        }
+    }
 }

-static int GetLowTic(void)
+// Returns true if there are players in the game:
+
+static boolean PlayersInGame(void)
 {
-    int lowtic;
+    boolean result = false;
+    unsigned int i;
+
+    // If we are connected to a server, check if there are any players
+    // in the game.

-#ifdef FEATURE_MULTIPLAYER
     if (net_client_connected)
     {
-        int i;
-
-        lowtic = INT_MAX;
-
-        for (i=0; i<MAXPLAYERS; ++i)
+        for (i = 0; i < MAXPLAYERS; ++i)
         {
-            if (playeringame[i])
-            {
-                if (nettics[i] < lowtic)
-                    lowtic = nettics[i];
-            }
+            result = result || playeringame[i];
         }
     }
-    else
-#endif
+
+    // Whether single or multi-player, unless we are running as a drone,
+    // we are in the game.
+
+    if (!drone)
     {
-        lowtic = maketic;
+        result = true;
     }

-    return lowtic;
+    return result;
+}
+
+// When using ticdup, certain values must be cleared out when running
+// the duplicate ticcmds.
+
+static void TicdupSquash(ticcmd_set_t *set)
+{
+    ticcmd_t *cmd;
+    unsigned int i;
+
+    for (i = 0; i < MAXPLAYERS ; ++i)
+    {
+        cmd = &set->cmds[i];
+        cmd->chatchar = 0;
+        if (cmd->buttons & BT_SPECIAL)
+            cmd->buttons = 0;
+    }
+}
+
+static void D_RunTic(ticcmd_set_t *set)
+{
+    extern boolean advancedemo;
+    unsigned int i;
+
+    // Check for player quits.
+
+    for (i = 0; i < MAXPLAYERS; ++i)
+    {
+        if (playeringame[i] && !set->ingame[i])
+        {
+            D_PlayerQuitGame(&players[i]);
+        }
+    }
+
+    netcmds = set->cmds;
+
+    // check that there are players in the game.  if not, we cannot
+    // run a tic.
+
+    if (advancedemo)
+        D_DoAdvanceDemo ();
+
+    G_Ticker ();
+}
+
+// When running in single player mode, clear all the ingame[] array
+// except the consoleplayer.
+
+static void SinglePlayerClear(ticcmd_set_t *set)
+{
+    unsigned int i;
+
+    for (i = 0; i < MAXPLAYERS; ++i)
+    {
+        if (i != consoleplayer)
+        {
+            set->ingame[i] = false;
+        }
+    }
 }

 //
 // TryRunTics
 //
-int	oldnettics;
-int	frametics[4];
-int	frameon;
-int	frameskip[4];
-int	oldnettics;
-
-extern	boolean	advancedemo;

 void TryRunTics (void)
 {
@@ -601,52 +704,9 @@ void TryRunTics (void)
         if (counts < 1)
             counts = 1;

-        frameon++;
-
-        if (!demoplayback)
+        if (net_client_connected)
         {
-	    int keyplayer = -1;
-
-            // ideally maketic should be 1 - 3 tics above lowtic
-            // if we are consistantly slower, speed up time
-
-            for (i=0 ; i<MAXPLAYERS ; i++)
-	    {
-                if (playeringame[i])
-		{
-		    keyplayer = i;
-                    break;
-		}
-	    }
-
-	    if (keyplayer < 0)
-	    {
-		// If there are no players, we can never advance anyway
-
-		return;
-	    }
-
-            if (consoleplayer == keyplayer)
-            {
-                // the key player does not adapt
-            }
-            else
-            {
-                if (maketic <= nettics[keyplayer])
-                {
-                    lasttime--;
-                    // printf ("-");
-                }
-
-                frameskip[frameon & 3] = (oldnettics > nettics[keyplayer]);
-                oldnettics = maketic;
-
-                if (frameskip[0] && frameskip[1] && frameskip[2] && frameskip[3])
-                {
-                    skiptics = 1;
-                    // printf ("+");
-                }
-            }
+            OldNetSync();
         }
     }

@@ -678,41 +738,33 @@ void TryRunTics (void)
     // run the count * ticdup dics
     while (counts--)
     {
+        ticcmd_set_t *set;
+
+        if (!PlayersInGame())
+        {
+            return;
+        }
+
+        set = &ticdata[(gametic / ticdup) % BACKUPTICS];
+
+        if (!net_client_connected)
+        {
+            SinglePlayerClear(set);
+        }
+
 	for (i=0 ; i<ticdup ; i++)
 	{
-            // check that there are players in the game.  if not, we cannot
-            // run a tic.
-
-            if (!PlayersInGame())
-            {
-                return;
-            }
-
-	    if (gametic/ticdup > lowtic)
-		I_Error ("gametic>lowtic");
-	    if (advancedemo)
-		D_DoAdvanceDemo ();
+            if (gametic/ticdup > lowtic)
+                I_Error ("gametic>lowtic");

-	    G_Ticker ();
+            D_RunTic(set);
 	    gametic++;

 	    // modify command for duplicated tics
-	    if (i != ticdup-1)
-	    {
-		ticcmd_t	*cmd;
-		int			buf;
-		int			j;
-
-		buf = (gametic/ticdup)%BACKUPTICS;
-		for (j=0 ; j<MAXPLAYERS ; j++)
-		{
-		    cmd = &netcmds[j][buf];
-		    cmd->chatchar = 0;
-		    if (cmd->buttons & BT_SPECIAL)
-			cmd->buttons = 0;
-		}
-	    }
+
+            TicdupSquash(set);
 	}
+
 	NetUpdate ();	// check for new console commands
     }
 }
diff --git a/src/doom/doomstat.h b/src/doom/doomstat.h
index 40147833..15a8d743 100644
--- a/src/doom/doomstat.h
+++ b/src/doom/doomstat.h
@@ -289,7 +289,7 @@ extern	int		rndindex;
 extern	int		maketic;
 extern  int             nettics[MAXPLAYERS];

-extern  ticcmd_t        netcmds[MAXPLAYERS][BACKUPTICS];
+extern  ticcmd_t       *netcmds;
 extern	int		ticdup;


diff --git a/src/doom/g_game.c b/src/doom/g_game.c
index ad7155a0..0aaf8ee7 100644
--- a/src/doom/g_game.c
+++ b/src/doom/g_game.c
@@ -986,9 +986,9 @@ void G_Ticker (void)
 	if (playeringame[i])
 	{
 	    cmd = &players[i].cmd;
-
-	    memcpy (cmd, &netcmds[i][buf], sizeof(ticcmd_t));
-
+
+	    memcpy(cmd, &netcmds[i], sizeof(ticcmd_t));
+
 	    if (demoplayback)
 		G_ReadDemoTiccmd (cmd);
 	    if (demorecording)