From e50368114dc9a687cf3d15156cc006b5ac223c91 Mon Sep 17 00:00:00 2001 From: Cyp Date: Sun, 11 Dec 2011 15:52:39 +0100 Subject: [PATCH] Allow multiple logical updates per rendered frame. Allows maintaining game speed when the GPU can't keep up. --- lib/gamelib/gtime.cpp | 19 ++++++++++++++----- src/keybind.cpp | 7 +++++-- src/loop.cpp | 31 ++++++++++++++++++++----------- 3 files changed, 39 insertions(+), 18 deletions(-) diff --git a/lib/gamelib/gtime.cpp b/lib/gamelib/gtime.cpp index 08fc75c02..c09405ad9 100644 --- a/lib/gamelib/gtime.cpp +++ b/lib/gamelib/gtime.cpp @@ -32,6 +32,10 @@ #include +// Maximum seconds per frame. +// If not reaching the goal, force graphics updates, even if we aren't doing enough game state updates to maintain game speed. +#define MAXIMUM_SPF 1/4 + /* See header file for documentation */ UDWORD gameTime = 0, deltaGameTime = 0, graphicsTime = 0, deltaGraphicsTime = 0, realTime = 0, deltaRealTime = 0; float graphicsTimeFraction = 0.0, realTimeFraction = 0.0; @@ -188,10 +192,10 @@ void gameTimeUpdate() { unsigned player; - // Pause time, since we are waiting GAME_GAME_TIME from other players. - scaledCurrTime = graphicsTime; + // Pause time at current game time, since we are waiting GAME_GAME_TIME from other players. + scaledCurrTime = gameTime; baseTime = currTime; - timeOffset = graphicsTime; + timeOffset = gameTime; debug(LOG_SYNC, "Waiting for other players. gameTime = %u, player times are {%s}", gameTime, listToString("%u", ", ", gameQueueTime, gameQueueTime + game.maxPlayers).c_str()); mayUpdate = false; @@ -212,10 +216,10 @@ void gameTimeUpdate() // Adjust deltas. if (scaledCurrTime >= gameTime && mayUpdate) { - if (scaledCurrTime > gameTime + GAME_TICKS_PER_UPDATE) + if (scaledCurrTime > gameTime + GAME_TICKS_PER_SEC*MAXIMUM_SPF) { // Game isn't updating fast enough... - uint32_t slideBack = deltaGraphicsTime - GAME_TICKS_PER_UPDATE; + uint32_t slideBack = deltaGraphicsTime - GAME_TICKS_PER_SEC*MAXIMUM_SPF; baseTime += slideBack / modifier; // adjust the addition to base time deltaGraphicsTime -= slideBack; } @@ -235,6 +239,11 @@ void gameTimeUpdate() deltaGameTime = 0; } + if (deltaGameTime != 0) + { + deltaGraphicsTime = 0; // Don't update graphics until game state is updated. + } + // Store the game and graphics times gameTime += deltaGameTime; graphicsTime += deltaGraphicsTime; diff --git a/src/keybind.cpp b/src/keybind.cpp index 334572295..ba41ee133 100644 --- a/src/keybind.cpp +++ b/src/keybind.cpp @@ -2575,9 +2575,12 @@ float available_speed[] = { 5.f / 2.f, // n 3.f / 1.f, // n 10.f / 1.f, // n - 20.f / 1.f // n + 20.f / 1.f, // n + 30.f / 1.f, // n + 60.f / 1.f, // n + 100.f / 1.f, // n }; -unsigned int nb_available_speeds = 12; +unsigned int nb_available_speeds = ARRAY_SIZE(available_speed); void kf_SpeedUp( void ) { diff --git a/src/loop.cpp b/src/loop.cpp index f35cd6658..51455874d 100644 --- a/src/loop.cpp +++ b/src/loop.cpp @@ -671,25 +671,34 @@ static void gameStateUpdate() /* The main game loop */ GAMECODE gameLoop(void) { - bool gameTicked; // true iff we are doing a logical update. static uint32_t lastFlushTime = 0; - // Receive NET_BLAH messages. - // Receive GAME_BLAH messages, and if it's time, process exactly as many GAME_BLAH messages as required to be able to tick the gameTime. - recvMessage(); - - // Update gameTime and graphicsTime, and corresponding deltas. Note that gameTime and graphicsTime pause, if we aren't getting our GAME_GAME_TIME messages. - gameTimeUpdate(); - gameTicked = deltaGameTime != 0; - - if (gameTicked) + bool didTick = false; + while (true) { + // Receive NET_BLAH messages. + // Receive GAME_BLAH messages, and if it's time, process exactly as many GAME_BLAH messages as required to be able to tick the gameTime. + recvMessage(); + + // Update gameTime and graphicsTime, and corresponding deltas. Note that gameTime and graphicsTime pause, if we aren't getting our GAME_GAME_TIME messages. + gameTimeUpdate(); + + if (deltaGameTime == 0) + { + break; // Not doing a game state update. + } + didTick = true; + ASSERT(!paused && !gameUpdatePaused() && !editPaused(), "Nonsensical pause values."); + syncDebug("Begin game state update, gameTime = %d", gameTime); gameStateUpdate(); + syncDebug("End game state update, gameTime = %d", gameTime); + + ASSERT(deltaGraphicsTime == 0, "Shouldn't update graphics and game state at once."); } - if (gameTicked || realTime - lastFlushTime < 400u) + if (didTick || realTime - lastFlushTime < 400u) { lastFlushTime = realTime; NETflush(); // Make sure the game time tick message is really sent over the network, and that we aren't waiting too long to send data.