ref: 687ab6c9a481ffcec476fce2add35b7ae12eee48
parent: 460c3748565ba1f0fee9e39fd33e76436c6ddc78
author: Simon Howard <fraggle@gmail.com>
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);