shithub: choc

Download patch

ref: 687ab6c9a481ffcec476fce2add35b7ae12eee48
parent: 460c3748565ba1f0fee9e39fd33e76436c6ddc78
author: Simon Howard <[email protected]>
date: Wed Oct 12 21:15:33 EDT 2011

Split out common main loop code into separate file, d_loop.c.

Subversion-branch: /branches/v2-branch
Subversion-revision: 2413

--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -144,9 +144,11 @@
 
 if HAVE_WINDRES
 @PROGRAM_PREFIX@doom_SOURCES=$(SOURCE_FILES_WITH_DEH) resource.rc \
+               d_loop.c d_loop.h \
                $(FEATURE_MULTIPLAYER_SOURCE_FILES)
 else
 @PROGRAM_PREFIX@doom_SOURCES=$(SOURCE_FILES_WITH_DEH) \
+               d_loop.c d_loop.h \
                $(FEATURE_MULTIPLAYER_SOURCE_FILES)
 endif
 
--- /dev/null
+++ b/src/d_loop.c
@@ -1,0 +1,751 @@
+// Emacs style mode select   -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+//     Main loop code.
+//
+//-----------------------------------------------------------------------------
+
+#include <stdlib.h>
+
+#include "doomfeatures.h"
+
+#include "d_event.h"
+#include "d_loop.h"
+#include "d_ticcmd.h"
+
+#include "i_system.h"
+#include "i_timer.h"
+#include "i_video.h"
+
+#include "m_argv.h"
+#include "m_fixed.h"
+
+#include "net_client.h"
+#include "net_gui.h"
+#include "net_io.h"
+#include "net_query.h"
+#include "net_server.h"
+#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;
+
+//
+// gametic is the tic about to (or currently being) run
+// 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 ticcmds are received for it
+// from all players.
+//
+
+static ticcmd_set_t ticdata[BACKUPTICS];
+
+// The index of the next tic to be made (with a call to BuildTiccmd).
+
+static int maketic;
+
+// The number of complete tics received from the server so far.
+
+static int recvtic;
+
+// The number of tics that have been run (using RunTic) so far.
+
+int gametic;
+
+// When set to true, a single tic is run each time TryRunTics() is called.
+// This is used for -timedemo mode.
+
+boolean singletics = false;
+
+// Index of the local player.
+
+static int localplayer;
+
+// Used for original sync code.
+
+static int      skiptics = 0;
+
+// Reduce the bandwidth needed by sampling game input less and transmitting
+// less.  If ticdup is 2, sample half normal, 3 = one third normal, etc.
+
+int		ticdup;
+
+// Amount to offset the timer for game sync.
+
+fixed_t         offsetms;
+
+// Use new client syncronisation code
+
+static boolean  new_sync = true;
+
+// Callback functions for loop code.
+
+static loop_interface_t *loop_interface = NULL;
+
+// Current players in the multiplayer game.
+// This is distinct from playeringame[] used by the game code, which may
+// modify playeringame[] when playing back multiplayer demos.
+
+static boolean local_playeringame[MAXPLAYERS];
+
+
+// 35 fps clock adjusted by offsetms milliseconds
+
+static int GetAdjustedTime(void)
+{
+    int time_ms;
+
+    time_ms = I_GetTimeMS();
+
+    if (new_sync)
+    {
+	// Use the adjustments from net_client.c only if we are
+	// using the new sync mode.
+
+        time_ms += (offsetms / FRACUNIT);
+    }
+
+    return (time_ms * TICRATE) / 1000;
+}
+
+static boolean BuildNewTic(void)
+{
+    int	gameticdiv;
+    ticcmd_t cmd;
+
+    gameticdiv = gametic/ticdup;
+
+    I_StartTic ();
+    loop_interface->ProcesEvents();
+
+    // Always run the menu
+
+    loop_interface->RunMenu();
+
+    if (drone)
+    {
+        // In drone mode, do not generate any ticcmds.
+
+        return false;
+    }
+
+    if (new_sync)
+    {
+       // If playing single player, do not allow tics to buffer
+       // up very far
+
+       if (!net_client_connected && maketic - gameticdiv > 2)
+           return false;
+
+       // Never go more than ~200ms ahead
+
+       if (maketic - gameticdiv > 8)
+           return false;
+    }
+    else
+    {
+       if (maketic - gameticdiv >= 5)
+           return false;
+    }
+
+    //printf ("mk:%i ",maketic);
+    loop_interface->BuildTiccmd(&cmd, maketic);
+
+#ifdef FEATURE_MULTIPLAYER
+
+    if (net_client_connected)
+    {
+        NET_CL_SendTiccmd(&cmd, maketic);
+    }
+
+#endif
+    ticdata[maketic % BACKUPTICS].cmds[localplayer] = cmd;
+    ticdata[maketic % BACKUPTICS].ingame[localplayer] = true;
+
+    ++maketic;
+
+    return true;
+}
+
+//
+// NetUpdate
+// Builds ticcmds for console player,
+// sends out a packet
+//
+int      lasttime;
+
+void NetUpdate (void)
+{
+    int nowtime;
+    int newtics;
+    int	i;
+
+    // If we are running with singletics (timing a demo), this
+    // is all done separately.
+
+    if (singletics)
+        return;
+
+#ifdef FEATURE_MULTIPLAYER
+
+    // Run network subsystems
+
+    NET_CL_Run();
+    NET_SV_Run();
+
+#endif
+
+    // check time
+    nowtime = GetAdjustedTime() / ticdup;
+    newtics = nowtime - lasttime;
+
+    lasttime = nowtime;
+
+    if (skiptics <= newtics)
+    {
+        newtics -= skiptics;
+        skiptics = 0;
+    }
+    else
+    {
+        skiptics -= newtics;
+        newtics = 0;
+    }
+
+    // build new ticcmds for console player
+
+    for (i=0 ; i<newtics ; i++)
+    {
+        if (!BuildNewTic())
+        {
+            break;
+        }
+    }
+}
+
+static void D_Disconnected(void)
+{
+    // In drone mode, the game cannot continue once disconnected.
+
+    if (drone)
+    {
+        I_Error("Disconnected from server in drone mode.");
+    }
+
+    // disconnected from server
+
+    printf("Disconnected from server.\n");
+}
+
+//
+// Invoked by the network engine when a complete set of ticcmds is
+// available.
+//
+
+void D_ReceiveTic(ticcmd_t *ticcmds, boolean *players_mask)
+{
+    int i;
+
+    // Disconnected from server?
+
+    if (ticcmds == NULL && players_mask == NULL)
+    {
+        D_Disconnected();
+        return;
+    }
+
+    for (i = 0; i < MAXPLAYERS; ++i)
+    {
+        if (!drone && i == localplayer)
+        {
+            // This is us.  Don't overwrite it.
+        }
+        else
+        {
+            ticdata[recvtic % BACKUPTICS].cmds[i] = ticcmds[i];
+            ticdata[recvtic % BACKUPTICS].ingame[i] = players_mask[i];
+        }
+    }
+
+    ++recvtic;
+}
+
+//
+// Start game loop
+//
+// Called after the screen is set but before the game starts running.
+//
+
+void D_StartGameLoop(void)
+{
+    lasttime = GetAdjustedTime() / ticdup;
+}
+
+boolean D_InitNetGame(net_connect_data_t *connect_data,
+                      net_gamesettings_t *settings)
+{
+    net_addr_t *addr = NULL;
+    boolean result = false;
+    int i;
+
+    offsetms = 0;
+    recvtic = 0;
+
+    settings->consoleplayer = 0;
+    settings->num_players = 1;
+
+    //!
+    // @category net
+    //
+    // Use original game sync code.
+    //
+
+    if (M_CheckParm("-oldsync") > 0)
+	settings->new_sync = 0;
+    else
+	settings->new_sync = 1;
+
+    //!
+    // @category net
+    // @arg <n>
+    //
+    // Send n extra tics in every packet as insurance against dropped
+    // packets.
+    //
+
+    i = M_CheckParmWithArgs("-extratics", 1);
+
+    if (i > 0)
+        settings->extratics = atoi(myargv[i+1]);
+    else
+        settings->extratics = 1;
+
+    //!
+    // @category net
+    // @arg <n>
+    //
+    // Reduce the resolution of the game by a factor of n, reducing
+    // the amount of network bandwidth needed.
+    //
+
+    i = M_CheckParmWithArgs("-dup", 1);
+
+    if (i > 0)
+        settings->ticdup = atoi(myargv[i+1]);
+    else
+        settings->ticdup = 1;
+
+#ifdef FEATURE_MULTIPLAYER
+
+    //!
+    // @category net
+    //
+    // Start a multiplayer server, listening for connections.
+    //
+
+    if (M_CheckParm("-server") > 0
+     || M_CheckParm("-privateserver") > 0)
+    {
+        NET_SV_Init();
+        NET_SV_AddModule(&net_loop_server_module);
+        NET_SV_AddModule(&net_sdl_module);
+        NET_SV_RegisterWithMaster();
+
+        net_loop_client_module.InitClient();
+        addr = net_loop_client_module.ResolveAddress(NULL);
+    }
+    else
+    {
+        //!
+        // @category net
+        //
+        // Automatically search the local LAN for a multiplayer
+        // server and join it.
+        //
+
+        i = M_CheckParm("-autojoin");
+
+        if (i > 0)
+        {
+            addr = NET_FindLANServer();
+
+            if (addr == NULL)
+            {
+                I_Error("No server found on local LAN");
+            }
+        }
+
+        //!
+        // @arg <address>
+        // @category net
+        //
+        // Connect to a multiplayer server running on the given
+        // address.
+        //
+
+        i = M_CheckParmWithArgs("-connect", 1);
+
+        if (i > 0)
+        {
+            net_sdl_module.InitClient();
+            addr = net_sdl_module.ResolveAddress(myargv[i+1]);
+
+            if (addr == NULL)
+            {
+                I_Error("Unable to resolve '%s'\n", myargv[i+1]);
+            }
+        }
+    }
+
+    if (addr != NULL)
+    {
+        if (M_CheckParm("-drone") > 0)
+        {
+            connect_data->drone = true;
+        }
+
+        if (!NET_CL_Connect(addr, connect_data))
+        {
+            I_Error("D_CheckNetGame: Failed to connect to %s\n",
+                    NET_AddrToString(addr));
+        }
+
+        printf("D_CheckNetGame: Connected to %s\n", NET_AddrToString(addr));
+
+        // Wait for game start message received from server.
+
+        NET_WaitForStart(settings);
+
+        // Read the game settings that were received.
+
+        NET_CL_GetSettings(settings);
+
+        result = true;
+    }
+
+#endif
+
+    // Set the local player and playeringame[] values.
+
+    localplayer = settings->consoleplayer;
+
+    for (i = 0; i < MAXPLAYERS; ++i)
+    {
+        local_playeringame[i] = i < settings->num_players;
+    }
+
+    // Check for sync mode.
+
+    new_sync = settings->new_sync;
+
+    if (new_sync == false)
+    {
+	printf("Syncing netgames like Vanilla Doom.\n");
+    }
+
+    return result;
+}
+
+
+//
+// D_QuitNetGame
+// Called before quitting to leave a net game
+// without hanging the other players
+//
+void D_QuitNetGame (void)
+{
+#ifdef FEATURE_MULTIPLAYER
+
+    NET_SV_Shutdown();
+    NET_CL_Disconnect();
+
+#endif
+
+}
+
+static int GetLowTic(void)
+{
+    int lowtic;
+
+    lowtic = maketic;
+
+#ifdef FEATURE_MULTIPLAYER
+    if (net_client_connected)
+    {
+        if (drone || recvtic < lowtic)
+        {
+            lowtic = recvtic;
+        }
+    }
+#endif
+
+    return lowtic;
+}
+
+static int frameon;
+static int frameskip[4];
+static int oldnettics;
+
+static void OldNetSync(void)
+{
+    unsigned int i;
+    unsigned int keyplayer = -1;
+
+    frameon++;
+
+    // ideally maketic should be 1 - 3 tics above lowtic
+    // if we are consistantly slower, speed up time
+
+    for (i=0 ; i<MAXPLAYERS ; i++)
+    {
+        if (local_playeringame[i])
+        {
+            keyplayer = i;
+            break;
+        }
+    }
+
+    if (keyplayer < 0)
+    {
+        // If there are no players, we can never advance anyway
+
+        return;
+    }
+
+    if (localplayer == 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 ("+");
+        }
+    }
+}
+
+// Returns true if there are players in the game:
+
+static boolean PlayersInGame(void)
+{
+    boolean result = false;
+    unsigned int i;
+
+    // If we are connected to a server, check if there are any players
+    // in the game.
+
+    if (net_client_connected)
+    {
+        for (i = 0; i < MAXPLAYERS; ++i)
+        {
+            result = result || local_playeringame[i];
+        }
+    }
+
+    // Whether single or multi-player, unless we are running as a drone,
+    // we are in the game.
+
+    if (!drone)
+    {
+        result = true;
+    }
+
+    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;
+    }
+}
+
+// When running in single player mode, clear all the ingame[] array
+// except the local player.
+
+static void SinglePlayerClear(ticcmd_set_t *set)
+{
+    unsigned int i;
+
+    for (i = 0; i < MAXPLAYERS; ++i)
+    {
+        if (i != localplayer)
+        {
+            set->ingame[i] = false;
+        }
+    }
+}
+
+//
+// TryRunTics
+//
+
+void TryRunTics (void)
+{
+    int	i;
+    int	lowtic;
+    int	entertic;
+    static int oldentertics;
+    int realtics;
+    int	availabletics;
+    int	counts;
+
+    // get real tics
+    entertic = I_GetTime() / ticdup;
+    realtics = entertic - oldentertics;
+    oldentertics = entertic;
+
+    // in singletics mode, run a single tic every time this function
+    // is called.
+
+    if (singletics)
+    {
+        BuildNewTic();
+    }
+    else
+    {
+        NetUpdate ();
+    }
+
+    lowtic = GetLowTic();
+
+    availabletics = lowtic - gametic/ticdup;
+
+    // decide how many tics to run
+
+    if (new_sync)
+    {
+	counts = availabletics;
+    }
+    else
+    {
+        // decide how many tics to run
+        if (realtics < availabletics-1)
+            counts = realtics+1;
+        else if (realtics < availabletics)
+            counts = realtics;
+        else
+            counts = availabletics;
+
+        if (counts < 1)
+            counts = 1;
+
+        if (net_client_connected)
+        {
+            OldNetSync();
+        }
+    }
+
+    if (counts < 1)
+	counts = 1;
+
+    // wait for new tics if needed
+
+    while (!PlayersInGame() || lowtic < gametic/ticdup + counts)
+    {
+	NetUpdate ();
+
+        lowtic = GetLowTic();
+
+	if (lowtic < gametic/ticdup)
+	    I_Error ("TryRunTics: lowtic < gametic");
+
+        // Don't stay in this loop forever.  The menu is still running,
+        // so return to update the screen
+
+	if (I_GetTime() / ticdup - entertic > 0)
+	{
+	    return;
+	}
+
+        I_Sleep(1);
+    }
+
+    // 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++)
+	{
+            if (gametic/ticdup > lowtic)
+                I_Error ("gametic>lowtic");
+
+            memcpy(local_playeringame, set->ingame, sizeof(local_playeringame));
+
+            loop_interface->RunTic(set->cmds, set->ingame);
+	    gametic++;
+
+	    // modify command for duplicated tics
+
+            TicdupSquash(set);
+	}
+
+	NetUpdate ();	// check for new console commands
+    }
+}
+
+void D_RegisterLoopCallbacks(loop_interface_t *i)
+{
+    loop_interface = i;
+}
+
--- /dev/null
+++ b/src/d_loop.h
@@ -1,0 +1,76 @@
+// Emacs style mode select   -*- C++ -*- 
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005-2011 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+//
+// DESCRIPTION:
+//	Main loop stuff.
+//
+//-----------------------------------------------------------------------------
+
+#ifndef __D_LOOP__
+#define __D_LOOP__
+
+#include "net_defs.h"
+
+typedef struct
+{
+    // Read events from the event queue, and process them.
+
+    void (*ProcesEvents)();
+
+    // Given the current input state, fill in the fields of the specified
+    // ticcmd_t structure with data for a new tic.
+
+    void (*BuildTiccmd)(ticcmd_t *cmd, int maketic);
+
+    // Advance the game forward one tic, using the specified player input.
+
+    void (*RunTic)(ticcmd_t *cmds, boolean *ingame);
+
+    // Run the menu (runs independently of the game).
+
+    void (*RunMenu)();
+} loop_interface_t;
+
+// Register callback functions for the main loop code to use.
+void D_RegisterLoopCallbacks(loop_interface_t *i);
+
+// Create any new ticcmds and broadcast to other players.
+void NetUpdate (void);
+
+// Broadcasts special packets to other players
+//  to notify of game exit
+void D_QuitNetGame (void);
+
+//? how many ticks to run?
+void TryRunTics (void);
+
+// Called at start of game loop to initialize timers
+void D_StartGameLoop(void);
+
+// Initialize networking code; structures contain desired game settings,
+// these may be changed.
+boolean D_InitNetGame(net_connect_data_t *connect_data,
+                      net_gamesettings_t *settings);
+
+extern boolean singletics;
+
+#endif
+
--- a/src/doom/d_main.c
+++ b/src/doom/d_main.c
@@ -107,9 +107,6 @@
 boolean         respawnparm;	// checkparm of -respawn
 boolean         fastparm;	// checkparm of -fast
 
