mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-20 15:08:19 +00:00
Merge pull request #7837 from Robyt3/Demo-Recorder-Improvements
Refactor demo recorder usage
This commit is contained in:
commit
fca6e0abe3
|
@ -165,7 +165,7 @@ public:
|
||||||
#endif
|
#endif
|
||||||
virtual void DemoRecorder_Start(const char *pFilename, bool WithTimestamp, int Recorder, bool Verbose = false) = 0;
|
virtual void DemoRecorder_Start(const char *pFilename, bool WithTimestamp, int Recorder, bool Verbose = false) = 0;
|
||||||
virtual void DemoRecorder_HandleAutoStart() = 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 class IDemoRecorder *DemoRecorder(int Recorder) = 0;
|
||||||
virtual void AutoScreenshot_Start() = 0;
|
virtual void AutoScreenshot_Start() = 0;
|
||||||
virtual void AutoStatScreenshot_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);
|
m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "client", aBuf, gs_ClientNetworkPrintColor);
|
||||||
|
|
||||||
// stop demo playback and recorder
|
// stop demo playback and recorder
|
||||||
|
// make sure to remove replay tmp demo
|
||||||
m_DemoPlayer.Stop();
|
m_DemoPlayer.Stop();
|
||||||
for(int i = 0; i < RECORDER_MAX; i++)
|
for(int Recorder = 0; Recorder < RECORDER_MAX; Recorder++)
|
||||||
DemoRecorder_Stop(i);
|
{
|
||||||
|
DemoRecorder(Recorder)->Stop(Recorder == RECORDER_REPLAYS ? IDemoRecorder::EStopMode::REMOVE_FILE : IDemoRecorder::EStopMode::KEEP_FILE);
|
||||||
|
}
|
||||||
|
|
||||||
//
|
|
||||||
m_aRconAuthed[0] = 0;
|
m_aRconAuthed[0] = 0;
|
||||||
mem_zero(m_aRconUsername, sizeof(m_aRconUsername));
|
mem_zero(m_aRconUsername, sizeof(m_aRconUsername));
|
||||||
mem_zero(m_aRconPassword, sizeof(m_aRconPassword));
|
mem_zero(m_aRconPassword, sizeof(m_aRconPassword));
|
||||||
|
@ -581,14 +583,9 @@ void CClient::DisconnectWithReason(const char *pReason)
|
||||||
|
|
||||||
void CClient::Disconnect()
|
void CClient::Disconnect()
|
||||||
{
|
{
|
||||||
m_ButtonRender = false;
|
|
||||||
if(m_State != IClient::STATE_OFFLINE)
|
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
|
// stop demo recording if we loaded a new map
|
||||||
for(int i = 0; i < RECORDER_MAX; i++)
|
for(int Recorder = 0; Recorder < RECORDER_MAX; Recorder++)
|
||||||
DemoRecorder_Stop(i, i == RECORDER_REPLAYS);
|
{
|
||||||
|
DemoRecorder(Recorder)->Stop(Recorder == RECORDER_REPLAYS ? IDemoRecorder::EStopMode::REMOVE_FILE : IDemoRecorder::EStopMode::KEEP_FILE);
|
||||||
|
}
|
||||||
|
|
||||||
char aBuf[256];
|
char aBuf[256];
|
||||||
str_format(aBuf, sizeof(aBuf), "loaded map '%s'", pFilename);
|
str_format(aBuf, sizeof(aBuf), "loaded map '%s'", pFilename);
|
||||||
|
@ -2352,22 +2351,20 @@ void CClient::Update()
|
||||||
{
|
{
|
||||||
if(State() == IClient::STATE_DEMOPLAYBACK)
|
if(State() == IClient::STATE_DEMOPLAYBACK)
|
||||||
{
|
{
|
||||||
|
if(m_DemoPlayer.IsPlaying())
|
||||||
|
{
|
||||||
#if defined(CONF_VIDEORECORDER)
|
#if defined(CONF_VIDEORECORDER)
|
||||||
if(m_DemoPlayer.IsPlaying() && IVideo::Current())
|
if(IVideo::Current())
|
||||||
{
|
{
|
||||||
IVideo::Current()->NextVideoFrame();
|
IVideo::Current()->NextVideoFrame();
|
||||||
IVideo::Current()->NextAudioFrameTimeline([this](short *pFinalOut, unsigned Frames) {
|
IVideo::Current()->NextAudioFrameTimeline([this](short *pFinalOut, unsigned Frames) {
|
||||||
Sound()->Mix(pFinalOut, Frames);
|
Sound()->Mix(pFinalOut, Frames);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else if(m_ButtonRender)
|
|
||||||
Disconnect();
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
m_DemoPlayer.Update();
|
m_DemoPlayer.Update();
|
||||||
|
|
||||||
if(m_DemoPlayer.IsPlaying())
|
|
||||||
{
|
|
||||||
// update timers
|
// update timers
|
||||||
const CDemoPlayer::CPlaybackInfo *pInfo = m_DemoPlayer.Info();
|
const CDemoPlayer::CPlaybackInfo *pInfo = m_DemoPlayer.Info();
|
||||||
m_aCurGameTick[g_Config.m_ClDummy] = pInfo->m_Info.m_CurrentTick;
|
m_aCurGameTick[g_Config.m_ClDummy] = pInfo->m_Info.m_CurrentTick;
|
||||||
|
@ -2377,7 +2374,8 @@ void CClient::Update()
|
||||||
}
|
}
|
||||||
else
|
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());
|
DisconnectWithReason(m_DemoPlayer.ErrorMessage());
|
||||||
if(m_DemoPlayer.ErrorMessage()[0] != '\0')
|
if(m_DemoPlayer.ErrorMessage()[0] != '\0')
|
||||||
{
|
{
|
||||||
|
@ -3472,26 +3470,32 @@ void CClient::SaveReplay(const int Length, const char *pFilename)
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!DemoRecorder(RECORDER_REPLAYS)->IsRecording())
|
if(!DemoRecorder(RECORDER_REPLAYS)->IsRecording())
|
||||||
|
{
|
||||||
m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "replay", "ERROR: demorecorder isn't recording. Try to rejoin to fix that.");
|
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)
|
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.");
|
m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "replay", "ERROR: demorecorder isn't recording for at least 1 second.");
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// First we stop the recorder to slice correctly the demo after
|
// First we stop the recorder to slice correctly the demo after
|
||||||
DemoRecorder_Stop(RECORDER_REPLAYS);
|
DemoRecorder(RECORDER_REPLAYS)->Stop(IDemoRecorder::EStopMode::KEEP_FILE);
|
||||||
|
|
||||||
char aDate[64];
|
|
||||||
str_timestamp(aDate, sizeof(aDate));
|
|
||||||
|
|
||||||
char aFilename[IO_MAX_PATH_LENGTH];
|
char aFilename[IO_MAX_PATH_LENGTH];
|
||||||
if(str_comp(pFilename, "") == 0)
|
if(pFilename[0] == '\0')
|
||||||
str_format(aFilename, sizeof(aFilename), "demos/replays/%s_%s (replay).demo", m_aCurrentMap, aDate);
|
{
|
||||||
|
char aTimestamp[20];
|
||||||
|
str_timestamp(aTimestamp, sizeof(aTimestamp));
|
||||||
|
str_format(aFilename, sizeof(aFilename), "demos/replays/%s_%s_(replay).demo", m_aCurrentMap, aTimestamp);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
str_format(aFilename, sizeof(aFilename), "demos/replays/%s.demo", pFilename);
|
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
|
// 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 EndTick = GameTick(g_Config.m_ClDummy);
|
||||||
const int StartTick = EndTick - Length * GameTickSpeed();
|
const int StartTick = EndTick - Length * GameTickSpeed();
|
||||||
|
|
||||||
|
@ -3503,7 +3507,7 @@ void CClient::SaveReplay(const int Length, const char *pFilename)
|
||||||
m_EditJobs.push_back(pDemoEditTask);
|
m_EditJobs.push_back(pDemoEditTask);
|
||||||
|
|
||||||
// And we restart the recorder
|
// 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);
|
const char *pError = DemoPlayer_Play(pFilename, StorageType);
|
||||||
if(pError)
|
if(pError)
|
||||||
return pError;
|
return pError;
|
||||||
m_ButtonRender = true;
|
|
||||||
|
|
||||||
this->CClient::StartVideo(NULL, this, pVideoName);
|
this->CClient::StartVideo(NULL, this, pVideoName);
|
||||||
m_DemoPlayer.Play();
|
m_DemoPlayer.Play();
|
||||||
|
@ -3632,19 +3635,23 @@ void CClient::DemoRecorder_Start(const char *pFilename, bool WithTimestamp, int
|
||||||
if(State() != IClient::STATE_ONLINE)
|
if(State() != IClient::STATE_ONLINE)
|
||||||
{
|
{
|
||||||
if(Verbose)
|
if(Verbose)
|
||||||
|
{
|
||||||
m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "demorec/record", "client is not online");
|
m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "demorec/record", "client is not online");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
char aFilename[IO_MAX_PATH_LENGTH];
|
char aFilename[IO_MAX_PATH_LENGTH];
|
||||||
if(WithTimestamp)
|
if(WithTimestamp)
|
||||||
{
|
{
|
||||||
char aDate[20];
|
char aTimestamp[20];
|
||||||
str_timestamp(aDate, sizeof(aDate));
|
str_timestamp(aTimestamp, sizeof(aTimestamp));
|
||||||
str_format(aFilename, sizeof(aFilename), "demos/%s_%s.demo", pFilename, aDate);
|
str_format(aFilename, sizeof(aFilename), "demos/%s_%s.demo", pFilename, aTimestamp);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
str_format(aFilename, sizeof(aFilename), "demos/%s.demo", pFilename);
|
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());
|
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)
|
if(g_Config.m_ClAutoDemoRecord)
|
||||||
{
|
{
|
||||||
DemoRecorder_Stop(RECORDER_AUTO);
|
DemoRecorder(RECORDER_AUTO)->Stop(IDemoRecorder::EStopMode::KEEP_FILE);
|
||||||
char aBuf[512];
|
|
||||||
str_format(aBuf, sizeof(aBuf), "auto/%s", m_aCurrentMap);
|
char aFilename[IO_MAX_PATH_LENGTH];
|
||||||
DemoRecorder_Start(aBuf, true, RECORDER_AUTO);
|
str_format(aFilename, sizeof(aFilename), "auto/%s", m_aCurrentMap);
|
||||||
|
DemoRecorder_Start(aFilename, true, RECORDER_AUTO);
|
||||||
|
|
||||||
if(g_Config.m_ClAutoDemoMax)
|
if(g_Config.m_ClAutoDemoMax)
|
||||||
{
|
{
|
||||||
// clean up auto recorded demos
|
// 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);
|
AutoDemos.Init(Storage(), "demos/auto", "" /* empty for wild card */, ".demo", g_Config.m_ClAutoDemoMax);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!DemoRecorder(RECORDER_REPLAYS)->IsRecording())
|
|
||||||
{
|
DemoRecorder_UpdateReplayRecorder();
|
||||||
DemoRecorder_StartReplayRecorder();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
DemoRecorder(RECORDER_REPLAYS)->Stop(IDemoRecorder::EStopMode::REMOVE_FILE);
|
||||||
char aBuf[512];
|
|
||||||
str_format(aBuf, sizeof(aBuf), "replays/replay_tmp-%s", m_aCurrentMap);
|
|
||||||
DemoRecorder_Start(aBuf, true, RECORDER_REPLAYS);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void CClient::DemoRecorder_Stop(int Recorder, bool RemoveFile)
|
if(g_Config.m_ClReplays && !DemoRecorder(RECORDER_REPLAYS)->IsRecording())
|
||||||
{
|
|
||||||
m_aDemoRecorder[Recorder].Stop();
|
|
||||||
if(RemoveFile)
|
|
||||||
{
|
{
|
||||||
const char *pFilename = m_aDemoRecorder[Recorder].GetCurrentFilename();
|
char aFilename[IO_MAX_PATH_LENGTH];
|
||||||
if(pFilename[0] != '\0')
|
str_format(aFilename, sizeof(aFilename), "replays/replay_tmp_%s", m_aCurrentMap);
|
||||||
{
|
DemoRecorder_Start(aFilename, true, RECORDER_REPLAYS);
|
||||||
Storage()->RemoveFile(pFilename, IStorage::TYPE_SAVE);
|
|
||||||
m_aDemoRecorder[Recorder].ClearCurrentFilename();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3725,7 +3722,7 @@ void CClient::Con_Record(IConsole::IResult *pResult, void *pUserData)
|
||||||
void CClient::Con_StopRecord(IConsole::IResult *pResult, void *pUserData)
|
void CClient::Con_StopRecord(IConsole::IResult *pResult, void *pUserData)
|
||||||
{
|
{
|
||||||
CClient *pSelf = (CClient *)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)
|
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);
|
pfnCallback(pResult, pCallbackUserData);
|
||||||
if(pResult->NumArguments())
|
if(pResult->NumArguments())
|
||||||
{
|
{
|
||||||
int Status = pResult->GetInteger(0);
|
pSelf->DemoRecorder_UpdateReplayRecorder();
|
||||||
if(Status == 0)
|
|
||||||
{
|
|
||||||
// stop recording and remove the tmp demo file
|
|
||||||
pSelf->DemoRecorder_Stop(RECORDER_REPLAYS, true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// start recording
|
|
||||||
pSelf->DemoRecorder_HandleAutoStart();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4562,7 +4549,9 @@ void CClient::RaceRecord_Start(const char *pFilename)
|
||||||
void CClient::RaceRecord_Stop()
|
void CClient::RaceRecord_Stop()
|
||||||
{
|
{
|
||||||
if(m_aDemoRecorder[RECORDER_RACE].IsRecording())
|
if(m_aDemoRecorder[RECORDER_RACE].IsRecording())
|
||||||
m_aDemoRecorder[RECORDER_RACE].Stop();
|
{
|
||||||
|
m_aDemoRecorder[RECORDER_RACE].Stop(IDemoRecorder::EStopMode::KEEP_FILE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CClient::RaceRecord_IsRecording()
|
bool CClient::RaceRecord_IsRecording()
|
||||||
|
|
|
@ -119,7 +119,6 @@ class CClient : public IClient, public CDemoPlayer::IListener
|
||||||
int m_UseTempRconCommands = 0;
|
int m_UseTempRconCommands = 0;
|
||||||
char m_aPassword[sizeof(g_Config.m_Password)] = "";
|
char m_aPassword[sizeof(g_Config.m_Password)] = "";
|
||||||
bool m_SendPassword = false;
|
bool m_SendPassword = false;
|
||||||
bool m_ButtonRender = false;
|
|
||||||
|
|
||||||
// version-checking
|
// version-checking
|
||||||
char m_aVersionStr[10] = "0";
|
char m_aVersionStr[10] = "0";
|
||||||
|
@ -437,8 +436,7 @@ public:
|
||||||
const char *DemoPlayer_Play(const char *pFilename, int StorageType) override;
|
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_Start(const char *pFilename, bool WithTimestamp, int Recorder, bool Verbose = false) override;
|
||||||
void DemoRecorder_HandleAutoStart() override;
|
void DemoRecorder_HandleAutoStart() override;
|
||||||
void DemoRecorder_StartReplayRecorder();
|
void DemoRecorder_UpdateReplayRecorder() override;
|
||||||
void DemoRecorder_Stop(int Recorder, bool RemoveFile = false) override;
|
|
||||||
void DemoRecorder_AddDemoMarker(int Recorder);
|
void DemoRecorder_AddDemoMarker(int Recorder);
|
||||||
IDemoRecorder *DemoRecorder(int Recorder) override;
|
IDemoRecorder *DemoRecorder(int Recorder) override;
|
||||||
|
|
||||||
|
|
|
@ -101,11 +101,17 @@ class IDemoRecorder : public IInterface
|
||||||
{
|
{
|
||||||
MACRO_INTERFACE("demorecorder")
|
MACRO_INTERFACE("demorecorder")
|
||||||
public:
|
public:
|
||||||
|
enum class EStopMode
|
||||||
|
{
|
||||||
|
KEEP_FILE,
|
||||||
|
REMOVE_FILE,
|
||||||
|
};
|
||||||
|
|
||||||
virtual ~IDemoRecorder() {}
|
virtual ~IDemoRecorder() {}
|
||||||
virtual bool IsRecording() const = 0;
|
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 int Length() const = 0;
|
||||||
virtual char *GetCurrentFilename() = 0;
|
virtual const char *CurrentFilename() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class IDemoEditor : public IInterface
|
class IDemoEditor : public IInterface
|
||||||
|
|
|
@ -3412,12 +3412,14 @@ void CServer::DemoRecorder_HandleAutoStart()
|
||||||
{
|
{
|
||||||
if(Config()->m_SvAutoDemoRecord)
|
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 aFilename[IO_MAX_PATH_LENGTH];
|
||||||
char aDate[20];
|
str_format(aFilename, sizeof(aFilename), "demos/auto/server/%s_%s.demo", m_aCurrentMap, aTimestamp);
|
||||||
str_timestamp(aDate, sizeof(aDate));
|
|
||||||
str_format(aFilename, sizeof(aFilename), "demos/auto/server/%s_%s.demo", m_aCurrentMap, aDate);
|
|
||||||
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]);
|
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)
|
if(Config()->m_SvAutoDemoMax)
|
||||||
{
|
{
|
||||||
// clean up auto recorded demos
|
// clean up auto recorded demos
|
||||||
|
@ -3431,14 +3433,9 @@ void CServer::SaveDemo(int ClientID, float Time)
|
||||||
{
|
{
|
||||||
if(IsRecording(ClientID))
|
if(IsRecording(ClientID))
|
||||||
{
|
{
|
||||||
m_aDemoRecorder[ClientID].Stop();
|
|
||||||
|
|
||||||
// rename the demo
|
|
||||||
char aOldFilename[IO_MAX_PATH_LENGTH];
|
|
||||||
char aNewFilename[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);
|
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))
|
if(IsRecording(ClientID))
|
||||||
{
|
{
|
||||||
m_aDemoRecorder[ClientID].Stop();
|
m_aDemoRecorder[ClientID].Stop(IDemoRecorder::EStopMode::REMOVE_FILE);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3476,22 +3469,13 @@ void CServer::StopDemos()
|
||||||
if(!m_aDemoRecorder[i].IsRecording())
|
if(!m_aDemoRecorder[i].IsRecording())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
m_aDemoRecorder[i].Stop();
|
m_aDemoRecorder[i].Stop(i < MAX_CLIENTS ? IDemoRecorder::EStopMode::REMOVE_FILE : IDemoRecorder::EStopMode::KEEP_FILE);
|
||||||
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CServer::ConRecord(IConsole::IResult *pResult, void *pUser)
|
void CServer::ConRecord(IConsole::IResult *pResult, void *pUser)
|
||||||
{
|
{
|
||||||
CServer *pServer = (CServer *)pUser;
|
CServer *pServer = (CServer *)pUser;
|
||||||
char aFilename[IO_MAX_PATH_LENGTH];
|
|
||||||
|
|
||||||
if(pServer->IsRecording(RECORDER_MANUAL))
|
if(pServer->IsRecording(RECORDER_MANUAL))
|
||||||
{
|
{
|
||||||
|
@ -3499,20 +3483,23 @@ void CServer::ConRecord(IConsole::IResult *pResult, void *pUser)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char aFilename[IO_MAX_PATH_LENGTH];
|
||||||
if(pResult->NumArguments())
|
if(pResult->NumArguments())
|
||||||
|
{
|
||||||
str_format(aFilename, sizeof(aFilename), "demos/%s.demo", pResult->GetString(0));
|
str_format(aFilename, sizeof(aFilename), "demos/%s.demo", pResult->GetString(0));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
char aDate[20];
|
char aTimestamp[20];
|
||||||
str_timestamp(aDate, sizeof(aDate));
|
str_timestamp(aTimestamp, sizeof(aTimestamp));
|
||||||
str_format(aFilename, sizeof(aFilename), "demos/demo_%s.demo", aDate);
|
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]);
|
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)
|
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)
|
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");
|
dbg_assert(m_File == 0, "Demo recorder already recording");
|
||||||
|
|
||||||
m_pfnFilter = pfnFilter;
|
|
||||||
m_pUser = pUser;
|
|
||||||
|
|
||||||
m_pMapData = pMapData;
|
|
||||||
m_pConsole = pConsole;
|
m_pConsole = pConsole;
|
||||||
|
m_pStorage = pStorage;
|
||||||
|
|
||||||
IOHANDLE DemoFile = pStorage->OpenFile(pFilename, IOFLAG_WRITE, IStorage::TYPE_SAVE);
|
IOHANDLE DemoFile = pStorage->OpenFile(pFilename, IOFLAG_WRITE, IStorage::TYPE_SAVE);
|
||||||
if(!DemoFile)
|
if(!DemoFile)
|
||||||
{
|
{
|
||||||
if(m_pConsole)
|
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);
|
str_format(aBuf, sizeof(aBuf), "Unable to open '%s' for recording", pFilename);
|
||||||
m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "demo_recorder", aBuf, gs_DemoPrintColor);
|
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);
|
str_format(aBuf, sizeof(aBuf), "Recording to '%s'", pFilename);
|
||||||
m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "demo_recorder", aBuf, gs_DemoPrintColor);
|
m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "demo_recorder", aBuf, gs_DemoPrintColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_pfnFilter = pfnFilter;
|
||||||
|
m_pUser = pUser;
|
||||||
|
|
||||||
m_File = DemoFile;
|
m_File = DemoFile;
|
||||||
str_copy(m_aCurrentFilename, pFilename);
|
str_copy(m_aCurrentFilename, pFilename);
|
||||||
|
|
||||||
|
@ -337,11 +338,13 @@ void CDemoRecorder::RecordMessage(const void *pData, int Size)
|
||||||
Write(CHUNKTYPE_MESSAGE, pData, Size);
|
Write(CHUNKTYPE_MESSAGE, pData, Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
int CDemoRecorder::Stop()
|
int CDemoRecorder::Stop(IDemoRecorder::EStopMode Mode, const char *pTargetFilename)
|
||||||
{
|
{
|
||||||
if(!m_File)
|
if(!m_File)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
if(Mode == IDemoRecorder::EStopMode::KEEP_FILE)
|
||||||
|
{
|
||||||
// add the demo length to the header
|
// add the demo length to the header
|
||||||
io_seek(m_File, gs_LengthOffset, IOSEEK_START);
|
io_seek(m_File, gs_LengthOffset, IOSEEK_START);
|
||||||
unsigned char aLength[sizeof(int32_t)];
|
unsigned char aLength[sizeof(int32_t)];
|
||||||
|
@ -359,11 +362,44 @@ int CDemoRecorder::Stop()
|
||||||
uint_to_bytes_be(aMarker, m_aTimelineMarkers[i]);
|
uint_to_bytes_be(aMarker, m_aTimelineMarkers[i]);
|
||||||
io_write(m_File, aMarker, sizeof(aMarker));
|
io_write(m_File, aMarker, sizeof(aMarker));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
io_close(m_File);
|
io_close(m_File);
|
||||||
m_File = 0;
|
m_File = 0;
|
||||||
|
|
||||||
|
if(Mode == IDemoRecorder::EStopMode::REMOVE_FILE)
|
||||||
|
{
|
||||||
|
if(!m_pStorage->RemoveFile(m_aCurrentFilename, IStorage::TYPE_SAVE))
|
||||||
|
{
|
||||||
if(m_pConsole)
|
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), "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)
|
||||||
|
{
|
||||||
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1229,5 +1265,5 @@ void CDemoEditor::Slice(const char *pDemo, const char *pDst, int StartTick, int
|
||||||
}
|
}
|
||||||
|
|
||||||
DemoPlayer.Stop();
|
DemoPlayer.Stop();
|
||||||
DemoRecorder.Stop();
|
DemoRecorder.Stop(IDemoRecorder::EStopMode::KEEP_FILE);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,17 +18,21 @@ typedef std::function<void()> TUpdateIntraTimesFunc;
|
||||||
class CDemoRecorder : public IDemoRecorder
|
class CDemoRecorder : public IDemoRecorder
|
||||||
{
|
{
|
||||||
class IConsole *m_pConsole;
|
class IConsole *m_pConsole;
|
||||||
|
class IStorage *m_pStorage;
|
||||||
|
|
||||||
IOHANDLE m_File;
|
IOHANDLE m_File;
|
||||||
char m_aCurrentFilename[IO_MAX_PATH_LENGTH];
|
char m_aCurrentFilename[IO_MAX_PATH_LENGTH];
|
||||||
int m_LastTickMarker;
|
int m_LastTickMarker;
|
||||||
int m_LastKeyFrame;
|
int m_LastKeyFrame;
|
||||||
int m_FirstTick;
|
int m_FirstTick;
|
||||||
|
|
||||||
unsigned char m_aLastSnapshotData[CSnapshot::MAX_SIZE];
|
unsigned char m_aLastSnapshotData[CSnapshot::MAX_SIZE];
|
||||||
class CSnapshotDelta *m_pSnapshotDelta;
|
class CSnapshotDelta *m_pSnapshotDelta;
|
||||||
|
|
||||||
int m_NumTimelineMarkers;
|
int m_NumTimelineMarkers;
|
||||||
int m_aTimelineMarkers[MAX_TIMELINE_MARKERS];
|
int m_aTimelineMarkers[MAX_TIMELINE_MARKERS];
|
||||||
|
|
||||||
bool m_NoMapData;
|
bool m_NoMapData;
|
||||||
unsigned char *m_pMapData;
|
|
||||||
|
|
||||||
DEMOFUNC_FILTER m_pfnFilter;
|
DEMOFUNC_FILTER m_pfnFilter;
|
||||||
void *m_pUser;
|
void *m_pUser;
|
||||||
|
@ -42,7 +46,7 @@ public:
|
||||||
~CDemoRecorder() override;
|
~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 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();
|
||||||
void AddDemoMarker(int Tick);
|
void AddDemoMarker(int Tick);
|
||||||
|
@ -51,8 +55,7 @@ public:
|
||||||
void RecordMessage(const void *pData, int Size);
|
void RecordMessage(const void *pData, int Size);
|
||||||
|
|
||||||
bool IsRecording() const override { return m_File != nullptr; }
|
bool IsRecording() const override { return m_File != nullptr; }
|
||||||
char *GetCurrentFilename() override { return m_aCurrentFilename; }
|
const char *CurrentFilename() const override { return m_aCurrentFilename; }
|
||||||
void ClearCurrentFilename() { m_aCurrentFilename[0] = '\0'; }
|
|
||||||
|
|
||||||
int Length() const override { return (m_LastTickMarker - m_FirstTick) / SERVER_TICK_SPEED; }
|
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);
|
ButtonBar.VSplitRight(140.0f, &ButtonBar, &Button);
|
||||||
|
|
||||||
static CButtonContainer s_DemoButton;
|
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(DoButton_Menu(&s_DemoButton, Recording ? Localize("Stop record") : Localize("Record demo"), 0, &Button))
|
||||||
{
|
{
|
||||||
if(!Recording)
|
if(!Recording)
|
||||||
Client()->DemoRecorder_Start(Client()->GetCurrentMap(), true, RECORDER_MANUAL);
|
Client()->DemoRecorder_Start(Client()->GetCurrentMap(), true, RECORDER_MANUAL);
|
||||||
else
|
else
|
||||||
Client()->DemoRecorder_Stop(RECORDER_MANUAL);
|
Client()->DemoRecorder(RECORDER_MANUAL)->Stop(IDemoRecorder::EStopMode::KEEP_FILE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static CButtonContainer s_SpectateButton;
|
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))
|
if(DoButton_CheckBox(&g_Config.m_ClReplays, Localize("Enable replays"), g_Config.m_ClReplays, &Button))
|
||||||
{
|
{
|
||||||
g_Config.m_ClReplays ^= 1;
|
g_Config.m_ClReplays ^= 1;
|
||||||
if(!g_Config.m_ClReplays)
|
Client()->DemoRecorder_UpdateReplayRecorder();
|
||||||
{
|
|
||||||
// stop recording and remove the tmp demo file
|
|
||||||
Client()->DemoRecorder_Stop(RECORDER_REPLAYS, true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// start recording
|
|
||||||
Client()->DemoRecorder_HandleAutoStart();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Left.HSplitTop(20.0f, &Button, &Left);
|
Left.HSplitTop(20.0f, &Button, &Left);
|
||||||
|
|
Loading…
Reference in a new issue