diff options
author | Simon Howard | 2011-10-13 01:15:33 +0000 |
---|---|---|
committer | Simon Howard | 2011-10-13 01:15:33 +0000 |
commit | 687ab6c9a481ffcec476fce2add35b7ae12eee48 (patch) | |
tree | 7caef2504005c7accdc3276152c40cab106f7c77 /src | |
parent | 460c3748565ba1f0fee9e39fd33e76436c6ddc78 (diff) | |
download | chocolate-doom-687ab6c9a481ffcec476fce2add35b7ae12eee48.tar.gz chocolate-doom-687ab6c9a481ffcec476fce2add35b7ae12eee48.tar.bz2 chocolate-doom-687ab6c9a481ffcec476fce2add35b7ae12eee48.zip |
Split out common main loop code into separate file, d_loop.c.
Subversion-branch: /branches/v2-branch
Subversion-revision: 2413
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/d_loop.c | 751 | ||||
-rw-r--r-- | src/d_loop.h | 76 | ||||
-rw-r--r-- | src/doom/d_main.c | 32 | ||||
-rw-r--r-- | src/doom/d_net.c | 677 | ||||
-rw-r--r-- | src/doom/d_net.h | 19 | ||||
-rw-r--r-- | src/doom/doomstat.h | 3 | ||||
-rw-r--r-- | src/doom/g_game.c | 3 | ||||
-rw-r--r-- | src/doom/g_game.h | 2 |
9 files changed, 842 insertions, 723 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 1bf6e2c6..6818dbaa 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -144,9 +144,11 @@ EXTRA_LIBS = \ 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 diff --git a/src/d_loop.c b/src/d_loop.c new file mode 100644 index 00000000..865ade9d --- /dev/null +++ b/src/d_loop.c @@ -0,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; +} + diff --git a/src/d_loop.h b/src/d_loop.h new file mode 100644 index 00000000..83376ea7 --- /dev/null +++ b/src/d_loop.h @@ -0,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 + diff --git a/src/doom/d_main.c b/src/doom/d_main.c index 2784c26d..c2fee76a 100644 --- a/src/doom/d_main.c +++ b/src/doom/d_main.c @@ -107,9 +107,6 @@ boolean nomonsters; // checkparm of -nomonsters 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 @@ int show_endoom = 1; void D_CheckNetGame (void); -void D_ProcessEvents (void); -void G_BuildTiccmd (ticcmd_t* cmd); void D_DoAdvanceDemo (void); @@ -442,29 +437,10 @@ void D_DoomLoop (void) while (1) { // frame syncronous IO operations - I_StartFrame (); - - // process one or more tics - if (singletics) - { - static ticcmd_t cmds[MAXPLAYERS]; - - 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 - } - + I_StartFrame (); + + TryRunTics (); // will run at least one tic + S_UpdateSounds (players[consoleplayer].mo);// move positional sounds // Update display, next frame, with current state. diff --git a/src/doom/d_net.c b/src/doom/d_net.c index 68a804aa..fc804ea3 100644 --- a/src/doom/d_net.c +++ b/src/doom/d_net.c @@ -41,668 +41,7 @@ #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" - -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; -} - -//---------------------------------------------------------------------- +#include "d_loop.h" ticcmd_t *netcmds; @@ -761,6 +100,7 @@ static void RunTic(ticcmd_t *cmds, boolean *ingame) } static loop_interface_t doom_loop_interface = { + D_ProcessEvents, G_BuildTiccmd, RunTic, M_Ticker @@ -770,13 +110,13 @@ static loop_interface_t doom_loop_interface = { // 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 @@ static void LoadGameSettings(net_gamesettings_t *settings) "because there is a client recording a Vanilla demo.\n"); } - if (!drone) + if (!connect_data->drone) { consoleplayer = settings->consoleplayer; } @@ -905,9 +245,6 @@ void D_CheckNetGame (void) 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 @@ void D_CheckNetGame (void) D_InitSinglePlayerGame(&settings); } - LoadGameSettings(&settings); + LoadGameSettings(&settings, &connect_data); DEH_printf("startskill %i deathmatch: %i startmap: %i startepisode: %i\n", startskill, deathmatch, startmap, startepisode); @@ -955,5 +292,3 @@ void D_CheckNetGame (void) } } -//---------------------------------------------------------------------- - diff --git a/src/doom/d_net.h b/src/doom/d_net.h index a3c1a43c..fe64e286 100644 --- 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 diff --git a/src/doom/doomstat.h b/src/doom/doomstat.h index b0cff548..8b430395 100644 --- a/src/doom/doomstat.h +++ b/src/doom/doomstat.h @@ -275,9 +275,6 @@ extern boolean precache; extern gamestate_t wipegamestate; extern int mouseSensitivity; -//? -// debug flag to cancel adaptiveness -extern boolean singletics; extern int bodyqueslot; diff --git a/src/doom/g_game.c b/src/doom/g_game.c index 433e35e3..3c9eba62 100644 --- a/src/doom/g_game.c +++ b/src/doom/g_game.c @@ -134,7 +134,6 @@ boolean turbodetected[MAXPLAYERS]; 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 @@ static int G_NextWeapon(int direction) // 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; diff --git a/src/doom/g_game.h b/src/doom/g_game.h index 8cf5b068..46c80bd8 100644 --- a/src/doom/g_game.h +++ b/src/doom/g_game.h @@ -72,7 +72,7 @@ void G_WorldDone (void); // 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); |