-boolean		singletics = false; // debug flag to cancel adaptiveness
-
-
 //extern int soundVolume;
 //extern  int	sfxVolume;
 //extern  int	musicVolume;
@@ -136,8 +133,6 @@
 
 
 void D_CheckNetGame (void);
-void D_ProcessEvents (void);
-void G_BuildTiccmd (ticcmd_t* cmd);
 void D_DoAdvanceDemo (void);
 
 
@@ -442,29 +437,10 @@
     while (1)
     {
 	// frame syncronous IO operations
-	I_StartFrame ();                
-	
-	// process one or more tics
-	if (singletics)
-	{
-            static ticcmd_t cmds[MAXPLAYERS];
+	I_StartFrame ();
 
-	    I_StartTic ();
-	    D_ProcessEvents ();
-            netcmds = cmds;
-	    G_BuildTiccmd(&cmds[consoleplayer]);
-	    if (advancedemo)
-		D_DoAdvanceDemo ();
-	    M_Ticker ();
-	    G_Ticker ();
-	    gametic++;
-	    maketic++;
-	}
-	else
-	{
-	    TryRunTics (); // will run at least one tic
-	}
-		
+        TryRunTics (); // will run at least one tic
+
 	S_UpdateSounds (players[consoleplayer].mo);// move positional sounds
 
 	// Update display, next frame, with current state.
--- a/src/doom/d_net.c
+++ b/src/doom/d_net.c
@@ -41,669 +41,8 @@
 
 #include "deh_main.h"
 
-#include "net_client.h"
-#include "net_gui.h"
-#include "net_io.h"
-#include "net_query.h"
-#include "net_server.h"
-#include "net_sdl.h"
-#include "net_loop.h"
+#include "d_loop.h"
 
-typedef struct
-{
-    void (*BuildTiccmd)(ticcmd_t *cmd);
-    void (*RunTic)(ticcmd_t *cmds, boolean *ingame);
-    void (*RunMenu)();
-} loop_interface_t;
-
-// 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 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 ticcmds are received for it
-// from all players.
-//
-
-ticcmd_set_t ticdata[BACKUPTICS];
-
-int             maketic;
-int             recvtic;
-
-// Used for original sync code.
-
-static int      skiptics = 0;
-
-// Reduce the bandwidth needed by sampling game input less and transmitting
-// less.  If ticdup is 2, sample half normal, 3 = one third normal, etc.
-
-int		ticdup;
-
-// Send this many extra (backup) tics in each packet.
-
-int             extratics;
-
-// Amount to offset the timer for game sync.
-
-fixed_t         offsetms;
-
-// Use new client syncronisation code
-
-boolean         new_sync = true;
-
-// Callback functions for loop code.
-
-static loop_interface_t *loop_interface = NULL;
-
-// 35 fps clock adjusted by offsetms milliseconds
-
-static int GetAdjustedTime(void)
-{
-    int time_ms;
-
-    time_ms = I_GetTimeMS();
-
-    if (new_sync)
-    {
-	// Use the adjustments from net_client.c only if we are
-	// using the new sync mode.
-
-        time_ms += (offsetms / FRACUNIT);
-    }
-
-    return (time_ms * TICRATE) / 1000;
-}
-
-//
-// NetUpdate
-// Builds ticcmds for console player,
-// sends out a packet
-//
-int      lasttime;
-
-void NetUpdate (void)
-{
-    int nowtime;
-    int newtics;
-    int	i;
-    int	gameticdiv;
-
-    // If we are running with singletics (timing a demo), this
-    // is all done separately.
-
-    if (singletics)
-        return;
-    
-#ifdef FEATURE_MULTIPLAYER
-
-    // Run network subsystems
-
-    NET_CL_Run();
-    NET_SV_Run();
-
-#endif
-
-    // check time
-    nowtime = GetAdjustedTime() / ticdup;
-    newtics = nowtime - lasttime;
-
-    lasttime = nowtime;
-
-    if (skiptics <= newtics)
-    {
-        newtics -= skiptics;
-        skiptics = 0;
-    }
-    else
-    {
-        skiptics -= newtics;
-        newtics = 0;
-    }
-
-    // build new ticcmds for console player
-    gameticdiv = gametic/ticdup;
-
-    for (i=0 ; i<newtics ; i++)
-    {
-        ticcmd_t cmd;
-
-	I_StartTic ();
-	D_ProcessEvents ();
-
-        // Always run the menu
-
-        loop_interface->RunMenu();
-
-        if (drone)
-        {
-            // In drone mode, do not generate any ticcmds.
-
-            continue;
-        }
-	
-        if (new_sync)
-        { 
-           // If playing single player, do not allow tics to buffer
-           // up very far
-
-           if (!net_client_connected && maketic - gameticdiv > 2)
-               break;
-
-           // Never go more than ~200ms ahead
-
-           if (maketic - gameticdiv > 8)
-               break;
-        }
-	else
-	{
-           if (maketic - gameticdiv >= 5)
-               break;
-	}
-
-	//printf ("mk:%i ",maketic);
-	loop_interface->BuildTiccmd(&cmd);
-
-#ifdef FEATURE_MULTIPLAYER
-
-        if (net_client_connected)
-        {
-            NET_CL_SendTiccmd(&cmd, maketic);
-        }
-
-#endif
-        ticdata[maketic % BACKUPTICS].cmds[consoleplayer] = cmd;
-        ticdata[maketic % BACKUPTICS].ingame[consoleplayer] = true;
-
-	++maketic;
-    }
-}
-
-static void D_Disconnected(void)
-{
-    // In drone mode, the game cannot continue once disconnected.
-
-    if (drone)
-    { 
-        I_Error("Disconnected from server in drone mode.");
-    }
-
-    // disconnected from server
-
-    printf("Disconnected from server.\n");
-}
-
-//
-// Invoked by the network engine when a complete set of ticcmds is
-// available.
-//
-
-void D_ReceiveTic(ticcmd_t *ticcmds, boolean *players_mask)
-{
-    int i;
-
-    // Disconnected from server?
-
-    if (ticcmds == NULL && players_mask == NULL)
-    {
-        D_Disconnected();
-        return;
-    }
-
-    for (i = 0; i < MAXPLAYERS; ++i)
-    {
-        if (!drone && i == consoleplayer)
-        {
-            // This is us.  Don't overwrite it.
-        }
-        else
-        {
-            ticdata[recvtic % BACKUPTICS].cmds[i] = ticcmds[i];
-            ticdata[recvtic % BACKUPTICS].ingame[i] = players_mask[i];
-        }
-    }
-
-    ++recvtic;
-}
-
-//
-// Start game loop
-//
-// Called after the screen is set but before the game starts running.
-//  
-
-void D_StartGameLoop(void)
-{
-    lasttime = GetAdjustedTime() / ticdup;
-}
-
-boolean D_InitNetGame(net_connect_data_t *connect_data,
-                      net_gamesettings_t *settings)
-{
-    net_addr_t *addr = NULL;
-    boolean result = false;
-    int i;
-
-    //!
-    // @category net
-    //
-    // Use original game sync code.
-    //
-
-    if (M_CheckParm("-oldsync") > 0)
-	settings->new_sync = 0;
-    else
-	settings->new_sync = 1;
-    
-    //!
-    // @category net
-    // @arg <n>
-    //
-    // Send n extra tics in every packet as insurance against dropped
-    // packets.
-    //
-
-    i = M_CheckParmWithArgs("-extratics", 1);
-
-    if (i > 0)
-        settings->extratics = atoi(myargv[i+1]);
-    else
-        settings->extratics = 1;
-
-    //!
-    // @category net
-    // @arg <n>
-    //
-    // Reduce the resolution of the game by a factor of n, reducing
-    // the amount of network bandwidth needed.
-    //
-
-    i = M_CheckParmWithArgs("-dup", 1);
-
-    if (i > 0)
-        settings->ticdup = atoi(myargv[i+1]);
-    else
-        settings->ticdup = 1;
-
-#ifdef FEATURE_MULTIPLAYER
-
-    //!
-    // @category net
-    //
-    // Start a multiplayer server, listening for connections.
-    //
-
-    if (M_CheckParm("-server") > 0
-     || M_CheckParm("-privateserver") > 0)
-    {
-        NET_SV_Init();
-        NET_SV_AddModule(&net_loop_server_module);
-        NET_SV_AddModule(&net_sdl_module);
-        NET_SV_RegisterWithMaster();
-
-        net_loop_client_module.InitClient();
-        addr = net_loop_client_module.ResolveAddress(NULL);
-    }
-    else
-    {
-        //! 
-        // @category net
-        //
-        // Automatically search the local LAN for a multiplayer
-        // server and join it.
-        //
-
-        i = M_CheckParm("-autojoin");
-
-        if (i > 0)
-        {
-            addr = NET_FindLANServer();
-
-            if (addr == NULL)
-            {
-                I_Error("No server found on local LAN");
-            }
-        }
-
-        //!
-        // @arg <address>
-        // @category net
-        //
-        // Connect to a multiplayer server running on the given 
-        // address.
-        //
-        
-        i = M_CheckParmWithArgs("-connect", 1);
-
-        if (i > 0)
-        {
-            net_sdl_module.InitClient();
-            addr = net_sdl_module.ResolveAddress(myargv[i+1]);
-
-            if (addr == NULL)
-            {
-                I_Error("Unable to resolve '%s'\n", myargv[i+1]);
-            }
-        }
-    }
-
-    if (addr != NULL)
-    {
-        if (M_CheckParm("-drone") > 0)
-        {
-            connect_data->drone = true;
-        }
-
-        if (!NET_CL_Connect(addr, connect_data))
-        {
-            I_Error("D_CheckNetGame: Failed to connect to %s\n", 
-                    NET_AddrToString(addr));
-        }
-
-        printf("D_CheckNetGame: Connected to %s\n", NET_AddrToString(addr));
-
-        // Wait for game start message received from server.
-
-        NET_WaitForStart(settings);
-
-        // Read the game settings that were received.
-
-        NET_CL_GetSettings(settings);
-
-        result = true;
-    }
-
-#endif
-
-    new_sync = settings->new_sync;
-
-    if (new_sync == false)
-    {
-	printf("Syncing netgames like Vanilla Doom.\n");
-    }
-
-    return result;
-}
-
-
-//
-// D_QuitNetGame
-// Called before quitting to leave a net game
-// without hanging the other players
-//
-void D_QuitNetGame (void)
-{
-#ifdef FEATURE_MULTIPLAYER
-
-    NET_SV_Shutdown();
-    NET_CL_Disconnect();
-
-#endif
-
-}
-
-static int GetLowTic(void)
-{
-    int lowtic;
-
-    lowtic = maketic;
-
-#ifdef FEATURE_MULTIPLAYER
-    if (net_client_connected)
-    {
-        if (drone || recvtic < lowtic)
-        {
-            lowtic = recvtic;
-        }
-    }
-#endif
-
-    return lowtic;
-}
-
-static int frameon;
-static int frameskip[4];
-static int oldnettics;
-
-static void OldNetSync(void)
-{
-    unsigned int i;
-    unsigned int keyplayer = -1;
-
-    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])
-        {
-            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 <= recvtic)
-        {
-            lasttime--;
-            // printf ("-");
-        }
-
-        frameskip[frameon & 3] = oldnettics > recvtic;
-        oldnettics = maketic;
-
-        if (frameskip[0] && frameskip[1] && frameskip[2] && frameskip[3])
-        {
-            skiptics = 1;
-            // printf ("+");
-        }
-    }
-}
-
-// Returns true if there are players in the game:
-
-static boolean PlayersInGame(void)
-{
-    boolean result = false;
-    unsigned int i;
-
-    // If we are connected to a server, check if there are any players
-    // in the game.
-
-    if (net_client_connected)
-    {
-        for (i = 0; i < MAXPLAYERS; ++i)
-        {
-            result = result || playeringame[i];
-        }
-    }
-
-    // Whether single or multi-player, unless we are running as a drone,
-    // we are in the game.
-
-    if (!drone)
-    {
-        result = true;
-    }
-
-    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;
-    }
-}
-
-// 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
-//
-
-void TryRunTics (void)
-{
-    int	i;
-    int	lowtic;
-    int	entertic;
-    static int oldentertics;
-    int realtics;
-    int	availabletics;
-    int	counts;
-
-    // get real tics		
-    entertic = I_GetTime() / ticdup;
-    realtics = entertic - oldentertics;
-    oldentertics = entertic;
-    
-    // get available tics
-    NetUpdate ();
-	
-    lowtic = GetLowTic();
-
-    availabletics = lowtic - gametic/ticdup;
-    
-    // decide how many tics to run
-    
-    if (new_sync)
-    {
-	counts = availabletics;
-    }
-    else
-    {
-        // decide how many tics to run
-        if (realtics < availabletics-1)
-            counts = realtics+1;
-        else if (realtics < availabletics)
-            counts = realtics;
-        else
-            counts = availabletics;
-        
-        if (counts < 1)
-            counts = 1;
-                    
-        if (net_client_connected)
-        {
-            OldNetSync();
-        }
-    }
-
-    if (counts < 1)
-	counts = 1;
-		
-    // wait for new tics if needed
-
-    while (!PlayersInGame() || lowtic < gametic/ticdup + counts)	
-    {
-	NetUpdate ();   
-
-        lowtic = GetLowTic();
-	
-	if (lowtic < gametic/ticdup)
-	    I_Error ("TryRunTics: lowtic < gametic");
-    
-        // Don't stay in this loop forever.  The menu is still running,
-        // so return to update the screen
-
-	if (I_GetTime() / ticdup - entertic > 0)
-	{
-	    return;
-	} 
-
-        I_Sleep(1);
-    }
-    
-    // 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++)
-	{
-            if (gametic/ticdup > lowtic)
-                I_Error ("gametic>lowtic");
-
-            loop_interface->RunTic(set->cmds, set->ingame);
-	    gametic++;
-
-	    // modify command for duplicated tics
-
-            TicdupSquash(set);
-	}
-
-	NetUpdate ();	// check for new console commands
-    }
-}
-
-void D_RegisterLoopCallbacks(loop_interface_t *i)
-{
-    loop_interface = i;
-}
-
-//----------------------------------------------------------------------
-
 ticcmd_t *netcmds;
 
 // Called when a player leaves the game
