mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-10 10:08:18 +00:00
Refactor demo recorder usage
To simplify the usage of the demo recorder, parameters are added to the `IDemoRecorder::Stop` function to control whether the demo file is removed or renamed when stopping the recording. Ensure demo files of the replay recorder are always removed (except on crashes). The temporary replay demos were previously not removed when being disconnected from a server. Fix auto demos being stopped and restarted when enabling replays in the settings menu. Now only the replay recorder is stopped/started when necessary. Fix replay recorder being restarted when setting `cl_replay` variable with console without changing the value. Remove unnecessary `CClient::m_ButtonRender` variable. Demo rendering is already stopped correctly when reaching the end of the demo without this additional variable. Remove unused `CDemoRecorder::m_pMapData` variable.
This commit is contained in:
parent
94931fadc0
commit
9150f48562
|
@ -165,7 +165,7 @@ public:
|
|||
#endif
|
||||
virtual void DemoRecorder_Start(const char *pFilename, bool WithTimestamp, int Recorder, bool Verbose = false) = 0;
|
||||
virtual void DemoRecorder_HandleAutoStart() = 0;
|
||||
virtual void DemoRecorder_Stop(int Recorder, bool RemoveFile = false) = 0;
|
||||
virtual void DemoRecorder_UpdateReplayRecorder() = 0;
|
||||
virtual class IDemoRecorder *DemoRecorder(int Recorder) = 0;
|
||||
virtual void AutoScreenshot_Start() = 0;
|
||||
virtual void AutoStatScreenshot_Start() = 0;
|
||||
|
|
|
@ -532,11 +532,13 @@ void CClient::DisconnectWithReason(const char *pReason)
|
|||
m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "client", aBuf, gs_ClientNetworkPrintColor);
|
||||
|
||||
// stop demo playback and recorder
|
||||
// make sure to remove replay tmp demo
|
||||
m_DemoPlayer.Stop();
|
||||
for(int i = 0; i < RECORDER_MAX; i++)
|
||||
DemoRecorder_Stop(i);
|
||||
for(int Recorder = 0; Recorder < RECORDER_MAX; Recorder++)
|
||||
{
|
||||
DemoRecorder(Recorder)->Stop(Recorder == RECORDER_REPLAYS ? IDemoRecorder::EStopMode::REMOVE_FILE : IDemoRecorder::EStopMode::KEEP_FILE);
|
||||
}
|
||||
|
||||
//
|
||||
m_aRconAuthed[0] = 0;
|
||||
mem_zero(m_aRconUsername, sizeof(m_aRconUsername));
|
||||
mem_zero(m_aRconPassword, sizeof(m_aRconPassword));
|
||||
|
@ -581,14 +583,9 @@ void CClient::DisconnectWithReason(const char *pReason)
|
|||
|
||||
void CClient::Disconnect()
|
||||
{
|
||||
m_ButtonRender = false;
|
||||
if(m_State != IClient::STATE_OFFLINE)
|
||||
DisconnectWithReason(0);
|
||||
|
||||
// make sure to remove replay tmp demo
|
||||
if(g_Config.m_ClReplays)
|
||||
{
|
||||
DemoRecorder_Stop(RECORDER_REPLAYS, true);
|
||||
DisconnectWithReason(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -946,8 +943,10 @@ const char *CClient::LoadMap(const char *pName, const char *pFilename, SHA256_DI
|
|||
}
|
||||
|
||||
// stop demo recording if we loaded a new map
|
||||
for(int i = 0; i < RECORDER_MAX; i++)
|
||||
DemoRecorder_Stop(i, i == RECORDER_REPLAYS);
|
||||
for(int Recorder = 0; Recorder < RECORDER_MAX; Recorder++)
|
||||
{
|
||||
DemoRecorder(Recorder)->Stop(Recorder == RECORDER_REPLAYS ? IDemoRecorder::EStopMode::REMOVE_FILE : IDemoRecorder::EStopMode::KEEP_FILE);
|
||||
}
|
||||
|
||||
char aBuf[256];
|
||||
str_format(aBuf, sizeof(aBuf), "loaded map '%s'", pFilename);
|
||||
|
@ -2352,22 +2351,20 @@ void CClient::Update()
|
|||
{
|
||||
if(State() == IClient::STATE_DEMOPLAYBACK)
|
||||
{
|
||||
#if defined(CONF_VIDEORECORDER)
|
||||
if(m_DemoPlayer.IsPlaying() && IVideo::Current())
|
||||
{
|
||||
IVideo::Current()->NextVideoFrame();
|
||||
IVideo::Current()->NextAudioFrameTimeline([this](short *pFinalOut, unsigned Frames) {
|
||||
Sound()->Mix(pFinalOut, Frames);
|
||||
});
|
||||
}
|
||||
else if(m_ButtonRender)
|
||||
Disconnect();
|
||||
#endif
|
||||
|
||||
m_DemoPlayer.Update();
|
||||
|
||||
if(m_DemoPlayer.IsPlaying())
|
||||
{
|
||||
#if defined(CONF_VIDEORECORDER)
|
||||
if(IVideo::Current())
|
||||
{
|
||||
IVideo::Current()->NextVideoFrame();
|
||||
IVideo::Current()->NextAudioFrameTimeline([this](short *pFinalOut, unsigned Frames) {
|
||||
Sound()->Mix(pFinalOut, Frames);
|
||||
});
|
||||
}
|
||||
#endif
|
||||
|
||||
m_DemoPlayer.Update();
|
||||
|
||||
// update timers
|
||||
const CDemoPlayer::CPlaybackInfo *pInfo = m_DemoPlayer.Info();
|
||||
m_aCurGameTick[g_Config.m_ClDummy] = pInfo->m_Info.m_CurrentTick;
|
||||
|
@ -2377,7 +2374,8 @@ void CClient::Update()
|
|||
}
|
||||
else
|
||||
{
|
||||
// disconnect on error
|
||||
// Disconnect when demo playback stopped, either due to playback error
|
||||
// or because the end of the demo was reached when rendering it.
|
||||
DisconnectWithReason(m_DemoPlayer.ErrorMessage());
|
||||
if(m_DemoPlayer.ErrorMessage()[0] != '\0')
|
||||
{
|
||||
|
@ -3472,26 +3470,32 @@ void CClient::SaveReplay(const int Length, const char *pFilename)
|
|||
}
|
||||
|
||||
if(!DemoRecorder(RECORDER_REPLAYS)->IsRecording())
|
||||
{
|
||||
m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "replay", "ERROR: demorecorder isn't recording. Try to rejoin to fix that.");
|
||||
}
|
||||
else if(DemoRecorder(RECORDER_REPLAYS)->Length() < 1)
|
||||
{
|
||||
m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "replay", "ERROR: demorecorder isn't recording for at least 1 second.");
|
||||
}
|
||||
else
|
||||
{
|
||||
// First we stop the recorder to slice correctly the demo after
|
||||
DemoRecorder_Stop(RECORDER_REPLAYS);
|
||||
|
||||
char aDate[64];
|
||||
str_timestamp(aDate, sizeof(aDate));
|
||||
DemoRecorder(RECORDER_REPLAYS)->Stop(IDemoRecorder::EStopMode::KEEP_FILE);
|
||||
|
||||
char aFilename[IO_MAX_PATH_LENGTH];
|
||||
if(str_comp(pFilename, "") == 0)
|
||||
str_format(aFilename, sizeof(aFilename), "demos/replays/%s_%s (replay).demo", m_aCurrentMap, aDate);
|
||||
if(pFilename[0] == '\0')
|
||||
{
|
||||
char aTimestamp[20];
|
||||
str_timestamp(aTimestamp, sizeof(aTimestamp));
|
||||
str_format(aFilename, sizeof(aFilename), "demos/replays/%s_%s_(replay).demo", m_aCurrentMap, aTimestamp);
|
||||
}
|
||||
else
|
||||
{
|
||||
str_format(aFilename, sizeof(aFilename), "demos/replays/%s.demo", pFilename);
|
||||
|
||||
char *pSrc = m_aDemoRecorder[RECORDER_REPLAYS].GetCurrentFilename();
|
||||
}
|
||||
|
||||
// Slice the demo to get only the last cl_replay_length seconds
|
||||
const char *pSrc = m_aDemoRecorder[RECORDER_REPLAYS].CurrentFilename();
|
||||
const int EndTick = GameTick(g_Config.m_ClDummy);
|
||||
const int StartTick = EndTick - Length * GameTickSpeed();
|
||||
|
||||
|
@ -3503,7 +3507,7 @@ void CClient::SaveReplay(const int Length, const char *pFilename)
|
|||
m_EditJobs.push_back(pDemoEditTask);
|
||||
|
||||
// And we restart the recorder
|
||||
DemoRecorder_StartReplayRecorder();
|
||||
DemoRecorder_UpdateReplayRecorder();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3586,7 +3590,6 @@ const char *CClient::DemoPlayer_Render(const char *pFilename, int StorageType, c
|
|||
const char *pError = DemoPlayer_Play(pFilename, StorageType);
|
||||
if(pError)
|
||||
return pError;
|
||||
m_ButtonRender = true;
|
||||
|
||||
this->CClient::StartVideo(NULL, this, pVideoName);
|
||||
m_DemoPlayer.Play();
|
||||
|
@ -3632,19 +3635,23 @@ void CClient::DemoRecorder_Start(const char *pFilename, bool WithTimestamp, int
|
|||
if(State() != IClient::STATE_ONLINE)
|
||||
{
|
||||
if(Verbose)
|
||||
{
|
||||
m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "demorec/record", "client is not online");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
char aFilename[IO_MAX_PATH_LENGTH];
|
||||
if(WithTimestamp)
|
||||
{
|
||||
char aDate[20];
|
||||
str_timestamp(aDate, sizeof(aDate));
|
||||
str_format(aFilename, sizeof(aFilename), "demos/%s_%s.demo", pFilename, aDate);
|
||||
char aTimestamp[20];
|
||||
str_timestamp(aTimestamp, sizeof(aTimestamp));
|
||||
str_format(aFilename, sizeof(aFilename), "demos/%s_%s.demo", pFilename, aTimestamp);
|
||||
}
|
||||
else
|
||||
{
|
||||
str_format(aFilename, sizeof(aFilename), "demos/%s.demo", pFilename);
|
||||
}
|
||||
|
||||
m_aDemoRecorder[Recorder].Start(Storage(), m_pConsole, aFilename, GameClient()->NetVersion(), m_aCurrentMap, m_pMap->Sha256(), m_pMap->Crc(), "client", m_pMap->MapSize(), 0, m_pMap->File());
|
||||
}
|
||||
|
@ -3654,10 +3661,12 @@ void CClient::DemoRecorder_HandleAutoStart()
|
|||
{
|
||||
if(g_Config.m_ClAutoDemoRecord)
|
||||
{
|
||||
DemoRecorder_Stop(RECORDER_AUTO);
|
||||
char aBuf[512];
|
||||
str_format(aBuf, sizeof(aBuf), "auto/%s", m_aCurrentMap);
|
||||
DemoRecorder_Start(aBuf, true, RECORDER_AUTO);
|
||||
DemoRecorder(RECORDER_AUTO)->Stop(IDemoRecorder::EStopMode::KEEP_FILE);
|
||||
|
||||
char aFilename[IO_MAX_PATH_LENGTH];
|
||||
str_format(aFilename, sizeof(aFilename), "auto/%s", m_aCurrentMap);
|
||||
DemoRecorder_Start(aFilename, true, RECORDER_AUTO);
|
||||
|
||||
if(g_Config.m_ClAutoDemoMax)
|
||||
{
|
||||
// clean up auto recorded demos
|
||||
|
@ -3665,34 +3674,22 @@ void CClient::DemoRecorder_HandleAutoStart()
|
|||
AutoDemos.Init(Storage(), "demos/auto", "" /* empty for wild card */, ".demo", g_Config.m_ClAutoDemoMax);
|
||||
}
|
||||
}
|
||||
if(!DemoRecorder(RECORDER_REPLAYS)->IsRecording())
|
||||
{
|
||||
DemoRecorder_StartReplayRecorder();
|
||||
}
|
||||
|
||||
DemoRecorder_UpdateReplayRecorder();
|
||||
}
|
||||
|
||||
void CClient::DemoRecorder_StartReplayRecorder()
|
||||
void CClient::DemoRecorder_UpdateReplayRecorder()
|
||||
{
|
||||
if(g_Config.m_ClReplays)
|
||||
if(!g_Config.m_ClReplays && DemoRecorder(RECORDER_REPLAYS)->IsRecording())
|
||||
{
|
||||
DemoRecorder_Stop(RECORDER_REPLAYS);
|
||||
char aBuf[512];
|
||||
str_format(aBuf, sizeof(aBuf), "replays/replay_tmp-%s", m_aCurrentMap);
|
||||
DemoRecorder_Start(aBuf, true, RECORDER_REPLAYS);
|
||||
DemoRecorder(RECORDER_REPLAYS)->Stop(IDemoRecorder::EStopMode::REMOVE_FILE);
|
||||
}
|
||||
}
|
||||
|
||||
void CClient::DemoRecorder_Stop(int Recorder, bool RemoveFile)
|
||||
{
|
||||
m_aDemoRecorder[Recorder].Stop();
|
||||
if(RemoveFile)
|
||||
if(g_Config.m_ClReplays && !DemoRecorder(RECORDER_REPLAYS)->IsRecording())
|
||||
{
|
||||
const char *pFilename = m_aDemoRecorder[Recorder].GetCurrentFilename();
|
||||
if(pFilename[0] != '\0')
|
||||
{
|
||||
Storage()->RemoveFile(pFilename, IStorage::TYPE_SAVE);
|
||||
m_aDemoRecorder[Recorder].ClearCurrentFilename();
|
||||
}
|
||||
char aFilename[IO_MAX_PATH_LENGTH];
|
||||
str_format(aFilename, sizeof(aFilename), "replays/replay_tmp_%s", m_aCurrentMap);
|
||||
DemoRecorder_Start(aFilename, true, RECORDER_REPLAYS);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3725,7 +3722,7 @@ void CClient::Con_Record(IConsole::IResult *pResult, void *pUserData)
|
|||
void CClient::Con_StopRecord(IConsole::IResult *pResult, void *pUserData)
|
||||
{
|
||||
CClient *pSelf = (CClient *)pUserData;
|
||||
pSelf->DemoRecorder_Stop(RECORDER_MANUAL);
|
||||
pSelf->DemoRecorder(RECORDER_MANUAL)->Stop(IDemoRecorder::EStopMode::KEEP_FILE);
|
||||
}
|
||||
|
||||
void CClient::Con_AddDemoMarker(IConsole::IResult *pResult, void *pUserData)
|
||||
|
@ -4019,17 +4016,7 @@ void CClient::ConchainReplays(IConsole::IResult *pResult, void *pUserData, ICons
|
|||
pfnCallback(pResult, pCallbackUserData);
|
||||
if(pResult->NumArguments())
|
||||
{
|
||||
int Status = pResult->GetInteger(0);
|
||||
if(Status == 0)
|
||||
{
|
||||
// stop recording and remove the tmp demo file
|
||||
pSelf->DemoRecorder_Stop(RECORDER_REPLAYS, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// start recording
|
||||
pSelf->DemoRecorder_HandleAutoStart();
|
||||
}
|
||||
pSelf->DemoRecorder_UpdateReplayRecorder();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4562,7 +4549,9 @@ void CClient::RaceRecord_Start(const char *pFilename)
|
|||
void CClient::RaceRecord_Stop()
|
||||
{
|
||||
if(m_aDemoRecorder[RECORDER_RACE].IsRecording())
|
||||
m_aDemoRecorder[RECORDER_RACE].Stop();
|
||||
{
|
||||
m_aDemoRecorder[RECORDER_RACE].Stop(IDemoRecorder::EStopMode::KEEP_FILE);
|
||||
}
|
||||
}
|
||||
|
||||
bool CClient::RaceRecord_IsRecording()
|
||||
|
|
|
@ -119,7 +119,6 @@ class CClient : public IClient, public CDemoPlayer::IListener
|
|||
int m_UseTempRconCommands = 0;
|
||||
char m_aPassword[sizeof(g_Config.m_Password)] = "";
|
||||
bool m_SendPassword = false;
|
||||
bool m_ButtonRender = false;
|
||||
|
||||
// version-checking
|
||||
char m_aVersionStr[10] = "0";
|
||||
|
@ -437,8 +436,7 @@ public:
|
|||
const char *DemoPlayer_Play(const char *pFilename, int StorageType) override;
|
||||
void DemoRecorder_Start(const char *pFilename, bool WithTimestamp, int Recorder, bool Verbose = false) override;
|
||||
void DemoRecorder_HandleAutoStart() override;
|
||||
void DemoRecorder_StartReplayRecorder();
|
||||
void DemoRecorder_Stop(int Recorder, bool RemoveFile = false) override;
|
||||
void DemoRecorder_UpdateReplayRecorder() override;
|
||||
void DemoRecorder_AddDemoMarker(int Recorder);
|
||||
IDemoRecorder *DemoRecorder(int Recorder) override;
|
||||
|
||||
|
|
|
@ -101,11 +101,17 @@ class IDemoRecorder : public IInterface
|
|||
{
|
||||
MACRO_INTERFACE("demorecorder")
|
||||
public:
|
||||
enum class EStopMode
|
||||
{
|
||||
KEEP_FILE,
|
||||
REMOVE_FILE,
|
||||
};
|
||||
|
||||
virtual ~IDemoRecorder() {}
|
||||
virtual bool IsRecording() const = 0;
|
||||
virtual int Stop() = 0;
|
||||
virtual int Stop(IDemoRecorder::EStopMode Mode, const char *pTargetFilename = "") = 0;
|
||||
virtual int Length() const = 0;
|
||||
virtual char *GetCurrentFilename() = 0;
|
||||
virtual const char *CurrentFilename() const = 0;
|
||||
};
|
||||
|
||||
class IDemoEditor : public IInterface
|
||||
|
|
|
@ -3412,12 +3412,14 @@ void CServer::DemoRecorder_HandleAutoStart()
|
|||
{
|
||||
if(Config()->m_SvAutoDemoRecord)
|
||||
{
|
||||
m_aDemoRecorder[RECORDER_AUTO].Stop();
|
||||
m_aDemoRecorder[RECORDER_AUTO].Stop(IDemoRecorder::EStopMode::KEEP_FILE);
|
||||
|
||||
char aTimestamp[20];
|
||||
str_timestamp(aTimestamp, sizeof(aTimestamp));
|
||||
char aFilename[IO_MAX_PATH_LENGTH];
|
||||
char aDate[20];
|
||||
str_timestamp(aDate, sizeof(aDate));
|
||||
str_format(aFilename, sizeof(aFilename), "demos/auto/server/%s_%s.demo", m_aCurrentMap, aDate);
|
||||
str_format(aFilename, sizeof(aFilename), "demos/auto/server/%s_%s.demo", m_aCurrentMap, aTimestamp);
|
||||
m_aDemoRecorder[RECORDER_AUTO].Start(Storage(), m_pConsole, aFilename, GameServer()->NetVersion(), m_aCurrentMap, m_aCurrentMapSha256[MAP_TYPE_SIX], m_aCurrentMapCrc[MAP_TYPE_SIX], "server", m_aCurrentMapSize[MAP_TYPE_SIX], m_apCurrentMapData[MAP_TYPE_SIX]);
|
||||
|
||||
if(Config()->m_SvAutoDemoMax)
|
||||
{
|
||||
// clean up auto recorded demos
|
||||
|
@ -3431,14 +3433,9 @@ void CServer::SaveDemo(int ClientID, float Time)
|
|||
{
|
||||
if(IsRecording(ClientID))
|
||||
{
|
||||
m_aDemoRecorder[ClientID].Stop();
|
||||
|
||||
// rename the demo
|
||||
char aOldFilename[IO_MAX_PATH_LENGTH];
|
||||
char aNewFilename[IO_MAX_PATH_LENGTH];
|
||||
str_format(aOldFilename, sizeof(aOldFilename), "demos/%s_%d_%d_tmp.demo", m_aCurrentMap, m_NetServer.Address().port, ClientID);
|
||||
str_format(aNewFilename, sizeof(aNewFilename), "demos/%s_%s_%05.2f.demo", m_aCurrentMap, m_aClients[ClientID].m_aName, Time);
|
||||
Storage()->RenameFile(aOldFilename, aNewFilename, IStorage::TYPE_SAVE);
|
||||
m_aDemoRecorder[ClientID].Stop(IDemoRecorder::EStopMode::KEEP_FILE, aNewFilename);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3456,11 +3453,7 @@ void CServer::StopRecord(int ClientID)
|
|||
{
|
||||
if(IsRecording(ClientID))
|
||||
{
|
||||
m_aDemoRecorder[ClientID].Stop();
|
||||
|
||||
char aFilename[IO_MAX_PATH_LENGTH];
|
||||
str_format(aFilename, sizeof(aFilename), "demos/%s_%d_%d_tmp.demo", m_aCurrentMap, m_NetServer.Address().port, ClientID);
|
||||
Storage()->RemoveFile(aFilename, IStorage::TYPE_SAVE);
|
||||
m_aDemoRecorder[ClientID].Stop(IDemoRecorder::EStopMode::REMOVE_FILE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3476,22 +3469,13 @@ void CServer::StopDemos()
|
|||
if(!m_aDemoRecorder[i].IsRecording())
|
||||
continue;
|
||||
|
||||
m_aDemoRecorder[i].Stop();
|
||||
|
||||
// remove tmp demos
|
||||
if(i < MAX_CLIENTS)
|
||||
{
|
||||
char aPath[256];
|
||||
str_format(aPath, sizeof(aPath), "demos/%s_%d_%d_tmp.demo", m_aCurrentMap, m_NetServer.Address().port, i);
|
||||
Storage()->RemoveFile(aPath, IStorage::TYPE_SAVE);
|
||||
}
|
||||
m_aDemoRecorder[i].Stop(i < MAX_CLIENTS ? IDemoRecorder::EStopMode::REMOVE_FILE : IDemoRecorder::EStopMode::KEEP_FILE);
|
||||
}
|
||||
}
|
||||
|
||||
void CServer::ConRecord(IConsole::IResult *pResult, void *pUser)
|
||||
{
|
||||
CServer *pServer = (CServer *)pUser;
|
||||
char aFilename[IO_MAX_PATH_LENGTH];
|
||||
|
||||
if(pServer->IsRecording(RECORDER_MANUAL))
|
||||
{
|
||||
|
@ -3499,20 +3483,23 @@ void CServer::ConRecord(IConsole::IResult *pResult, void *pUser)
|
|||
return;
|
||||
}
|
||||
|
||||
char aFilename[IO_MAX_PATH_LENGTH];
|
||||
if(pResult->NumArguments())
|
||||
{
|
||||
str_format(aFilename, sizeof(aFilename), "demos/%s.demo", pResult->GetString(0));
|
||||
}
|
||||
else
|
||||
{
|
||||
char aDate[20];
|
||||
str_timestamp(aDate, sizeof(aDate));
|
||||
str_format(aFilename, sizeof(aFilename), "demos/demo_%s.demo", aDate);
|
||||
char aTimestamp[20];
|
||||
str_timestamp(aTimestamp, sizeof(aTimestamp));
|
||||
str_format(aFilename, sizeof(aFilename), "demos/demo_%s.demo", aTimestamp);
|
||||
}
|
||||
pServer->m_aDemoRecorder[RECORDER_MANUAL].Start(pServer->Storage(), pServer->Console(), aFilename, pServer->GameServer()->NetVersion(), pServer->m_aCurrentMap, pServer->m_aCurrentMapSha256[MAP_TYPE_SIX], pServer->m_aCurrentMapCrc[MAP_TYPE_SIX], "server", pServer->m_aCurrentMapSize[MAP_TYPE_SIX], pServer->m_apCurrentMapData[MAP_TYPE_SIX]);
|
||||
}
|
||||
|
||||
void CServer::ConStopRecord(IConsole::IResult *pResult, void *pUser)
|
||||
{
|
||||
((CServer *)pUser)->m_aDemoRecorder[RECORDER_MANUAL].Stop();
|
||||
((CServer *)pUser)->m_aDemoRecorder[RECORDER_MANUAL].Stop(IDemoRecorder::EStopMode::KEEP_FILE);
|
||||
}
|
||||
|
||||
void CServer::ConMapReload(IConsole::IResult *pResult, void *pUser)
|
||||
|
|
|
@ -62,18 +62,15 @@ int CDemoRecorder::Start(class IStorage *pStorage, class IConsole *pConsole, con
|
|||
{
|
||||
dbg_assert(m_File == 0, "Demo recorder already recording");
|
||||
|
||||
m_pfnFilter = pfnFilter;
|
||||
m_pUser = pUser;
|
||||
|
||||
m_pMapData = pMapData;
|
||||
m_pConsole = pConsole;
|
||||
m_pStorage = pStorage;
|
||||
|
||||
IOHANDLE DemoFile = pStorage->OpenFile(pFilename, IOFLAG_WRITE, IStorage::TYPE_SAVE);
|
||||
if(!DemoFile)
|
||||
{
|
||||
if(m_pConsole)
|
||||
{
|
||||
char aBuf[256];
|
||||
char aBuf[64 + IO_MAX_PATH_LENGTH];
|
||||
str_format(aBuf, sizeof(aBuf), "Unable to open '%s' for recording", pFilename);
|
||||
m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "demo_recorder", aBuf, gs_DemoPrintColor);
|
||||
}
|
||||
|
@ -186,6 +183,10 @@ int CDemoRecorder::Start(class IStorage *pStorage, class IConsole *pConsole, con
|
|||
str_format(aBuf, sizeof(aBuf), "Recording to '%s'", pFilename);
|
||||
m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "demo_recorder", aBuf, gs_DemoPrintColor);
|
||||
}
|
||||
|
||||
m_pfnFilter = pfnFilter;
|
||||
m_pUser = pUser;
|
||||
|
||||
m_File = DemoFile;
|
||||
str_copy(m_aCurrentFilename, pFilename);
|
||||
|
||||
|
@ -337,33 +338,68 @@ void CDemoRecorder::RecordMessage(const void *pData, int Size)
|
|||
Write(CHUNKTYPE_MESSAGE, pData, Size);
|
||||
}
|
||||
|
||||
int CDemoRecorder::Stop()
|
||||
int CDemoRecorder::Stop(IDemoRecorder::EStopMode Mode, const char *pTargetFilename)
|
||||
{
|
||||
if(!m_File)
|
||||
return -1;
|
||||
|
||||
// add the demo length to the header
|
||||
io_seek(m_File, gs_LengthOffset, IOSEEK_START);
|
||||
unsigned char aLength[sizeof(int32_t)];
|
||||
uint_to_bytes_be(aLength, Length());
|
||||
io_write(m_File, aLength, sizeof(aLength));
|
||||
|
||||
// add the timeline markers to the header
|
||||
io_seek(m_File, gs_NumMarkersOffset, IOSEEK_START);
|
||||
unsigned char aNumMarkers[sizeof(int32_t)];
|
||||
uint_to_bytes_be(aNumMarkers, m_NumTimelineMarkers);
|
||||
io_write(m_File, aNumMarkers, sizeof(aNumMarkers));
|
||||
for(int i = 0; i < m_NumTimelineMarkers; i++)
|
||||
if(Mode == IDemoRecorder::EStopMode::KEEP_FILE)
|
||||
{
|
||||
unsigned char aMarker[sizeof(int32_t)];
|
||||
uint_to_bytes_be(aMarker, m_aTimelineMarkers[i]);
|
||||
io_write(m_File, aMarker, sizeof(aMarker));
|
||||
// add the demo length to the header
|
||||
io_seek(m_File, gs_LengthOffset, IOSEEK_START);
|
||||
unsigned char aLength[sizeof(int32_t)];
|
||||
uint_to_bytes_be(aLength, Length());
|
||||
io_write(m_File, aLength, sizeof(aLength));
|
||||
|
||||
// add the timeline markers to the header
|
||||
io_seek(m_File, gs_NumMarkersOffset, IOSEEK_START);
|
||||
unsigned char aNumMarkers[sizeof(int32_t)];
|
||||
uint_to_bytes_be(aNumMarkers, m_NumTimelineMarkers);
|
||||
io_write(m_File, aNumMarkers, sizeof(aNumMarkers));
|
||||
for(int i = 0; i < m_NumTimelineMarkers; i++)
|
||||
{
|
||||
unsigned char aMarker[sizeof(int32_t)];
|
||||
uint_to_bytes_be(aMarker, m_aTimelineMarkers[i]);
|
||||
io_write(m_File, aMarker, sizeof(aMarker));
|
||||
}
|
||||
}
|
||||
|
||||
io_close(m_File);
|
||||
m_File = 0;
|
||||
|
||||
if(Mode == IDemoRecorder::EStopMode::REMOVE_FILE)
|
||||
{
|
||||
if(!m_pStorage->RemoveFile(m_aCurrentFilename, IStorage::TYPE_SAVE))
|
||||
{
|
||||
if(m_pConsole)
|
||||
{
|
||||
char aBuf[64 + IO_MAX_PATH_LENGTH];
|
||||
str_format(aBuf, sizeof(aBuf), "Could not remove demo file '%s'.", m_aCurrentFilename);
|
||||
m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "demo_recorder", aBuf, gs_DemoPrintColor);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if(pTargetFilename[0] != '\0')
|
||||
{
|
||||
if(!m_pStorage->RenameFile(m_aCurrentFilename, pTargetFilename, IStorage::TYPE_SAVE))
|
||||
{
|
||||
if(m_pConsole)
|
||||
{
|
||||
char aBuf[64 + 2 * IO_MAX_PATH_LENGTH];
|
||||
str_format(aBuf, sizeof(aBuf), "Could not move demo file '%s' to '%s'.", m_aCurrentFilename, pTargetFilename);
|
||||
m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "demo_recorder", aBuf, gs_DemoPrintColor);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if(m_pConsole)
|
||||
m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "demo_recorder", "Stopped recording", gs_DemoPrintColor);
|
||||
{
|
||||
char aBuf[64 + IO_MAX_PATH_LENGTH];
|
||||
str_format(aBuf, sizeof(aBuf), "Stopped recording to '%s'", m_aCurrentFilename);
|
||||
m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "demo_recorder", aBuf, gs_DemoPrintColor);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1229,5 +1265,5 @@ void CDemoEditor::Slice(const char *pDemo, const char *pDst, int StartTick, int
|
|||
}
|
||||
|
||||
DemoPlayer.Stop();
|
||||
DemoRecorder.Stop();
|
||||
DemoRecorder.Stop(IDemoRecorder::EStopMode::KEEP_FILE);
|
||||
}
|
||||
|
|
|
@ -18,17 +18,21 @@ typedef std::function<void()> TUpdateIntraTimesFunc;
|
|||
class CDemoRecorder : public IDemoRecorder
|
||||
{
|
||||
class IConsole *m_pConsole;
|
||||
class IStorage *m_pStorage;
|
||||
|
||||
IOHANDLE m_File;
|
||||
char m_aCurrentFilename[IO_MAX_PATH_LENGTH];
|
||||
int m_LastTickMarker;
|
||||
int m_LastKeyFrame;
|
||||
int m_FirstTick;
|
||||
|
||||
unsigned char m_aLastSnapshotData[CSnapshot::MAX_SIZE];
|
||||
class CSnapshotDelta *m_pSnapshotDelta;
|
||||
|
||||
int m_NumTimelineMarkers;
|
||||
int m_aTimelineMarkers[MAX_TIMELINE_MARKERS];
|
||||
|
||||
bool m_NoMapData;
|
||||
unsigned char *m_pMapData;
|
||||
|
||||
DEMOFUNC_FILTER m_pfnFilter;
|
||||
void *m_pUser;
|
||||
|
@ -42,7 +46,7 @@ public:
|
|||
~CDemoRecorder() override;
|
||||
|
||||
int Start(class IStorage *pStorage, class IConsole *pConsole, const char *pFilename, const char *pNetversion, const char *pMap, const SHA256_DIGEST &Sha256, unsigned MapCrc, const char *pType, unsigned MapSize, unsigned char *pMapData, IOHANDLE MapFile = nullptr, DEMOFUNC_FILTER pfnFilter = nullptr, void *pUser = nullptr);
|
||||
int Stop() override;
|
||||
int Stop(IDemoRecorder::EStopMode Mode, const char *pTargetFilename = "") override;
|
||||
|
||||
void AddDemoMarker();
|
||||
void AddDemoMarker(int Tick);
|
||||
|
@ -51,8 +55,7 @@ public:
|
|||
void RecordMessage(const void *pData, int Size);
|
||||
|
||||
bool IsRecording() const override { return m_File != nullptr; }
|
||||
char *GetCurrentFilename() override { return m_aCurrentFilename; }
|
||||
void ClearCurrentFilename() { m_aCurrentFilename[0] = '\0'; }
|
||||
const char *CurrentFilename() const override { return m_aCurrentFilename; }
|
||||
|
||||
int Length() const override { return (m_LastTickMarker - m_FirstTick) / SERVER_TICK_SPEED; }
|
||||
};
|
||||
|
|
|
@ -105,13 +105,13 @@ void CMenus::RenderGame(CUIRect MainView)
|
|||
ButtonBar.VSplitRight(140.0f, &ButtonBar, &Button);
|
||||
|
||||
static CButtonContainer s_DemoButton;
|
||||
bool Recording = DemoRecorder(RECORDER_MANUAL)->IsRecording();
|
||||
const bool Recording = DemoRecorder(RECORDER_MANUAL)->IsRecording();
|
||||
if(DoButton_Menu(&s_DemoButton, Recording ? Localize("Stop record") : Localize("Record demo"), 0, &Button))
|
||||
{
|
||||
if(!Recording)
|
||||
Client()->DemoRecorder_Start(Client()->GetCurrentMap(), true, RECORDER_MANUAL);
|
||||
else
|
||||
Client()->DemoRecorder_Stop(RECORDER_MANUAL);
|
||||
Client()->DemoRecorder(RECORDER_MANUAL)->Stop(IDemoRecorder::EStopMode::KEEP_FILE);
|
||||
}
|
||||
|
||||
static CButtonContainer s_SpectateButton;
|
||||
|
|
|
@ -3194,16 +3194,7 @@ void CMenus::RenderSettingsDDNet(CUIRect MainView)
|
|||
if(DoButton_CheckBox(&g_Config.m_ClReplays, Localize("Enable replays"), g_Config.m_ClReplays, &Button))
|
||||
{
|
||||
g_Config.m_ClReplays ^= 1;
|
||||
if(!g_Config.m_ClReplays)
|
||||
{
|
||||
// stop recording and remove the tmp demo file
|
||||
Client()->DemoRecorder_Stop(RECORDER_REPLAYS, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// start recording
|
||||
Client()->DemoRecorder_HandleAutoStart();
|
||||
}
|
||||
Client()->DemoRecorder_UpdateReplayRecorder();
|
||||
}
|
||||
|
||||
Left.HSplitTop(20.0f, &Button, &Left);
|
||||
|
|
Loading…
Reference in a new issue