From 77f9bded9e8ab7de1551e714fe4fa3a541e1d213 Mon Sep 17 00:00:00 2001 From: obligaron Date: Mon, 9 Aug 2021 20:12:25 +0200 Subject: [PATCH] Introduce demo namespace --- CMakeLists.txt | 1 + Source/diablo.cpp | 52 +++---- Source/diablo.h | 3 - Source/dx.cpp | 3 +- Source/engine/demomode.cpp | 288 ++++++++++++++++++++++++++++++++++++ Source/engine/demomode.h | 31 ++++ Source/menu.cpp | 8 +- Source/miniwin/miniwin.h | 22 +-- Source/miniwin/misc_msg.cpp | 197 ++---------------------- Source/movie.cpp | 3 +- Source/nthread.cpp | 3 +- Source/options.cpp | 3 +- Source/utils/display.cpp | 5 +- 13 files changed, 366 insertions(+), 253 deletions(-) create mode 100644 Source/engine/demomode.cpp create mode 100644 Source/engine/demomode.h diff --git a/CMakeLists.txt b/CMakeLists.txt index d94ca9579..484400bf8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -397,6 +397,7 @@ set(libdevilutionx_SRCS Source/controls/touch.cpp Source/controls/keymapper.cpp Source/engine/animationinfo.cpp + Source/engine/demomode.cpp Source/engine/load_cel.cpp Source/engine/load_file.cpp Source/engine/random.cpp diff --git a/Source/diablo.cpp b/Source/diablo.cpp index 0cac6c3be..f2217ef27 100644 --- a/Source/diablo.cpp +++ b/Source/diablo.cpp @@ -28,6 +28,7 @@ #include "dx.h" #include "encrypt.h" #include "engine/cel_sprite.hpp" +#include "engine/demomode.h" #include "engine/load_cel.hpp" #include "engine/load_file.hpp" #include "engine/random.hpp" @@ -97,9 +98,6 @@ std::array quickSpellActionIndexes; bool gbForceWindowed = false; bool leveldebug = false; -int recordDemo = -1; -bool demoMode = false; -bool timedemo = false; #ifdef _DEBUG bool monstdebug = false; _monster_id DebugMonsters[10]; @@ -784,9 +782,10 @@ void GameEventHandler(uint32_t uMsg, int32_t wParam, int32_t lParam) void RunGameLoop(interface_mode uMsg) { + demo::NotifyGameLoopStart(); + WNDPROC saveProc; tagMSG msg; - int startTime; nthread_ignore_mutex(true); StartGame(uMsg); @@ -808,11 +807,6 @@ void RunGameLoop(interface_mode uMsg) unsigned run_game_iteration = 0; #endif - int logicTick = 0; - - if (timedemo) - startTime = SDL_GetTicks(); - while (gbRunGame) { while (FetchMessage(&msg)) { if (msg.message == DVL_WM_QUIT) { @@ -828,10 +822,10 @@ void RunGameLoop(interface_mode uMsg) bool drawGame = true; bool processInput = true; - bool runGameLoop = demoMode ? GetDemoRunGameLoop(drawGame, processInput) : nthread_has_500ms_passed(); + bool runGameLoop = demo::IsRunning() ? demo::GetRunGameLoop(drawGame, processInput) : nthread_has_500ms_passed(); + if (demo::IsRecording()) + demo::RecordGameLoopResult(runGameLoop); if (!runGameLoop) { - if (recordDemo != -1) - demoRecording << static_cast(DemoMsgType::Rendering) << "," << gfProgressToNextGameTick << "\n"; if (processInput) ProcessInput(); if (!drawGame) @@ -840,27 +834,20 @@ void RunGameLoop(interface_mode uMsg) DrawAndBlit(); continue; } - if (recordDemo != -1) - demoRecording << static_cast(DemoMsgType::GameTick) << "," << gfProgressToNextGameTick << "\n"; + diablo_color_cyc_logic(); multi_process_network_packets(); game_loop(gbGameLoopStartup); gbGameLoopStartup = false; if (drawGame) DrawAndBlit(); - logicTick++; #ifdef GPERF_HEAP_FIRST_GAME_ITERATION if (run_game_iteration++ == 0) HeapProfilerDump("first_game_iteration"); #endif } - if (timedemo) { - float secounds = (SDL_GetTicks() - startTime) / 1000.0; - SDL_Log("%d frames, %.2f seconds: %.1f fps", logicTick, secounds, logicTick / secounds); - gbRunGameResult = false; - gbRunGame = false; - } + demo::NotifyGameLoopEnd(); if (gbIsMultiplayer) { pfile_write_hero(/*writeGameData=*/false, /*clearTables=*/true); @@ -922,6 +909,9 @@ void RunGameLoop(interface_mode uMsg) void DiabloParseFlags(int argc, char **argv) { + bool timedemo = false; + int demoNumber = -1; + int recordNumber = -1; for (int i = 1; i < argc; i++) { if (strcasecmp("-h", argv[i]) == 0 || strcasecmp("--help", argv[i]) == 0) { PrintHelpAndExit(); @@ -933,15 +923,12 @@ void DiabloParseFlags(int argc, char **argv) } else if (strcasecmp("--save-dir", argv[i]) == 0) { paths::SetPrefPath(argv[++i]); } else if (strcasecmp("--demo", argv[i]) == 0) { - demoMode = true; - if (!LoadDemoMessages(SDL_atoi(argv[++i]))) { - SDL_Log("Unable to load demo file"); - diablo_quit(1); - } + demoNumber = SDL_atoi(argv[++i]); + gbShowIntro = false; } else if (strcasecmp("--timedemo", argv[i]) == 0) { timedemo = true; } else if (strcasecmp("--record", argv[i]) == 0) { - recordDemo = SDL_atoi(argv[++i]); + recordNumber = SDL_atoi(argv[++i]); } else if (strcasecmp("--config-dir", argv[i]) == 0) { paths::SetConfigPath(argv[++i]); } else if (strcasecmp("--lang-dir", argv[i]) == 0) { @@ -1002,6 +989,11 @@ void DiabloParseFlags(int argc, char **argv) PrintHelpAndExit(); } } + + if (demoNumber != -1) + demo::InitPlayBack(demoNumber, timedemo); + if (recordNumber != -1) + demo::InitRecording(recordNumber); } void DiabloInitScreen() @@ -1096,10 +1088,8 @@ void DiabloDeinit() { FreeItemGFX(); - if (sbWasOptionsLoaded && !demoMode) + if (sbWasOptionsLoaded && !demo::IsRunning()) SaveOptions(); - if (demoRecording.is_open()) - demoRecording.close(); if (was_snd_init) effects_cleanup_sfx(); #ifndef NOSOUND @@ -2198,7 +2188,7 @@ void game_loop(bool bStartup) TimeoutCursor(false); GameLogic(); - if (!gbRunGame || !gbIsMultiplayer || demoMode || recordDemo != -1 || !nthread_has_500ms_passed()) + if (!gbRunGame || !gbIsMultiplayer || demo::IsRunning() || demo::IsRecording() || !nthread_has_500ms_passed()) break; } } diff --git a/Source/diablo.h b/Source/diablo.h index bfc44f60e..e7a8698cf 100644 --- a/Source/diablo.h +++ b/Source/diablo.h @@ -102,9 +102,6 @@ void diablo_color_cyc_logic(); extern Keymapper keymapper; extern bool gbForceWindowed; extern bool leveldebug; -extern int recordDemo; -extern bool demoMode; -extern bool timedemo; #ifdef _DEBUG extern bool monstdebug; extern _monster_id DebugMonsters[10]; diff --git a/Source/dx.cpp b/Source/dx.cpp index ffab56794..75ca90a5d 100644 --- a/Source/dx.cpp +++ b/Source/dx.cpp @@ -7,6 +7,7 @@ #include +#include "engine/demomode.h" #include "engine.h" #include "options.h" #include "storm/storm.h" @@ -333,7 +334,7 @@ void RenderPresent() } SDL_RenderPresent(renderer); - if (!sgOptions.Graphics.bVSync && !timedemo) { + if (!sgOptions.Graphics.bVSync && !demo::IsTimedemo()) { LimitFrameRate(); } } else { diff --git a/Source/engine/demomode.cpp b/Source/engine/demomode.cpp new file mode 100644 index 000000000..ed7ab7f27 --- /dev/null +++ b/Source/engine/demomode.cpp @@ -0,0 +1,288 @@ +/** + * @file animationinfo.h + * + * Contains most of the the demomode specific logic + */ + +#include +#include +#include +#include + +#include "demomode.h" +#include "utils/display.h" +#include "utils/paths.h" +#include "menu.h" +#include "options.h" +#include "nthread.h" +#include "pfile.h" + +namespace devilution { + +namespace { + +enum class DemoMsgType { + GameTick = 0, + Rendering = 1, + Message = 2, +}; + +struct demoMsg { + DemoMsgType type; + uint32_t message; + int32_t wParam; + int32_t lParam; + float progressToNextGameTick; +}; + +int DemoNumber = -1; +bool Timedemo = false; +int RecordNumber = -1; + +std::ofstream DemoRecording; +std::deque Demo_Message_Queue; +uint32_t DemoModeLastTick = 0; + +int LogicTick = 0; +int StartTime = 0; + +void PumpDemoMessage(DemoMsgType demoMsgType, uint32_t message, int32_t wParam, int32_t lParam, float progressToNextGameTick) +{ + demoMsg msg; + msg.type = demoMsgType; + msg.message = message; + msg.wParam = wParam; + msg.lParam = lParam; + msg.progressToNextGameTick = progressToNextGameTick; + + Demo_Message_Queue.push_back(msg); +} + +bool LoadDemoMessages(int i) +{ + std::ifstream demofile; + char demoFilename[16]; + snprintf(demoFilename, 15, "demo_%d.dmo", i); + demofile.open(paths::PrefPath() + demoFilename); + if (!demofile.is_open()) { + return false; + } + + std::string line; + std::getline(demofile, line); + std::stringstream header(line); + + std::string number; + std::getline(header, number, ','); // Demo version + if (std::stoi(number) != 0) { + return false; + } + + std::getline(header, number, ','); + gSaveNumber = std::stoi(number); + + std::getline(header, number, ','); + uint32_t width = std::stoi(number); + sgOptions.Graphics.nWidth = width; + + std::getline(header, number, ','); + uint32_t height = std::stoi(number); + sgOptions.Graphics.nHeight = height; + + while (std::getline(demofile, line)) { + std::stringstream command(line); + + std::getline(command, number, ','); + int typeNum = std::stoi(number); + auto type = static_cast(typeNum); + + std::getline(command, number, ','); + float progressToNextGameTick = std::stof(number); + + switch (type) { + case DemoMsgType::Message: { + std::getline(command, number, ','); + uint32_t message = std::stoi(number); + std::getline(command, number, ','); + int32_t wParam = std::stoi(number); + std::getline(command, number, ','); + int32_t lParam = std::stoi(number); + PumpDemoMessage(type, message, wParam, lParam, progressToNextGameTick); + break; + } + default: + PumpDemoMessage(type, 0, 0, 0, progressToNextGameTick); + break; + } + } + + demofile.close(); + + DemoModeLastTick = SDL_GetTicks(); + + return true; +} + +} // namespace + +namespace demo { + +void InitPlayBack(int demoNumber, bool timedemo) +{ + DemoNumber = demoNumber; + Timedemo = timedemo; + + if (!LoadDemoMessages(demoNumber)) { + SDL_Log("Unable to load demo file"); + diablo_quit(1); + } +} +void InitRecording(int recordNumber) +{ + RecordNumber = recordNumber; +} + +bool IsRunning() +{ + return DemoNumber != -1; +} + +bool IsTimedemo() +{ + return Timedemo; +} + +bool IsRecording() +{ + return RecordNumber != -1; +}; + +bool GetRunGameLoop(bool &drawGame, bool &processInput) +{ + if (Demo_Message_Queue.empty()) + app_fatal("Demo queue empty"); + demoMsg dmsg = Demo_Message_Queue.front(); + if (dmsg.type == DemoMsgType::Message) + app_fatal("Unexpected Message"); + // disable additonal rendering to speedup replay + drawGame = dmsg.type == DemoMsgType::GameTick; + if (!Timedemo) { + int currentTickCount = SDL_GetTicks(); + int ticksElapsed = currentTickCount - DemoModeLastTick; + bool tickDue = ticksElapsed >= gnTickDelay; + if (tickDue) { + if (dmsg.type == DemoMsgType::GameTick) { + DemoModeLastTick = currentTickCount; + } + } else { + float progressToNextGameTick = clamp((float)ticksElapsed / (float)gnTickDelay, 0.F, 1.F); + if (dmsg.progressToNextGameTick > progressToNextGameTick) { + // we are ahead of the replay => add a additional rendering for smoothness + gfProgressToNextGameTick = progressToNextGameTick; + processInput = false; + drawGame = true; + return false; + } + } + } + gfProgressToNextGameTick = dmsg.progressToNextGameTick; + Demo_Message_Queue.pop_front(); + if (dmsg.type == DemoMsgType::GameTick) + LogicTick++; + return dmsg.type == DemoMsgType::GameTick; +} + +bool FetchMessage(tagMSG *lpMsg) +{ + SDL_Event e; + if (SDL_PollEvent(&e) != 0) { + if (e.type == SDL_QUIT) { + lpMsg->message = DVL_WM_QUIT; + lpMsg->lParam = 0; + lpMsg->wParam = 0; + return true; + } + if (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_ESCAPE) { + Demo_Message_Queue.clear(); + ClearMessageQueue(); + DemoNumber = -1; + Timedemo = false; + last_tick = SDL_GetTicks(); + } + if (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_KP_PLUS && sgGameInitInfo.nTickRate < 255) { + sgGameInitInfo.nTickRate++; + sgOptions.Gameplay.nTickRate = sgGameInitInfo.nTickRate; + gnTickDelay = 1000 / sgGameInitInfo.nTickRate; + } + if (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_KP_MINUS && sgGameInitInfo.nTickRate > 1) { + sgGameInitInfo.nTickRate--; + sgOptions.Gameplay.nTickRate = sgGameInitInfo.nTickRate; + gnTickDelay = 1000 / sgGameInitInfo.nTickRate; + } + } + + if (!Demo_Message_Queue.empty()) { + demoMsg dmsg = Demo_Message_Queue.front(); + if (dmsg.type == DemoMsgType::Message) { + lpMsg->message = dmsg.message; + lpMsg->lParam = dmsg.lParam; + lpMsg->wParam = dmsg.wParam; + gfProgressToNextGameTick = dmsg.progressToNextGameTick; + Demo_Message_Queue.pop_front(); + return true; + } + } + + lpMsg->message = 0; + lpMsg->lParam = 0; + lpMsg->wParam = 0; + + return false; +} + +void RecordGameLoopResult(bool runGameLoop) +{ + DemoRecording << static_cast(runGameLoop ? DemoMsgType::GameTick : DemoMsgType::Rendering) << "," << gfProgressToNextGameTick << "\n"; +} + +void RecordMessage(tagMSG *lpMsg) +{ + if (!gbRunGame || !DemoRecording.is_open()) + return; + DemoRecording << static_cast(DemoMsgType::Message) << "," << gfProgressToNextGameTick << "," << lpMsg->message << "," << lpMsg->wParam << "," << lpMsg->lParam << "\n"; +} + +void NotifyGameLoopStart() +{ + if (IsRecording()) { + char demoFilename[16]; + snprintf(demoFilename, 15, "demo_%d.dmo", RecordNumber); + DemoRecording.open(paths::PrefPath() + demoFilename, std::fstream::trunc); + DemoRecording << "0," << gSaveNumber << "," << gnScreenWidth << "," << gnScreenHeight << "\n"; + } + + if (IsRunning()) { + StartTime = SDL_GetTicks(); + LogicTick = 0; + } +} + +void NotifyGameLoopEnd() +{ + if (IsRecording()) { + DemoRecording.close(); + + RecordNumber = -1; + } + + if (IsRunning()) { + float secounds = (SDL_GetTicks() - StartTime) / 1000.0; + SDL_Log("%d frames, %.2f seconds: %.1f fps", LogicTick, secounds, LogicTick / secounds); + gbRunGameResult = false; + gbRunGame = false; + } +} + +} // namespace demo + +} // namespace devilution diff --git a/Source/engine/demomode.h b/Source/engine/demomode.h new file mode 100644 index 000000000..ca75066f6 --- /dev/null +++ b/Source/engine/demomode.h @@ -0,0 +1,31 @@ +/** + * @file animationinfo.h + * + * Contains most of the the demomode specific logic + */ +#pragma once + +#include "miniwin/miniwin.h" + +namespace devilution { + +namespace demo { + +void InitPlayBack(int demoNumber, bool timedemo); +void InitRecording(int recordNumber); + +bool IsRunning(); +bool IsTimedemo(); +bool IsRecording(); + +bool GetRunGameLoop(bool &drawGame, bool &processInput); +bool FetchMessage(tagMSG *lpMsg); +void RecordGameLoopResult(bool runGameLoop); +void RecordMessage(tagMSG *lpMsg); + +void NotifyGameLoopStart(); +void NotifyGameLoopEnd(); + +} // namespace demo + +} // namespace devilution diff --git a/Source/menu.cpp b/Source/menu.cpp index 4c34ad943..f8cf139ef 100644 --- a/Source/menu.cpp +++ b/Source/menu.cpp @@ -5,6 +5,7 @@ */ #include "DiabloUI/diabloui.h" +#include "engine/demomode.h" #include "init.h" #include "movie.h" #include "options.h" @@ -86,7 +87,7 @@ bool DummyGetHeroInfo(_uiheroinfo * /*pInfo*/) bool mainmenu_select_hero_dialog(GameData *gameData) { _selhero_selections dlgresult = SELHERO_NEW_DUNGEON; - if (demoMode) { + if (demo::IsRunning()) { pfile_ui_set_hero_infos(DummyGetHeroInfo); gbLoadGame = true; } else if (!gbIsMultiplayer) { @@ -116,9 +117,6 @@ bool mainmenu_select_hero_dialog(GameData *gameData) pfile_read_player_from_save(gSaveNumber, MyPlayerId); - if (recordDemo != -1) - CreateDemoFile(recordDemo); - return true; } @@ -132,7 +130,7 @@ void mainmenu_loop() do { menu = MAINMENU_NONE; - if (demoMode) + if (demo::IsRunning()) menu = MAINMENU_SINGLE_PLAYER; else if (!UiMainMenuDialog(gszProductName, &menu, effects_play_sound, 30)) app_fatal("%s", _("Unable to display mainmenu")); diff --git a/Source/miniwin/miniwin.h b/Source/miniwin/miniwin.h index 4190adc04..fc3c51039 100644 --- a/Source/miniwin/miniwin.h +++ b/Source/miniwin/miniwin.h @@ -8,8 +8,6 @@ #include #include #include -#include -#include namespace devilution { @@ -33,23 +31,6 @@ struct tagMSG { int32_t lParam; }; -enum class DemoMsgType { - GameTick = 0, - Rendering = 1, - Message = 2, -}; - -struct demoMsg { - DemoMsgType type; - uint32_t message; - int32_t wParam; - int32_t lParam; - float progressToNextGameTick; -}; - -extern std::ofstream demoRecording; -bool GetDemoRunGameLoop(bool &drawGame, bool &processInput); - // // Everything else // @@ -59,13 +40,12 @@ void FocusOnCharInfo(); bool GetAsyncKeyState(int vKey); -void CreateDemoFile(int i); -bool LoadDemoMessages(int i); bool FetchMessage(tagMSG *lpMsg); bool TranslateMessage(const tagMSG *lpMsg); void PushMessage(const tagMSG *lpMsg); bool PostMessage(uint32_t type, int32_t wParam, int32_t lParam); +void ClearMessageQueue(); #ifdef _MSC_VER #define strcasecmp _stricmp diff --git a/Source/miniwin/misc_msg.cpp b/Source/miniwin/misc_msg.cpp index 2593cc3ac..11acd949b 100644 --- a/Source/miniwin/misc_msg.cpp +++ b/Source/miniwin/misc_msg.cpp @@ -1,7 +1,6 @@ #include #include #include -#include #include #include "control.h" @@ -12,17 +11,16 @@ #include "controls/remap_keyboard.h" #include "controls/touch.h" #include "cursor.h" +#include "engine/demomode.h" #include "engine/rectangle.hpp" #include "hwcursor.hpp" #include "inv.h" #include "menu.h" #include "miniwin/miniwin.h" #include "movie.h" -#include "nthread.h" #include "storm/storm.h" #include "utils/display.h" #include "utils/log.hpp" -#include "utils/paths.h" #include "utils/sdl_compat.h" #include "utils/stubs.h" @@ -48,7 +46,7 @@ void SetCursorPos(int x, int y) mousePositionWarping = { x, y }; mouseWarping = true; LogicalToOutput(&x, &y); - if (!demoMode) + if (!demo::IsRunning()) SDL_WarpMouseInWindow(ghMainWnd, x, y); } @@ -592,192 +590,12 @@ bool FetchMessage_Real(tagMSG *lpMsg) return true; } -std::ofstream demoRecording; -static std::deque demo_message_queue; -uint32_t demoModeLastTick = 0; - -void CreateDemoFile(int i) -{ - char demoFilename[16]; - snprintf(demoFilename, 15, "demo_%d.dmo", i); - demoRecording.open(paths::PrefPath() + demoFilename, std::fstream::trunc); - - demoRecording << "0," << gSaveNumber << "," << gnScreenWidth << "," << gnScreenHeight << "\n"; -} - -void SaveDemoMessage(tagMSG *lpMsg) -{ - demoRecording << static_cast(DemoMsgType::Message) << "," << gfProgressToNextGameTick << "," << lpMsg->message << "," << lpMsg->wParam << "," << lpMsg->lParam << "\n"; -} - -void PumpDemoMessage(DemoMsgType demoMsgType, uint32_t message, int32_t wParam, int32_t lParam, float progressToNextGameTick) -{ - demoMsg msg; - msg.type = demoMsgType; - msg.message = message; - msg.wParam = wParam; - msg.lParam = lParam; - msg.progressToNextGameTick = progressToNextGameTick; - - demo_message_queue.push_back(msg); -} - -bool LoadDemoMessages(int i) -{ - std::ifstream demofile; - char demoFilename[16]; - snprintf(demoFilename, 15, "demo_%d.dmo", i); - demofile.open(paths::PrefPath() + demoFilename); - if (!demofile.is_open()) { - return false; - } - - std::string line; - std::getline(demofile, line); - std::stringstream header(line); - - std::string number; - std::getline(header, number, ','); // Demo version - if (std::stoi(number) != 0) { - return false; - } - - std::getline(header, number, ','); - gSaveNumber = std::stoi(number); - - std::getline(header, number, ','); - uint32_t width = std::stoi(number); - sgOptions.Graphics.nWidth = width; - - std::getline(header, number, ','); - uint32_t height = std::stoi(number); - sgOptions.Graphics.nHeight = height; - - while (std::getline(demofile, line)) { - std::stringstream command(line); - - std::getline(command, number, ','); - int typeNum = std::stoi(number); - auto type = static_cast(typeNum); - - std::getline(command, number, ','); - float progressToNextGameTick = std::stof(number); - - switch (type) { - case DemoMsgType::Message: { - std::getline(command, number, ','); - uint32_t message = std::stoi(number); - std::getline(command, number, ','); - int32_t wParam = std::stoi(number); - std::getline(command, number, ','); - int32_t lParam = std::stoi(number); - PumpDemoMessage(type, message, wParam, lParam, progressToNextGameTick); - break; - } - default: - PumpDemoMessage(type, 0, 0, 0, progressToNextGameTick); - break; - } - } - - demofile.close(); - - demoModeLastTick = SDL_GetTicks(); - - return true; -} - -bool DemoMessage(tagMSG *lpMsg) -{ - SDL_Event e; - if (SDL_PollEvent(&e) != 0) { - if (e.type == SDL_QUIT) { - lpMsg->message = DVL_WM_QUIT; - lpMsg->lParam = 0; - lpMsg->wParam = 0; - return true; - } - if (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_ESCAPE) { - demo_message_queue.clear(); - message_queue.clear(); - demoMode = false; - timedemo = false; - last_tick = SDL_GetTicks(); - } - if (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_KP_PLUS && sgGameInitInfo.nTickRate < 255) { - sgGameInitInfo.nTickRate++; - sgOptions.Gameplay.nTickRate = sgGameInitInfo.nTickRate; - gnTickDelay = 1000 / sgGameInitInfo.nTickRate; - } - if (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_KP_MINUS && sgGameInitInfo.nTickRate > 1) { - sgGameInitInfo.nTickRate--; - sgOptions.Gameplay.nTickRate = sgGameInitInfo.nTickRate; - gnTickDelay = 1000 / sgGameInitInfo.nTickRate; - } - } - - if (!demo_message_queue.empty()) { - demoMsg dmsg = demo_message_queue.front(); - if (dmsg.type == DemoMsgType::Message) { - lpMsg->message = dmsg.message; - lpMsg->lParam = dmsg.lParam; - lpMsg->wParam = dmsg.wParam; - gfProgressToNextGameTick = dmsg.progressToNextGameTick; - demo_message_queue.pop_front(); - return true; - } - } - - lpMsg->message = 0; - lpMsg->lParam = 0; - lpMsg->wParam = 0; - - return false; -} - -bool GetDemoRunGameLoop(bool &drawGame, bool &processInput) -{ - if (demo_message_queue.empty()) - app_fatal("Demo queue empty"); - demoMsg dmsg = demo_message_queue.front(); - if (dmsg.type == DemoMsgType::Message) - app_fatal("Unexpected Message"); - // disable additonal rendering to speedup replay - drawGame = dmsg.type == DemoMsgType::GameTick; - if (!timedemo) { - int currentTickCount = SDL_GetTicks(); - int ticksElapsed = currentTickCount - demoModeLastTick; - bool tickDue = ticksElapsed >= gnTickDelay; - if (tickDue) { - if (dmsg.type == DemoMsgType::GameTick) { - demoModeLastTick = currentTickCount; - } - } else { - float progressToNextGameTick = clamp((float)ticksElapsed / (float)gnTickDelay, 0.F, 1.F); - if (dmsg.progressToNextGameTick > progressToNextGameTick) { - // we are ahead of the replay => add a additional rendering for smoothness - gfProgressToNextGameTick = progressToNextGameTick; - processInput = false; - drawGame = true; - return false; - } - } - } - gfProgressToNextGameTick = dmsg.progressToNextGameTick; - demo_message_queue.pop_front(); - return dmsg.type == DemoMsgType::GameTick; -} - bool FetchMessage(tagMSG *lpMsg) { - if (demoMode) { - return DemoMessage(lpMsg); - } + bool available = demo::IsRunning() ? demo::FetchMessage(lpMsg) : FetchMessage_Real(lpMsg); - bool available = FetchMessage_Real(lpMsg); - - if (recordDemo != -1 && available && gbRunGame) - SaveDemoMessage(lpMsg); + if (available && demo::IsRecording()) + demo::RecordMessage(lpMsg); return available; } @@ -931,4 +749,9 @@ bool PostMessage(uint32_t type, int32_t wParam, int32_t lParam) return true; } +void ClearMessageQueue() +{ + message_queue.clear(); +} + } // namespace devilution diff --git a/Source/movie.cpp b/Source/movie.cpp index 457db8586..842ea37dc 100644 --- a/Source/movie.cpp +++ b/Source/movie.cpp @@ -6,6 +6,7 @@ #include "diablo.h" #include "effects.h" +#include "engine/demomode.h" #include "hwcursor.hpp" #include "storm/storm_svid.h" #include "utils/display.h" @@ -28,7 +29,7 @@ bool loop_movie; */ void play_movie(const char *pszMovie, bool userCanClose) { - if (timedemo) + if (demo::IsRunning()) return; movie_playing = true; diff --git a/Source/nthread.cpp b/Source/nthread.cpp index 6c6b7f0ee..ce3f04f50 100644 --- a/Source/nthread.cpp +++ b/Source/nthread.cpp @@ -5,6 +5,7 @@ */ #include "diablo.h" +#include "engine/demomode.h" #include "gmenu.h" #include "nthread.h" #include "storm/storm.h" @@ -227,7 +228,7 @@ bool nthread_has_500ms_passed() void nthread_UpdateProgressToNextGameTick() { - if (!gbRunGame || PauseMode != 0 || (!gbIsMultiplayer && gmenu_is_active()) || !gbProcessPlayers || demoMode) // if game is not running or paused there is no next gametick in the near future + if (!gbRunGame || PauseMode != 0 || (!gbIsMultiplayer && gmenu_is_active()) || !gbProcessPlayers || demo::IsRunning()) // if game is not running or paused there is no next gametick in the near future return; int currentTickCount = SDL_GetTicks(); int ticksElapsed = last_tick - currentTickCount; diff --git a/Source/options.cpp b/Source/options.cpp index 7f6f6ebf6..46de7252f 100644 --- a/Source/options.cpp +++ b/Source/options.cpp @@ -26,6 +26,7 @@ #include #include "diablo.h" +#include "engine/demomode.h" #include "options.h" #include "utils/file_util.h" #include "utils/language.h" @@ -224,7 +225,7 @@ void LoadOptions() sgOptions.Audio.nBufferSize = GetIniInt("Audio", "Buffer Size", DEFAULT_AUDIO_BUFFER_SIZE); sgOptions.Audio.nResamplingQuality = GetIniInt("Audio", "Resampling Quality", DEFAULT_AUDIO_RESAMPLING_QUALITY); - if (!demoMode) { + if (!demo::IsRunning()) { sgOptions.Graphics.nWidth = GetIniInt("Graphics", "Width", DEFAULT_WIDTH); sgOptions.Graphics.nHeight = GetIniInt("Graphics", "Height", DEFAULT_HEIGHT); } diff --git a/Source/utils/display.cpp b/Source/utils/display.cpp index 295299fa5..9b43cf6a6 100644 --- a/Source/utils/display.cpp +++ b/Source/utils/display.cpp @@ -15,6 +15,7 @@ #include "controls/devices/joystick.h" #include "controls/devices/kbcontroller.h" #include "controls/game_controls.h" +#include "engine/demomode.h" #include "options.h" #include "utils/log.hpp" @@ -172,7 +173,7 @@ bool SpawnWindow(const char *lpWindowName) int width = sgOptions.Graphics.nWidth; int height = sgOptions.Graphics.nHeight; - if (sgOptions.Graphics.bUpscale && sgOptions.Graphics.bFitToScreen && !demoMode) { + if (sgOptions.Graphics.bUpscale && sgOptions.Graphics.bFitToScreen && !demo::IsRunning()) { CalculatePreferdWindowSize(width, height); } AdjustToScreenGeometry(width, height); @@ -220,7 +221,7 @@ bool SpawnWindow(const char *lpWindowName) #ifndef USE_SDL1 Uint32 rendererFlags = SDL_RENDERER_ACCELERATED; - if (sgOptions.Graphics.bVSync && !timedemo) { + if (sgOptions.Graphics.bVSync && !demo::IsTimedemo()) { rendererFlags |= SDL_RENDERER_PRESENTVSYNC; }