2 changed files with 332 additions and 332 deletions
@ -1,301 +1,301 @@ |
|||||||
/**
|
/**
|
||||||
* @file animationinfo.h |
* @file animationinfo.h |
||||||
* |
* |
||||||
* Contains most of the the demomode specific logic |
* Contains most of the the demomode specific logic |
||||||
*/ |
*/ |
||||||
|
|
||||||
#include <deque> |
#include <deque> |
||||||
#include <fstream> |
#include <fstream> |
||||||
#include <iostream> |
#include <iostream> |
||||||
#include <sstream> |
#include <sstream> |
||||||
|
|
||||||
#include "demomode.h" |
#include "demomode.h" |
||||||
#include "menu.h" |
#include "menu.h" |
||||||
#include "nthread.h" |
#include "nthread.h" |
||||||
#include "options.h" |
#include "options.h" |
||||||
#include "pfile.h" |
#include "pfile.h" |
||||||
#include "utils/display.h" |
#include "utils/display.h" |
||||||
#include "utils/paths.h" |
#include "utils/paths.h" |
||||||
|
|
||||||
namespace devilution { |
namespace devilution { |
||||||
|
|
||||||
namespace { |
namespace { |
||||||
|
|
||||||
enum class DemoMsgType { |
enum class DemoMsgType { |
||||||
GameTick = 0, |
GameTick = 0, |
||||||
Rendering = 1, |
Rendering = 1, |
||||||
Message = 2, |
Message = 2, |
||||||
}; |
}; |
||||||
|
|
||||||
struct demoMsg { |
struct demoMsg { |
||||||
DemoMsgType type; |
DemoMsgType type; |
||||||
uint32_t message; |
uint32_t message; |
||||||
int32_t wParam; |
int32_t wParam; |
||||||
int32_t lParam; |
int32_t lParam; |
||||||
float progressToNextGameTick; |
float progressToNextGameTick; |
||||||
}; |
}; |
||||||
|
|
||||||
int DemoNumber = -1; |
int DemoNumber = -1; |
||||||
bool Timedemo = false; |
bool Timedemo = false; |
||||||
int RecordNumber = -1; |
int RecordNumber = -1; |
||||||
|
|
||||||
std::ofstream DemoRecording; |
std::ofstream DemoRecording; |
||||||
std::deque<demoMsg> Demo_Message_Queue; |
std::deque<demoMsg> Demo_Message_Queue; |
||||||
uint32_t DemoModeLastTick = 0; |
uint32_t DemoModeLastTick = 0; |
||||||
|
|
||||||
int LogicTick = 0; |
int LogicTick = 0; |
||||||
int StartTime = 0; |
int StartTime = 0; |
||||||
|
|
||||||
int DemoGraphicsWidth = 640; |
int DemoGraphicsWidth = 640; |
||||||
int DemoGraphicsHeight = 480; |
int DemoGraphicsHeight = 480; |
||||||
|
|
||||||
void PumpDemoMessage(DemoMsgType demoMsgType, uint32_t message, int32_t wParam, int32_t lParam, float progressToNextGameTick) |
void PumpDemoMessage(DemoMsgType demoMsgType, uint32_t message, int32_t wParam, int32_t lParam, float progressToNextGameTick) |
||||||
{ |
{ |
||||||
demoMsg msg; |
demoMsg msg; |
||||||
msg.type = demoMsgType; |
msg.type = demoMsgType; |
||||||
msg.message = message; |
msg.message = message; |
||||||
msg.wParam = wParam; |
msg.wParam = wParam; |
||||||
msg.lParam = lParam; |
msg.lParam = lParam; |
||||||
msg.progressToNextGameTick = progressToNextGameTick; |
msg.progressToNextGameTick = progressToNextGameTick; |
||||||
|
|
||||||
Demo_Message_Queue.push_back(msg); |
Demo_Message_Queue.push_back(msg); |
||||||
} |
} |
||||||
|
|
||||||
bool LoadDemoMessages(int i) |
bool LoadDemoMessages(int i) |
||||||
{ |
{ |
||||||
std::ifstream demofile; |
std::ifstream demofile; |
||||||
char demoFilename[16]; |
char demoFilename[16]; |
||||||
snprintf(demoFilename, 15, "demo_%d.dmo", i); |
snprintf(demoFilename, 15, "demo_%d.dmo", i); |
||||||
demofile.open(paths::PrefPath() + demoFilename); |
demofile.open(paths::PrefPath() + demoFilename); |
||||||
if (!demofile.is_open()) { |
if (!demofile.is_open()) { |
||||||
return false; |
return false; |
||||||
} |
} |
||||||
|
|
||||||
std::string line; |
std::string line; |
||||||
std::getline(demofile, line); |
std::getline(demofile, line); |
||||||
std::stringstream header(line); |
std::stringstream header(line); |
||||||
|
|
||||||
std::string number; |
std::string number; |
||||||
std::getline(header, number, ','); // Demo version
|
std::getline(header, number, ','); // Demo version
|
||||||
if (std::stoi(number) != 0) { |
if (std::stoi(number) != 0) { |
||||||
return false; |
return false; |
||||||
} |
} |
||||||
|
|
||||||
std::getline(header, number, ','); |
std::getline(header, number, ','); |
||||||
gSaveNumber = std::stoi(number); |
gSaveNumber = std::stoi(number); |
||||||
|
|
||||||
std::getline(header, number, ','); |
std::getline(header, number, ','); |
||||||
DemoGraphicsWidth = std::stoi(number); |
DemoGraphicsWidth = std::stoi(number); |
||||||
|
|
||||||
std::getline(header, number, ','); |
std::getline(header, number, ','); |
||||||
DemoGraphicsHeight = std::stoi(number); |
DemoGraphicsHeight = std::stoi(number); |
||||||
|
|
||||||
while (std::getline(demofile, line)) { |
while (std::getline(demofile, line)) { |
||||||
std::stringstream command(line); |
std::stringstream command(line); |
||||||
|
|
||||||
std::getline(command, number, ','); |
std::getline(command, number, ','); |
||||||
int typeNum = std::stoi(number); |
int typeNum = std::stoi(number); |
||||||
auto type = static_cast<DemoMsgType>(typeNum); |
auto type = static_cast<DemoMsgType>(typeNum); |
||||||
|
|
||||||
std::getline(command, number, ','); |
std::getline(command, number, ','); |
||||||
float progressToNextGameTick = std::stof(number); |
float progressToNextGameTick = std::stof(number); |
||||||
|
|
||||||
switch (type) { |
switch (type) { |
||||||
case DemoMsgType::Message: { |
case DemoMsgType::Message: { |
||||||
std::getline(command, number, ','); |
std::getline(command, number, ','); |
||||||
uint32_t message = std::stoi(number); |
uint32_t message = std::stoi(number); |
||||||
std::getline(command, number, ','); |
std::getline(command, number, ','); |
||||||
int32_t wParam = std::stoi(number); |
int32_t wParam = std::stoi(number); |
||||||
std::getline(command, number, ','); |
std::getline(command, number, ','); |
||||||
int32_t lParam = std::stoi(number); |
int32_t lParam = std::stoi(number); |
||||||
PumpDemoMessage(type, message, wParam, lParam, progressToNextGameTick); |
PumpDemoMessage(type, message, wParam, lParam, progressToNextGameTick); |
||||||
break; |
break; |
||||||
} |
} |
||||||
default: |
default: |
||||||
PumpDemoMessage(type, 0, 0, 0, progressToNextGameTick); |
PumpDemoMessage(type, 0, 0, 0, progressToNextGameTick); |
||||||
break; |
break; |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
demofile.close(); |
demofile.close(); |
||||||
|
|
||||||
DemoModeLastTick = SDL_GetTicks(); |
DemoModeLastTick = SDL_GetTicks(); |
||||||
|
|
||||||
return true; |
return true; |
||||||
} |
} |
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace demo { |
namespace demo { |
||||||
|
|
||||||
void InitPlayBack(int demoNumber, bool timedemo) |
void InitPlayBack(int demoNumber, bool timedemo) |
||||||
{ |
{ |
||||||
DemoNumber = demoNumber; |
DemoNumber = demoNumber; |
||||||
Timedemo = timedemo; |
Timedemo = timedemo; |
||||||
|
|
||||||
if (!LoadDemoMessages(demoNumber)) { |
if (!LoadDemoMessages(demoNumber)) { |
||||||
SDL_Log("Unable to load demo file"); |
SDL_Log("Unable to load demo file"); |
||||||
diablo_quit(1); |
diablo_quit(1); |
||||||
} |
} |
||||||
} |
} |
||||||
void InitRecording(int recordNumber) |
void InitRecording(int recordNumber) |
||||||
{ |
{ |
||||||
RecordNumber = recordNumber; |
RecordNumber = recordNumber; |
||||||
} |
} |
||||||
void OverrideOptions() |
void OverrideOptions() |
||||||
{ |
{ |
||||||
#ifndef USE_SDL1 |
#ifndef USE_SDL1 |
||||||
sgOptions.Graphics.fitToScreen.SetValue(false); |
sgOptions.Graphics.fitToScreen.SetValue(false); |
||||||
#endif |
#endif |
||||||
#if SDL_VERSION_ATLEAST(2, 0, 0) |
#if SDL_VERSION_ATLEAST(2, 0, 0) |
||||||
sgOptions.Graphics.bHardwareCursor = false; |
sgOptions.Graphics.bHardwareCursor = false; |
||||||
#endif |
#endif |
||||||
if (Timedemo) { |
if (Timedemo) { |
||||||
#ifndef USE_SDL1 |
#ifndef USE_SDL1 |
||||||
sgOptions.Graphics.vSync.SetValue(false); |
sgOptions.Graphics.vSync.SetValue(false); |
||||||
#endif |
#endif |
||||||
sgOptions.Graphics.limitFPS.SetValue(false); |
sgOptions.Graphics.limitFPS.SetValue(false); |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
bool IsRunning() |
bool IsRunning() |
||||||
{ |
{ |
||||||
return DemoNumber != -1; |
return DemoNumber != -1; |
||||||
} |
} |
||||||
|
|
||||||
bool IsRecording() |
bool IsRecording() |
||||||
{ |
{ |
||||||
return RecordNumber != -1; |
return RecordNumber != -1; |
||||||
}; |
}; |
||||||
|
|
||||||
bool GetRunGameLoop(bool &drawGame, bool &processInput) |
bool GetRunGameLoop(bool &drawGame, bool &processInput) |
||||||
{ |
{ |
||||||
if (Demo_Message_Queue.empty()) |
if (Demo_Message_Queue.empty()) |
||||||
app_fatal("Demo queue empty"); |
app_fatal("Demo queue empty"); |
||||||
demoMsg dmsg = Demo_Message_Queue.front(); |
demoMsg dmsg = Demo_Message_Queue.front(); |
||||||
if (dmsg.type == DemoMsgType::Message) |
if (dmsg.type == DemoMsgType::Message) |
||||||
app_fatal("Unexpected Message"); |
app_fatal("Unexpected Message"); |
||||||
if (Timedemo) { |
if (Timedemo) { |
||||||
// disable additonal rendering to speedup replay
|
// disable additonal rendering to speedup replay
|
||||||
drawGame = dmsg.type == DemoMsgType::GameTick; |
drawGame = dmsg.type == DemoMsgType::GameTick; |
||||||
} else { |
} else { |
||||||
int currentTickCount = SDL_GetTicks(); |
int currentTickCount = SDL_GetTicks(); |
||||||
int ticksElapsed = currentTickCount - DemoModeLastTick; |
int ticksElapsed = currentTickCount - DemoModeLastTick; |
||||||
bool tickDue = ticksElapsed >= gnTickDelay; |
bool tickDue = ticksElapsed >= gnTickDelay; |
||||||
drawGame = false; |
drawGame = false; |
||||||
if (tickDue) { |
if (tickDue) { |
||||||
if (dmsg.type == DemoMsgType::GameTick) { |
if (dmsg.type == DemoMsgType::GameTick) { |
||||||
DemoModeLastTick = currentTickCount; |
DemoModeLastTick = currentTickCount; |
||||||
} |
} |
||||||
} else { |
} else { |
||||||
float progressToNextGameTick = clamp((float)ticksElapsed / (float)gnTickDelay, 0.F, 1.F); |
float progressToNextGameTick = clamp((float)ticksElapsed / (float)gnTickDelay, 0.F, 1.F); |
||||||
if (dmsg.type == DemoMsgType::GameTick || dmsg.progressToNextGameTick > progressToNextGameTick) { |
if (dmsg.type == DemoMsgType::GameTick || dmsg.progressToNextGameTick > progressToNextGameTick) { |
||||||
// we are ahead of the replay => add a additional rendering for smoothness
|
// we are ahead of the replay => add a additional rendering for smoothness
|
||||||
gfProgressToNextGameTick = progressToNextGameTick; |
gfProgressToNextGameTick = progressToNextGameTick; |
||||||
processInput = false; |
processInput = false; |
||||||
drawGame = true; |
drawGame = true; |
||||||
return false; |
return false; |
||||||
} |
} |
||||||
} |
} |
||||||
} |
} |
||||||
gfProgressToNextGameTick = dmsg.progressToNextGameTick; |
gfProgressToNextGameTick = dmsg.progressToNextGameTick; |
||||||
Demo_Message_Queue.pop_front(); |
Demo_Message_Queue.pop_front(); |
||||||
if (dmsg.type == DemoMsgType::GameTick) |
if (dmsg.type == DemoMsgType::GameTick) |
||||||
LogicTick++; |
LogicTick++; |
||||||
return dmsg.type == DemoMsgType::GameTick; |
return dmsg.type == DemoMsgType::GameTick; |
||||||
} |
} |
||||||
|
|
||||||
bool FetchMessage(tagMSG *lpMsg) |
bool FetchMessage(tagMSG *lpMsg) |
||||||
{ |
{ |
||||||
SDL_Event e; |
SDL_Event e; |
||||||
if (SDL_PollEvent(&e) != 0) { |
if (SDL_PollEvent(&e) != 0) { |
||||||
if (e.type == SDL_QUIT) { |
if (e.type == SDL_QUIT) { |
||||||
lpMsg->message = DVL_WM_QUIT; |
lpMsg->message = DVL_WM_QUIT; |
||||||
lpMsg->lParam = 0; |
lpMsg->lParam = 0; |
||||||
lpMsg->wParam = 0; |
lpMsg->wParam = 0; |
||||||
return true; |
return true; |
||||||
} |
} |
||||||
if (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_ESCAPE) { |
if (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_ESCAPE) { |
||||||
Demo_Message_Queue.clear(); |
Demo_Message_Queue.clear(); |
||||||
ClearMessageQueue(); |
ClearMessageQueue(); |
||||||
DemoNumber = -1; |
DemoNumber = -1; |
||||||
Timedemo = false; |
Timedemo = false; |
||||||
last_tick = SDL_GetTicks(); |
last_tick = SDL_GetTicks(); |
||||||
} |
} |
||||||
if (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_KP_PLUS && sgGameInitInfo.nTickRate < 255) { |
if (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_KP_PLUS && sgGameInitInfo.nTickRate < 255) { |
||||||
sgGameInitInfo.nTickRate++; |
sgGameInitInfo.nTickRate++; |
||||||
sgOptions.Gameplay.nTickRate = sgGameInitInfo.nTickRate; |
sgOptions.Gameplay.nTickRate = sgGameInitInfo.nTickRate; |
||||||
gnTickDelay = 1000 / sgGameInitInfo.nTickRate; |
gnTickDelay = 1000 / sgGameInitInfo.nTickRate; |
||||||
} |
} |
||||||
if (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_KP_MINUS && sgGameInitInfo.nTickRate > 1) { |
if (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_KP_MINUS && sgGameInitInfo.nTickRate > 1) { |
||||||
sgGameInitInfo.nTickRate--; |
sgGameInitInfo.nTickRate--; |
||||||
sgOptions.Gameplay.nTickRate = sgGameInitInfo.nTickRate; |
sgOptions.Gameplay.nTickRate = sgGameInitInfo.nTickRate; |
||||||
gnTickDelay = 1000 / sgGameInitInfo.nTickRate; |
gnTickDelay = 1000 / sgGameInitInfo.nTickRate; |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
if (!Demo_Message_Queue.empty()) { |
if (!Demo_Message_Queue.empty()) { |
||||||
demoMsg dmsg = Demo_Message_Queue.front(); |
demoMsg dmsg = Demo_Message_Queue.front(); |
||||||
if (dmsg.type == DemoMsgType::Message) { |
if (dmsg.type == DemoMsgType::Message) { |
||||||
lpMsg->message = dmsg.message; |
lpMsg->message = dmsg.message; |
||||||
lpMsg->lParam = dmsg.lParam; |
lpMsg->lParam = dmsg.lParam; |
||||||
lpMsg->wParam = dmsg.wParam; |
lpMsg->wParam = dmsg.wParam; |
||||||
gfProgressToNextGameTick = dmsg.progressToNextGameTick; |
gfProgressToNextGameTick = dmsg.progressToNextGameTick; |
||||||
Demo_Message_Queue.pop_front(); |
Demo_Message_Queue.pop_front(); |
||||||
return true; |
return true; |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
lpMsg->message = 0; |
lpMsg->message = 0; |
||||||
lpMsg->lParam = 0; |
lpMsg->lParam = 0; |
||||||
lpMsg->wParam = 0; |
lpMsg->wParam = 0; |
||||||
|
|
||||||
return false; |
return false; |
||||||
} |
} |
||||||
|
|
||||||
void RecordGameLoopResult(bool runGameLoop) |
void RecordGameLoopResult(bool runGameLoop) |
||||||
{ |
{ |
||||||
DemoRecording << static_cast<uint32_t>(runGameLoop ? DemoMsgType::GameTick : DemoMsgType::Rendering) << "," << gfProgressToNextGameTick << "\n"; |
DemoRecording << static_cast<uint32_t>(runGameLoop ? DemoMsgType::GameTick : DemoMsgType::Rendering) << "," << gfProgressToNextGameTick << "\n"; |
||||||
} |
} |
||||||
|
|
||||||
void RecordMessage(tagMSG *lpMsg) |
void RecordMessage(tagMSG *lpMsg) |
||||||
{ |
{ |
||||||
if (!gbRunGame || !DemoRecording.is_open()) |
if (!gbRunGame || !DemoRecording.is_open()) |
||||||
return; |
return; |
||||||
DemoRecording << static_cast<uint32_t>(DemoMsgType::Message) << "," << gfProgressToNextGameTick << "," << lpMsg->message << "," << lpMsg->wParam << "," << lpMsg->lParam << "\n"; |
DemoRecording << static_cast<uint32_t>(DemoMsgType::Message) << "," << gfProgressToNextGameTick << "," << lpMsg->message << "," << lpMsg->wParam << "," << lpMsg->lParam << "\n"; |
||||||
} |
} |
||||||
|
|
||||||
void NotifyGameLoopStart() |
void NotifyGameLoopStart() |
||||||
{ |
{ |
||||||
if (IsRecording()) { |
if (IsRecording()) { |
||||||
char demoFilename[16]; |
char demoFilename[16]; |
||||||
snprintf(demoFilename, 15, "demo_%d.dmo", RecordNumber); |
snprintf(demoFilename, 15, "demo_%d.dmo", RecordNumber); |
||||||
DemoRecording.open(paths::PrefPath() + demoFilename, std::fstream::trunc); |
DemoRecording.open(paths::PrefPath() + demoFilename, std::fstream::trunc); |
||||||
DemoRecording << "0," << gSaveNumber << "," << gnScreenWidth << "," << gnScreenHeight << "\n"; |
DemoRecording << "0," << gSaveNumber << "," << gnScreenWidth << "," << gnScreenHeight << "\n"; |
||||||
} |
} |
||||||
|
|
||||||
if (IsRunning()) { |
if (IsRunning()) { |
||||||
StartTime = SDL_GetTicks(); |
StartTime = SDL_GetTicks(); |
||||||
LogicTick = 0; |
LogicTick = 0; |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
void NotifyGameLoopEnd() |
void NotifyGameLoopEnd() |
||||||
{ |
{ |
||||||
if (IsRecording()) { |
if (IsRecording()) { |
||||||
DemoRecording.close(); |
DemoRecording.close(); |
||||||
|
|
||||||
RecordNumber = -1; |
RecordNumber = -1; |
||||||
} |
} |
||||||
|
|
||||||
if (IsRunning()) { |
if (IsRunning()) { |
||||||
float secounds = (SDL_GetTicks() - StartTime) / 1000.0; |
float secounds = (SDL_GetTicks() - StartTime) / 1000.0; |
||||||
SDL_Log("%d frames, %.2f seconds: %.1f fps", LogicTick, secounds, LogicTick / secounds); |
SDL_Log("%d frames, %.2f seconds: %.1f fps", LogicTick, secounds, LogicTick / secounds); |
||||||
gbRunGameResult = false; |
gbRunGameResult = false; |
||||||
gbRunGame = false; |
gbRunGame = false; |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
} // namespace demo
|
} // namespace demo
|
||||||
|
|
||||||
} // namespace devilution
|
} // namespace devilution
|
||||||
|
|||||||
@ -1,31 +1,31 @@ |
|||||||
/**
|
/**
|
||||||
* @file animationinfo.h |
* @file animationinfo.h |
||||||
* |
* |
||||||
* Contains most of the the demomode specific logic |
* Contains most of the the demomode specific logic |
||||||
*/ |
*/ |
||||||
#pragma once |
#pragma once |
||||||
|
|
||||||
#include "miniwin/miniwin.h" |
#include "miniwin/miniwin.h" |
||||||
|
|
||||||
namespace devilution { |
namespace devilution { |
||||||
|
|
||||||
namespace demo { |
namespace demo { |
||||||
|
|
||||||
void InitPlayBack(int demoNumber, bool timedemo); |
void InitPlayBack(int demoNumber, bool timedemo); |
||||||
void InitRecording(int recordNumber); |
void InitRecording(int recordNumber); |
||||||
void OverrideOptions(); |
void OverrideOptions(); |
||||||
|
|
||||||
bool IsRunning(); |
bool IsRunning(); |
||||||
bool IsRecording(); |
bool IsRecording(); |
||||||
|
|
||||||
bool GetRunGameLoop(bool &drawGame, bool &processInput); |
bool GetRunGameLoop(bool &drawGame, bool &processInput); |
||||||
bool FetchMessage(tagMSG *lpMsg); |
bool FetchMessage(tagMSG *lpMsg); |
||||||
void RecordGameLoopResult(bool runGameLoop); |
void RecordGameLoopResult(bool runGameLoop); |
||||||
void RecordMessage(tagMSG *lpMsg); |
void RecordMessage(tagMSG *lpMsg); |
||||||
|
|
||||||
void NotifyGameLoopStart(); |
void NotifyGameLoopStart(); |
||||||
void NotifyGameLoopEnd(); |
void NotifyGameLoopEnd(); |
||||||
|
|
||||||
} // namespace demo
|
} // namespace demo
|
||||||
|
|
||||||
} // namespace devilution
|
} // namespace devilution
|
||||||
|
|||||||
Loading…
Reference in new issue