@@ -761,6 +100,7 @@
 }
 
 static loop_interface_t doom_loop_interface = {
+    D_ProcessEvents,
     G_BuildTiccmd,
     RunTic,
     M_Ticker
@@ -770,13 +110,13 @@
 // Load game settings from the specified structure and 
 // set global variables.
 
-static void LoadGameSettings(net_gamesettings_t *settings)
+static void LoadGameSettings(net_gamesettings_t *settings,
+                             net_connect_data_t *connect_data)
 {
     unsigned int i;
 
     deathmatch = settings->deathmatch;
     ticdup = settings->ticdup;
-    extratics = settings->extratics;
     startepisode = settings->episode;
     startmap = settings->map;
     startskill = settings->skill;
@@ -793,7 +133,7 @@
                "because there is a client recording a Vanilla demo.\n");
     }
 
-    if (!drone)
+    if (!connect_data->drone)
     {
         consoleplayer = settings->consoleplayer;
     }
@@ -905,9 +245,6 @@
     net_connect_data_t connect_data;
     net_gamesettings_t settings;
 
-    offsetms = 0;
-    recvtic = 0;
-
     D_RegisterLoopCallbacks(&doom_loop_interface);
 
     // Call D_QuitNetGame on exit 
@@ -926,7 +263,7 @@
         D_InitSinglePlayerGame(&settings);
     }
 
