Introduce demo namespace
This commit is contained in:
parent
ad6f9cb8e5
commit
77f9bded9e
13 changed files with 366 additions and 253 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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<Keymapper::ActionIndex, 4> 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<uint32_t>(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<uint32_t>(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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include <SDL.h>
|
||||
|
||||
#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 {
|
||||
|
|
|
|||
288
Source/engine/demomode.cpp
Normal file
288
Source/engine/demomode.cpp
Normal file
|
|
@ -0,0 +1,288 @@
|
|||
/**
|
||||
* @file animationinfo.h
|
||||
*
|
||||
* Contains most of the the demomode specific logic
|
||||
*/
|
||||
|
||||
#include <deque>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
||||
#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<demoMsg> 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<DemoMsgType>(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<uint32_t>(runGameLoop ? DemoMsgType::GameTick : DemoMsgType::Rendering) << "," << gfProgressToNextGameTick << "\n";
|
||||
}
|
||||
|
||||
void RecordMessage(tagMSG *lpMsg)
|
||||
{
|
||||
if (!gbRunGame || !DemoRecording.is_open())
|
||||
return;
|
||||
DemoRecording << static_cast<uint32_t>(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
|
||||
31
Source/engine/demomode.h
Normal file
31
Source/engine/demomode.h
Normal file
|
|
@ -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
|
||||
|
|
@ -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"));
|
||||
|
|
|
|||
|
|
@ -8,8 +8,6 @@
|
|||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
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
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
#include <SDL.h>
|
||||
#include <cstdint>
|
||||
#include <deque>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#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<demoMsg> 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<uint32_t>(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<DemoMsgType>(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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
#include <SimpleIni.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue