mirror of
https://github.com/ZDoom/raze-gles.git
synced 2024-12-27 20:20:40 +00:00
- continued work on main loop - added a few new entry points to the game interface.
This commit is contained in:
parent
c0ebe3e08b
commit
d49aedacea
26 changed files with 566 additions and 322 deletions
|
@ -785,6 +785,7 @@ set (PCH_SOURCES
|
|||
core/ct_chat.cpp
|
||||
core/d_net.cpp
|
||||
core/d_protocol.cpp
|
||||
core/mainloop.cpp
|
||||
core/gameconfigfile.cpp
|
||||
core/gamecvars.cpp
|
||||
core/gamecontrol.cpp
|
||||
|
|
|
@ -589,7 +589,7 @@ void ProcessFrame(void)
|
|||
ambProcess();
|
||||
viewUpdateDelirium();
|
||||
viewUpdateShake();
|
||||
sfxUpdate3DSounds();
|
||||
gi->UpdateSounds();
|
||||
if (gMe->hand == 1)
|
||||
{
|
||||
const int CHOKERATE = 8;
|
||||
|
|
|
@ -89,7 +89,8 @@ struct GameInterface : ::GameInterface
|
|||
void QuitToTitle() override;
|
||||
FString GetCoordString() override;
|
||||
ReservedSpace GetReservedScreenSpace(int viewsize) override;
|
||||
|
||||
void UpdateSounds() override;
|
||||
|
||||
GameStats getStats() override;
|
||||
};
|
||||
|
||||
|
|
|
@ -121,7 +121,7 @@ void BloodSoundEngine::CalcPosVel(int type, const void* source, const float pt[3
|
|||
}
|
||||
|
||||
|
||||
void sfxUpdate3DSounds(void)
|
||||
void GameInterface::UpdateSounds()
|
||||
{
|
||||
SoundListener listener;
|
||||
|
||||
|
|
|
@ -60,7 +60,6 @@ void sfxPlay3DSound(spritetype *pSprite, int soundId, int a3 = -1, int a4 = 0);
|
|||
void sfxPlay3DSoundCP(spritetype* pSprite, int soundId, int a3 = -1, int a4 = 0, int pitch = 0, int volume = -1);
|
||||
void sfxKill3DSound(spritetype *pSprite, int a2 = -1, int a3 = -1);
|
||||
void sfxKillAllSounds(void);
|
||||
void sfxUpdate3DSounds(void);
|
||||
void sfxSetReverb(bool toggle);
|
||||
void sfxSetReverb2(bool toggle);
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@
|
|||
CVAR(Bool, gl_scale_viewport, true, CVAR_ARCHIVE);
|
||||
|
||||
EXTERN_CVAR(Int, vid_maxfps)
|
||||
CVAR(Bool, cl_capfps, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
EXTERN_CVAR(Bool, cl_capfps)
|
||||
EXTERN_CVAR(Int, screenblocks)
|
||||
|
||||
//==========================================================================
|
||||
|
|
|
@ -51,14 +51,15 @@
|
|||
#include "i_time.h"
|
||||
#include "d_ticcmd.h"
|
||||
|
||||
extern bool pauseext;
|
||||
extern int gametic;
|
||||
|
||||
// Placeholders to make it compile.
|
||||
FILE* debugfile;
|
||||
int gametic;
|
||||
extern bool netgame;
|
||||
bool demoplayback;
|
||||
int Net_Arbitrator;
|
||||
bool playeringame[MAXPLAYERS];
|
||||
bool pauseext;
|
||||
bool singletics;
|
||||
char* startmap;
|
||||
int rngseed;
|
||||
|
@ -69,12 +70,6 @@ void D_WriteUserInfoStrings(int, uint8_t**, bool) {}
|
|||
FString GetPlayerName(int num);
|
||||
void G_BuildTiccmd(ticcmd_t*) {}
|
||||
|
||||
|
||||
|
||||
EXTERN_CVAR (Int, disableautosave)
|
||||
EXTERN_CVAR (Int, autosavecount)
|
||||
EXTERN_CVAR(Bool, cl_capfps)
|
||||
|
||||
//#define SIMULATEERRORS (RAND_MAX/3)
|
||||
#define SIMULATEERRORS 0
|
||||
|
||||
|
@ -1812,212 +1807,6 @@ void D_QuitNetGame (void)
|
|||
fclose (debugfile);
|
||||
}
|
||||
|
||||
// Forces playsim processing time to be consistent across frames.
|
||||
// This improves interpolation for frames in between tics.
|
||||
//
|
||||
// With this cvar off the mods with a high playsim processing time will appear
|
||||
// less smooth as the measured time used for interpolation will vary.
|
||||
|
||||
CVAR(Bool, r_ticstability, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
|
||||
static uint64_t stabilityticduration = 0;
|
||||
static uint64_t stabilitystarttime = 0;
|
||||
|
||||
static void TicStabilityWait()
|
||||
{
|
||||
using namespace std::chrono;
|
||||
using namespace std::this_thread;
|
||||
|
||||
if (!r_ticstability)
|
||||
return;
|
||||
|
||||
uint64_t start = duration_cast<microseconds>(steady_clock::now().time_since_epoch()).count();
|
||||
while (true)
|
||||
{
|
||||
uint64_t cur = duration_cast<microseconds>(steady_clock::now().time_since_epoch()).count();
|
||||
if (cur - start > stabilityticduration)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void TicStabilityBegin()
|
||||
{
|
||||
using namespace std::chrono;
|
||||
stabilitystarttime = duration_cast<microseconds>(steady_clock::now().time_since_epoch()).count();
|
||||
}
|
||||
|
||||
static void TicStabilityEnd()
|
||||
{
|
||||
using namespace std::chrono;
|
||||
uint64_t stabilityendtime = duration_cast<microseconds>(steady_clock::now().time_since_epoch()).count();
|
||||
stabilityticduration = std::min(stabilityendtime - stabilitystarttime, (uint64_t)1'000'000);
|
||||
}
|
||||
|
||||
//
|
||||
// TryRunTics
|
||||
//
|
||||
void TryRunTics (void)
|
||||
{
|
||||
#if 0
|
||||
int i;
|
||||
int lowtic;
|
||||
int realtics;
|
||||
int availabletics;
|
||||
int counts;
|
||||
int numplaying;
|
||||
|
||||
// If paused, do not eat more CPU time than we need, because it
|
||||
// will all be wasted anyway.
|
||||
if (pauseext)
|
||||
r_NoInterpolate = true;
|
||||
bool doWait = cl_capfps || r_NoInterpolate /*|| netgame*/;
|
||||
|
||||
// get real tics
|
||||
if (doWait)
|
||||
{
|
||||
entertic = I_WaitForTic (oldentertics);
|
||||
}
|
||||
else
|
||||
{
|
||||
entertic = I_GetTime ();
|
||||
}
|
||||
realtics = entertic - oldentertics;
|
||||
oldentertics = entertic;
|
||||
|
||||
// get available tics
|
||||
NetUpdate ();
|
||||
|
||||
if (pauseext)
|
||||
return;
|
||||
|
||||
lowtic = INT_MAX;
|
||||
numplaying = 0;
|
||||
for (i = 0; i < doomcom.numnodes; i++)
|
||||
{
|
||||
if (nodeingame[i])
|
||||
{
|
||||
numplaying++;
|
||||
if (nettics[i] < lowtic)
|
||||
lowtic = nettics[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (ticdup == 1)
|
||||
{
|
||||
availabletics = lowtic - gametic;
|
||||
}
|
||||
else
|
||||
{
|
||||
availabletics = lowtic - gametic / ticdup;
|
||||
}
|
||||
|
||||
// decide how many tics to run
|
||||
if (realtics < availabletics-1)
|
||||
counts = realtics+1;
|
||||
else if (realtics < availabletics)
|
||||
counts = realtics;
|
||||
else
|
||||
counts = availabletics;
|
||||
|
||||
// Uncapped framerate needs seprate checks
|
||||
if (counts == 0 && !doWait)
|
||||
{
|
||||
TicStabilityWait();
|
||||
|
||||
// Check possible stall conditions
|
||||
Net_CheckLastReceived(counts);
|
||||
if (realtics >= 1)
|
||||
{
|
||||
C_Ticker();
|
||||
M_Ticker();
|
||||
// Repredict the player for new buffered movement
|
||||
P_UnPredictPlayer();
|
||||
P_PredictPlayer(&players[myconnectindex]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (counts < 1)
|
||||
counts = 1;
|
||||
|
||||
if (debugfile)
|
||||
fprintf (debugfile,
|
||||
"=======real: %i avail: %i game: %i\n",
|
||||
realtics, availabletics, counts);
|
||||
|
||||
// wait for new tics if needed
|
||||
while (lowtic < gametic + counts)
|
||||
{
|
||||
NetUpdate ();
|
||||
lowtic = INT_MAX;
|
||||
|
||||
for (i = 0; i < doomcom.numnodes; i++)
|
||||
if (nodeingame[i] && nettics[i] < lowtic)
|
||||
lowtic = nettics[i];
|
||||
|
||||
lowtic = lowtic * ticdup;
|
||||
|
||||
if (lowtic < gametic)
|
||||
I_Error ("TryRunTics: lowtic < gametic");
|
||||
|
||||
// Check possible stall conditions
|
||||
Net_CheckLastReceived (counts);
|
||||
|
||||
// Update time returned by I_GetTime, but only if we are stuck in this loop
|
||||
if (lowtic < gametic + counts)
|
||||
I_SetFrameTime();
|
||||
|
||||
// don't stay in here forever -- give the menu a chance to work
|
||||
if (I_GetTime () - entertic >= 1)
|
||||
{
|
||||
C_Ticker ();
|
||||
M_Ticker ();
|
||||
// Repredict the player for new buffered movement
|
||||
P_UnPredictPlayer();
|
||||
P_PredictPlayer(&players[myconnectindex]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//Tic lowtic is high enough to process this gametic. Clear all possible waiting info
|
||||
hadlate = false;
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
players[i].waiting = false;
|
||||
lastglobalrecvtime = I_GetTime (); //Update the last time the game tic'd over
|
||||
|
||||
// run the count tics
|
||||
if (counts > 0)
|
||||
{
|
||||
P_UnPredictPlayer();
|
||||
while (counts--)
|
||||
{
|
||||
TicStabilityBegin();
|
||||
if (gametic > lowtic)
|
||||
{
|
||||
I_Error ("gametic>lowtic");
|
||||
}
|
||||
if (advancedemo)
|
||||
{
|
||||
D_DoAdvanceDemo ();
|
||||
}
|
||||
if (debugfile) fprintf (debugfile, "run tic %d\n", gametic);
|
||||
C_Ticker ();
|
||||
M_Ticker ();
|
||||
G_Ticker();
|
||||
gametic++;
|
||||
|
||||
NetUpdate (); // check for new console commands
|
||||
TicStabilityEnd();
|
||||
}
|
||||
P_PredictPlayer(&players[myconnectindex]);
|
||||
S_UpdateSounds (players[myconnectindex].camera); // move positional sounds
|
||||
}
|
||||
else
|
||||
{
|
||||
TicStabilityWait();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Net_CheckLastReceived (int counts)
|
||||
{
|
||||
|
|
|
@ -69,6 +69,9 @@ extern int nodeforplayer[MAXPLAYERS];
|
|||
|
||||
extern ticcmd_t netcmds[MAXPLAYERS][BACKUPTICS];
|
||||
extern int ticdup;
|
||||
extern bool nodeingame[MAXNETNODES]; // set false as nodes leave game
|
||||
extern bool hadlate;
|
||||
extern uint64_t lastglobalrecvtime; // Identify the last time a packet was received.
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -966,6 +966,7 @@ void app_loop()
|
|||
}
|
||||
catch (CRecoverableError& err)
|
||||
{
|
||||
gi->ErrorCleanup();
|
||||
C_FullConsole();
|
||||
Printf(TEXTCOLOR_RED "%s\n", err.what());
|
||||
}
|
||||
|
|
|
@ -93,6 +93,9 @@ struct GameInterface
|
|||
virtual ReservedSpace GetReservedScreenSpace(int viewsize) { return { 0, 0 }; }
|
||||
virtual void ResetFollowPos(bool) {}
|
||||
virtual void GetInput(InputPacket* packet) {}
|
||||
virtual void UpdateSounds() {}
|
||||
virtual void ErrorCleanup() {}
|
||||
virtual void Render() {}
|
||||
|
||||
|
||||
};
|
||||
|
|
453
source/core/mainloop.cpp
Normal file
453
source/core/mainloop.cpp
Normal file
|
@ -0,0 +1,453 @@
|
|||
/*
|
||||
** mainloop.cpp
|
||||
** Implements the main game loop
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2020 Christoph Oelckers
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
|
||||
// For TryRunTics the following applies:
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// $Id:$
|
||||
//
|
||||
// Copyright (C) 1993-1996 by id Software, Inc.
|
||||
// Copyright 1999-2016 Randy Heit
|
||||
// Copyright 2002-2020 Christoph Oelckers
|
||||
//
|
||||
// This source is available for distribution and/or modification
|
||||
// only under the terms of the DOOM Source Code License as
|
||||
// published by id Software. All rights reserved.
|
||||
//
|
||||
// The source is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
|
||||
// for more details.
|
||||
//
|
||||
// $Log:$
|
||||
//
|
||||
// DESCRIPTION:
|
||||
// DOOM Network game communication and protocol,
|
||||
// all OS independent parts.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
#include "c_cvars.h"
|
||||
#include "i_time.h"
|
||||
#include "d_net.h"
|
||||
#include "gamecontrol.h"
|
||||
#include "c_console.h"
|
||||
#include "menu.h"
|
||||
#include "i_system.h"
|
||||
#include "raze_sound.h"
|
||||
#include "raze_music.h"
|
||||
#include "vm.h"
|
||||
|
||||
|
||||
|
||||
// Forces playsim processing time to be consistent across frames.
|
||||
// This improves interpolation for frames in between tics.
|
||||
//
|
||||
// With this cvar off the mods with a high playsim processing time will appear
|
||||
// less smooth as the measured time used for interpolation will vary.
|
||||
|
||||
CVAR(Bool, r_ticstability, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
CVAR(Bool, cl_capfps, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||
|
||||
static uint64_t stabilityticduration = 0;
|
||||
static uint64_t stabilitystarttime = 0;
|
||||
|
||||
bool pauseext;
|
||||
bool r_NoInterpolate;
|
||||
int entertic;
|
||||
int oldentertics;
|
||||
int gametic;
|
||||
|
||||
|
||||
static void TicStabilityWait()
|
||||
{
|
||||
using namespace std::chrono;
|
||||
using namespace std::this_thread;
|
||||
|
||||
if (!r_ticstability)
|
||||
return;
|
||||
|
||||
uint64_t start = duration_cast<microseconds>(steady_clock::now().time_since_epoch()).count();
|
||||
while (true)
|
||||
{
|
||||
uint64_t cur = duration_cast<microseconds>(steady_clock::now().time_since_epoch()).count();
|
||||
if (cur - start > stabilityticduration)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void TicStabilityBegin()
|
||||
{
|
||||
using namespace std::chrono;
|
||||
stabilitystarttime = duration_cast<microseconds>(steady_clock::now().time_since_epoch()).count();
|
||||
}
|
||||
|
||||
static void TicStabilityEnd()
|
||||
{
|
||||
using namespace std::chrono;
|
||||
uint64_t stabilityendtime = duration_cast<microseconds>(steady_clock::now().time_since_epoch()).count();
|
||||
stabilityticduration = std::min(stabilityendtime - stabilitystarttime, (uint64_t)1'000'000);
|
||||
}
|
||||
|
||||
//
|
||||
// TryRunTics
|
||||
//
|
||||
void TryRunTics (void)
|
||||
{
|
||||
int i;
|
||||
int lowtic;
|
||||
int realtics;
|
||||
int availabletics;
|
||||
int counts;
|
||||
int numplaying;
|
||||
|
||||
// If paused, do not eat more CPU time than we need, because it
|
||||
// will all be wasted anyway.
|
||||
if (pauseext)
|
||||
r_NoInterpolate = true;
|
||||
bool doWait = cl_capfps || r_NoInterpolate /*|| netgame*/;
|
||||
|
||||
// get real tics
|
||||
if (doWait)
|
||||
{
|
||||
entertic = I_WaitForTic (oldentertics);
|
||||
}
|
||||
else
|
||||
{
|
||||
entertic = I_GetTime ();
|
||||
}
|
||||
realtics = entertic - oldentertics;
|
||||
oldentertics = entertic;
|
||||
|
||||
// get available tics
|
||||
NetUpdate ();
|
||||
|
||||
if (pauseext)
|
||||
return;
|
||||
|
||||
lowtic = INT_MAX;
|
||||
numplaying = 0;
|
||||
for (i = 0; i < doomcom.numnodes; i++)
|
||||
{
|
||||
if (nodeingame[i])
|
||||
{
|
||||
numplaying++;
|
||||
if (nettics[i] < lowtic)
|
||||
lowtic = nettics[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (ticdup == 1)
|
||||
{
|
||||
availabletics = lowtic - gametic;
|
||||
}
|
||||
else
|
||||
{
|
||||
availabletics = lowtic - gametic / ticdup;
|
||||
}
|
||||
|
||||
// decide how many tics to run
|
||||
if (realtics < availabletics-1)
|
||||
counts = realtics+1;
|
||||
else if (realtics < availabletics)
|
||||
counts = realtics;
|
||||
else
|
||||
counts = availabletics;
|
||||
|
||||
// Uncapped framerate needs seprate checks
|
||||
if (counts == 0 && !doWait)
|
||||
{
|
||||
TicStabilityWait();
|
||||
|
||||
// Check possible stall conditions
|
||||
Net_CheckLastReceived(counts);
|
||||
if (realtics >= 1)
|
||||
{
|
||||
C_Ticker();
|
||||
M_Ticker();
|
||||
// Repredict the player for new buffered movement
|
||||
#if 0
|
||||
gi->Unpredict();
|
||||
gi->Predict(myconnectindex);
|
||||
#endif
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (counts < 1)
|
||||
counts = 1;
|
||||
|
||||
// wait for new tics if needed
|
||||
while (lowtic < gametic + counts)
|
||||
{
|
||||
NetUpdate ();
|
||||
lowtic = INT_MAX;
|
||||
|
||||
for (i = 0; i < doomcom.numnodes; i++)
|
||||
if (nodeingame[i] && nettics[i] < lowtic)
|
||||
lowtic = nettics[i];
|
||||
|
||||
lowtic = lowtic * ticdup;
|
||||
|
||||
if (lowtic < gametic)
|
||||
I_Error ("TryRunTics: lowtic < gametic");
|
||||
|
||||
// Check possible stall conditions
|
||||
Net_CheckLastReceived (counts);
|
||||
|
||||
// Update time returned by I_GetTime, but only if we are stuck in this loop
|
||||
if (lowtic < gametic + counts)
|
||||
I_SetFrameTime();
|
||||
|
||||
// don't stay in here forever -- give the menu a chance to work
|
||||
if (I_GetTime () - entertic >= 1)
|
||||
{
|
||||
C_Ticker ();
|
||||
M_Ticker ();
|
||||
// Repredict the player for new buffered movement
|
||||
#if 0
|
||||
gi->Unpredict();
|
||||
gi->Predict(myconnectindex);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//Tic lowtic is high enough to process this gametic. Clear all possible waiting info
|
||||
hadlate = false;
|
||||
#if 0
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
players[i].waiting = false;
|
||||
#endif
|
||||
lastglobalrecvtime = I_GetTime (); //Update the last time the game tic'd over
|
||||
|
||||
// run the count tics
|
||||
if (counts > 0)
|
||||
{
|
||||
#if 0
|
||||
gi->Unpredict();
|
||||
#endif
|
||||
while (counts--)
|
||||
{
|
||||
TicStabilityBegin();
|
||||
if (gametic > lowtic)
|
||||
{
|
||||
I_Error ("gametic>lowtic");
|
||||
}
|
||||
#if 0
|
||||
if (advancedemo)
|
||||
{
|
||||
D_DoAdvanceDemo ();
|
||||
}
|
||||
#endif
|
||||
//if (debugfile) fprintf (debugfile, "run tic %d\n", gametic);
|
||||
C_Ticker ();
|
||||
M_Ticker ();
|
||||
//G_Ticker();
|
||||
gametic++;
|
||||
|
||||
NetUpdate (); // check for new console commands
|
||||
TicStabilityEnd();
|
||||
}
|
||||
#if 0
|
||||
gi->Predict(myconnectindex);
|
||||
#endif
|
||||
gi->UpdateSounds();
|
||||
soundEngine->UpdateSounds(I_GetTime());
|
||||
}
|
||||
else
|
||||
{
|
||||
TicStabilityWait();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// D_DoomLoop
|
||||
//
|
||||
// Manages timing and IO, calls all ?_Responder, ?_Ticker, and ?_Drawer,
|
||||
// calls I_GetTime, I_StartFrame, and I_StartTic
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void MainLoop ()
|
||||
{
|
||||
int lasttic = 0;
|
||||
|
||||
// Clamp the timer to TICRATE until the playloop has been entered.
|
||||
r_NoInterpolate = true;
|
||||
|
||||
//vid_cursor.Callback();
|
||||
|
||||
for (;;)
|
||||
{
|
||||
try
|
||||
{
|
||||
// frame syncronous IO operations
|
||||
if (gametic > lasttic)
|
||||
{
|
||||
lasttic = gametic;
|
||||
I_StartFrame ();
|
||||
}
|
||||
I_SetFrameTime();
|
||||
|
||||
TryRunTics (); // will run at least one tic
|
||||
// Update display, next frame, with current state.
|
||||
I_StartTic ();
|
||||
gi->Render();
|
||||
Mus_UpdateMusic(); // must be at the end.
|
||||
}
|
||||
catch (CRecoverableError &error)
|
||||
{
|
||||
if (error.GetMessage ())
|
||||
{
|
||||
Printf (PRINT_BOLD, "\n%s\n", error.GetMessage());
|
||||
}
|
||||
gi->ErrorCleanup();
|
||||
C_FullConsole();
|
||||
}
|
||||
catch (CVMAbortException &error)
|
||||
{
|
||||
error.MaybePrintMessage();
|
||||
Printf("%s", error.stacktrace.GetChars());
|
||||
gi->ErrorCleanup();
|
||||
C_FullConsole();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// The one and only main loop in the entire engine. Yay!
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
#if 0
|
||||
|
||||
void _TickSubsystems()
|
||||
{
|
||||
// run these on an independent timer until we got something working for the games.
|
||||
static const uint64_t tickInterval = 1'000'000'000 / 30;
|
||||
static uint64_t nexttick = 0;
|
||||
|
||||
auto nowtick = I_nsTime();
|
||||
if (nexttick == 0) nexttick = nowtick;
|
||||
int cnt = 0;
|
||||
while (nexttick <= nowtick && cnt < 5)
|
||||
{
|
||||
nexttick += tickInterval;
|
||||
C_Ticker();
|
||||
M_Ticker();
|
||||
C_RunDelayedCommands();
|
||||
cnt++;
|
||||
}
|
||||
// If this took too long the engine was most likely suspended so recalibrate the timer.
|
||||
// Perfect precision is not needed here.
|
||||
if (cnt == 5) nexttick = nowtick + tickInterval;
|
||||
}
|
||||
|
||||
static void _updatePauseStatus()
|
||||
{
|
||||
// This must go through the network in multiplayer games.
|
||||
if (M_Active() || System_WantGuiCapture())
|
||||
{
|
||||
paused = 1;
|
||||
}
|
||||
else if (!M_Active() || !System_WantGuiCapture())
|
||||
{
|
||||
if (!pausedWithKey)
|
||||
{
|
||||
paused = 0;
|
||||
}
|
||||
|
||||
if (sendPause)
|
||||
{
|
||||
sendPause = false;
|
||||
paused = pausedWithKey ? 0 : 2;
|
||||
pausedWithKey = !!paused;
|
||||
}
|
||||
}
|
||||
|
||||
paused ? S_PauseSound(!pausedWithKey, !paused) : S_ResumeSound(paused);
|
||||
}
|
||||
|
||||
|
||||
void _app_loop()
|
||||
{
|
||||
gamestate = GS_STARTUP;
|
||||
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
I_SetFrameTime();
|
||||
TickSubsystems();
|
||||
twod->SetSize(screen->GetWidth(), screen->GetHeight());
|
||||
twodpsp.SetSize(screen->GetWidth(), screen->GetHeight());
|
||||
|
||||
handleevents();
|
||||
updatePauseStatus();
|
||||
D_ProcessEvents();
|
||||
|
||||
gi->RunGameFrame();
|
||||
|
||||
// Draw overlay elements to the 2D drawer
|
||||
FStat::PrintStat(twod);
|
||||
CT_Drawer();
|
||||
C_DrawConsole();
|
||||
M_Drawer();
|
||||
|
||||
// Handle the final 2D overlays.
|
||||
if (gamestate == GS_LEVEL) DrawFullscreenBlends();
|
||||
DrawRateStuff();
|
||||
|
||||
|
||||
videoShowFrame(0);
|
||||
videoSetBrightness(0); // immediately reset this so that the value doesn't stick around in the backend.
|
||||
}
|
||||
catch (CRecoverableError& err)
|
||||
{
|
||||
C_FullConsole();
|
||||
Printf(TEXTCOLOR_RED "%s\n", err.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
|
@ -251,6 +251,8 @@ struct GameInterface : ::GameInterface
|
|||
bool CanSave() override;
|
||||
ReservedSpace GetReservedScreenSpace(int viewsize) override { return { 0, 24 }; }
|
||||
void QuitToTitle() override;
|
||||
void UpdateSounds() override;
|
||||
void ErrorCleanup() override;
|
||||
|
||||
FString statFPS() override;
|
||||
::GameStats getStats() override;
|
||||
|
|
|
@ -256,7 +256,7 @@ void GameLoop()
|
|||
{
|
||||
GameTicker();
|
||||
PlayerInterruptKeys(true);
|
||||
UpdateSounds();
|
||||
gi->UpdateSounds();
|
||||
CheckKeys2();
|
||||
}
|
||||
|
||||
|
@ -264,55 +264,51 @@ void GameLoop()
|
|||
void GameInterface::RunGameFrame()
|
||||
{
|
||||
again:
|
||||
try
|
||||
CheckProgression();
|
||||
switch (gamestate)
|
||||
{
|
||||
CheckProgression();
|
||||
switch (gamestate)
|
||||
{
|
||||
default:
|
||||
case GS_STARTUP:
|
||||
resettiming();
|
||||
GameAction = -1;
|
||||
EndLevel = false;
|
||||
|
||||
if (userConfig.CommandMap.IsNotEmpty())
|
||||
{
|
||||
auto map = FindMapByName(userConfig.CommandMap);
|
||||
if (map) GameAction = map->levelNumber;
|
||||
userConfig.CommandMap = "";
|
||||
goto again;
|
||||
}
|
||||
else
|
||||
{
|
||||
DoTitle([](bool) { startmainmenu(); });
|
||||
}
|
||||
break;
|
||||
|
||||
case GS_MENUSCREEN:
|
||||
case GS_FULLCONSOLE:
|
||||
drawmenubackground();
|
||||
break;
|
||||
|
||||
case GS_LEVEL:
|
||||
GameLoop();
|
||||
GameDisplay();
|
||||
break;
|
||||
|
||||
case GS_INTERMISSION:
|
||||
case GS_INTRO:
|
||||
RunScreenJobFrame(); // This handles continuation through its completion callback.
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
catch (CRecoverableError&)
|
||||
{
|
||||
// Clear all progression sensitive variables here.
|
||||
default:
|
||||
case GS_STARTUP:
|
||||
resettiming();
|
||||
GameAction = -1;
|
||||
EndLevel = false;
|
||||
throw;
|
||||
}
|
||||
|
||||
if (userConfig.CommandMap.IsNotEmpty())
|
||||
{
|
||||
auto map = FindMapByName(userConfig.CommandMap);
|
||||
if (map) GameAction = map->levelNumber;
|
||||
userConfig.CommandMap = "";
|
||||
goto again;
|
||||
}
|
||||
else
|
||||
{
|
||||
DoTitle([](bool) { startmainmenu(); });
|
||||
}
|
||||
break;
|
||||
|
||||
case GS_MENUSCREEN:
|
||||
case GS_FULLCONSOLE:
|
||||
drawmenubackground();
|
||||
break;
|
||||
|
||||
case GS_LEVEL:
|
||||
GameLoop();
|
||||
GameDisplay();
|
||||
break;
|
||||
|
||||
case GS_INTERMISSION:
|
||||
case GS_INTRO:
|
||||
RunScreenJobFrame(); // This handles continuation through its completion callback.
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void GameInterface::ErrorCleanup()
|
||||
{
|
||||
// Clear all progression sensitive variables here.
|
||||
GameAction = -1;
|
||||
EndLevel = false;
|
||||
}
|
||||
|
||||
END_PS_NS
|
||||
|
|
|
@ -490,7 +490,7 @@ void EXSoundEngine::CalcPosVel(int type, const void* source, const float pt[3],
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void UpdateSounds()
|
||||
void GameInterface::UpdateSounds()
|
||||
{
|
||||
if (nFreeze)
|
||||
return;
|
||||
|
|
|
@ -117,7 +117,6 @@ extern short nCreepyTimer;
|
|||
extern short StaticSound[];
|
||||
|
||||
|
||||
void UpdateSounds();
|
||||
void UpdateCreepySounds();
|
||||
|
||||
void InitFX();
|
||||
|
|
|
@ -293,7 +293,7 @@ void GameInterface::StartGame(FNewGameStartup& gs)
|
|||
|
||||
while (S_CheckSoundPlaying(skillsound))
|
||||
{
|
||||
S_Update();
|
||||
gi->UpdateSounds();
|
||||
soundEngine->UpdateSounds(I_GetTime());
|
||||
I_GetEvent();
|
||||
}
|
||||
|
|
|
@ -58,6 +58,7 @@ struct GameInterface : public ::GameInterface
|
|||
void DrawPlayerSprite(const DVector2& origin, bool onteam) override;
|
||||
void ResetFollowPos(bool message) override;
|
||||
void GetInput(InputPacket* packet) override;
|
||||
void UpdateSounds() override;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -331,7 +331,7 @@ void GameTicker()
|
|||
}
|
||||
|
||||
nonsharedkeys();
|
||||
S_Update();
|
||||
gi->UpdateSounds();
|
||||
drawtime.Reset();
|
||||
drawtime.Clock();
|
||||
videoSetBrightness(thunder_brightness);
|
||||
|
|
|
@ -318,7 +318,7 @@ void DukeSoundEngine::CalcPosVel(int type, const void* source, const float pt[3]
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void S_Update(void)
|
||||
void GameInterface::UpdateSounds(void)
|
||||
{
|
||||
SoundListener listener;
|
||||
vec3_t* c;
|
||||
|
|
|
@ -36,7 +36,6 @@ enum esound_t
|
|||
};
|
||||
|
||||
void S_InitSound();
|
||||
void S_Update(void);
|
||||
void S_CacheAllSounds(void);
|
||||
int S_DefineSound(unsigned index, const char* filename, int ps, int pe, int pr, int m, int vo, float vol);
|
||||
|
||||
|
|
|
@ -230,7 +230,7 @@ void GameInterface::StartGame(FNewGameStartup& gs)
|
|||
|
||||
while (soundEngine->IsSourcePlayingSomething(SOURCE_None, nullptr, CHAN_VOICE))
|
||||
{
|
||||
DoUpdateSounds();
|
||||
gi->UpdateSounds();
|
||||
soundEngine->UpdateSounds(I_GetTime());
|
||||
I_GetEvent();
|
||||
}
|
||||
|
|
|
@ -767,59 +767,55 @@ void GameTicker(void)
|
|||
|
||||
void GameInterface::RunGameFrame()
|
||||
{
|
||||
try
|
||||
// if the menu initiazed a new game or loaded a savegame, switch to play mode.
|
||||
if (SavegameLoaded || NextLevel) gamestate = GS_LEVEL;
|
||||
gi->UpdateSounds();
|
||||
switch (gamestate)
|
||||
{
|
||||
// if the menu initiazed a new game or loaded a savegame, switch to play mode.
|
||||
if (SavegameLoaded || NextLevel) gamestate = GS_LEVEL;
|
||||
DoUpdateSounds();
|
||||
switch (gamestate)
|
||||
default:
|
||||
case GS_STARTUP:
|
||||
I_ResetTime();
|
||||
lastTic = -1;
|
||||
ogameclock = gameclock = 0;
|
||||
|
||||
if (userConfig.CommandMap.IsNotEmpty())
|
||||
{
|
||||
default:
|
||||
case GS_STARTUP:
|
||||
I_ResetTime();
|
||||
lastTic = -1;
|
||||
ogameclock = gameclock = 0;
|
||||
|
||||
if (userConfig.CommandMap.IsNotEmpty())
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!userConfig.nologo) Logo([](bool) { StartMenu(); });
|
||||
else StartMenu();
|
||||
}
|
||||
break;
|
||||
|
||||
case GS_MENUSCREEN:
|
||||
case GS_FULLCONSOLE:
|
||||
DrawMenuLevelScreen();
|
||||
break;
|
||||
|
||||
case GS_LEVEL:
|
||||
GameTicker();
|
||||
break;
|
||||
|
||||
case GS_INTERMISSION:
|
||||
case GS_INTRO:
|
||||
RunScreenJobFrame(); // This handles continuation through its completion callback.
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
catch (CRecoverableError&)
|
||||
{
|
||||
// Make sure we do not leave the game in an unstable state
|
||||
TerminateLevel();
|
||||
NextLevel = nullptr;
|
||||
SavegameLoaded = false;
|
||||
ExitLevel = false;
|
||||
FinishAnim = 0;
|
||||
FinishedLevel = false;
|
||||
throw;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!userConfig.nologo) Logo([](bool) { StartMenu(); });
|
||||
else StartMenu();
|
||||
}
|
||||
break;
|
||||
|
||||
case GS_MENUSCREEN:
|
||||
case GS_FULLCONSOLE:
|
||||
DrawMenuLevelScreen();
|
||||
break;
|
||||
|
||||
case GS_LEVEL:
|
||||
GameTicker();
|
||||
break;
|
||||
|
||||
case GS_INTERMISSION:
|
||||
case GS_INTRO:
|
||||
RunScreenJobFrame(); // This handles continuation through its completion callback.
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GameInterface::ErrorCleanup()
|
||||
{
|
||||
// Make sure we do not leave the game in an unstable state
|
||||
TerminateLevel();
|
||||
NextLevel = nullptr;
|
||||
SavegameLoaded = false;
|
||||
ExitLevel = false;
|
||||
FinishAnim = 0;
|
||||
FinishedLevel = false;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
|
|
|
@ -2259,6 +2259,8 @@ struct GameInterface : ::GameInterface
|
|||
ReservedSpace GetReservedScreenSpace(int viewsize) override;
|
||||
void QuitToTitle() override;
|
||||
void ResetFollowPos(bool message) override;
|
||||
void UpdateSounds() override;
|
||||
void ErrorCleanup() override;
|
||||
|
||||
FString statFPS() override;
|
||||
GameStats getStats() override;
|
||||
|
|
|
@ -7727,7 +7727,7 @@ domovethings(void)
|
|||
MultiPlayLimits();
|
||||
|
||||
//if (MoveSkip8 == 0) // 8=5x 4=10x, 2=20x, 0=40x per second
|
||||
DoUpdateSounds();
|
||||
gi->UpdateSounds();
|
||||
|
||||
CorrectPrediction(movefifoplc - 1);
|
||||
|
||||
|
|
|
@ -585,7 +585,7 @@ void SWSoundEngine::CalcPosVel(int type, const void* source, const float pt[3],
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void DoUpdateSounds(void)
|
||||
void GameInterface::UpdateSounds(void)
|
||||
{
|
||||
PLAYERp pp = Player + screenpeek;
|
||||
SoundListener listener;
|
||||
|
|
|
@ -71,7 +71,6 @@ struct ambientstruct;
|
|||
typedef struct ambientstruct AMB_INFO, *AMB_INFOp;
|
||||
|
||||
|
||||
void DoUpdateSounds(void);
|
||||
void Terminate3DSounds(void);
|
||||
|
||||
void Set3DSoundOwner(short spritenum);
|
||||
|
|
Loading…
Reference in a new issue