-    LoadGameSettings(&settings);
+    LoadGameSettings(&settings, &connect_data);
 
     DEH_printf("startskill %i  deathmatch: %i  startmap: %i  startepisode: %i\n",
                startskill, deathmatch, startmap, startepisode);
@@ -954,6 +291,4 @@
         }
     }
 }
-
-//----------------------------------------------------------------------
 
--- a/src/doom/d_net.h
+++ b/src/doom/d_net.h
@@ -28,24 +28,7 @@
 #ifndef __D_NET__
 #define __D_NET__
 
-#include "d_player.h"
-
-extern int extratics;
-
-// Create any new ticcmds and broadcast to other players.
-void NetUpdate (void);
-
-// Broadcasts special packets to other players
-//  to notify of game exit
-void D_QuitNetGame (void);
-
-//? how many ticks to run?
-void TryRunTics (void);
-
-// Called at start of game loop to initialize timers
-void D_StartGameLoop(void);
-
-extern boolean net_cl_new_sync;
+#include "d_loop.h"
 
 #endif
 
--- a/src/doom/doomstat.h
+++ b/src/doom/doomstat.h
@@ -275,9 +275,6 @@
 extern  gamestate_t     wipegamestate;
 
 extern  int             mouseSensitivity;
-//?
-// debug flag to cancel adaptiveness
-extern  boolean         singletics;	
 
 extern  int             bodyqueslot;
 
--- a/src/doom/g_game.c
+++ b/src/doom/g_game.c
@@ -134,7 +134,6 @@
  
 int             consoleplayer;          // player taking events and displaying 
 int             displayplayer;          // view being displayed 
-int             gametic; 
 int             levelstarttic;          // gametic at level start 
 int             totalkills, totalitems, totalsecret;    // for intermission 
  
@@ -321,7 +320,7 @@
 // or reads it from the demo buffer. 
 // If recording a demo, write it out 
 // 
-void G_BuildTiccmd (ticcmd_t* cmd) 
+void G_BuildTiccmd (ticcmd_t* cmd, int maketic) 
 { 
     int		i; 
     boolean	strafe;
--- a/src/doom/g_game.h
+++ b/src/doom/g_game.h
@@ -72,7 +72,7 @@
 
 // Read current data from inputs and build a player movement command.
 
-void G_BuildTiccmd (ticcmd_t *cmd); 
+void G_BuildTiccmd (ticcmd_t *cmd, int maketic); 
 
 void G_Ticker (void);
 boolean G_Responder (event_t*	ev);