mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-10 10:08:18 +00:00
Reworked the race recorder
This commit is contained in:
parent
9e52957423
commit
5cc0d16029
|
@ -175,12 +175,13 @@ public:
|
|||
|
||||
//DDRace
|
||||
|
||||
virtual const char* GetCurrentMap() = 0;
|
||||
virtual int GetCurrentMapCrc() = 0;
|
||||
virtual const char* GetCurrentMapPath() = 0;
|
||||
virtual const char* RaceRecordStart(const char *pFilename) = 0;
|
||||
virtual void RaceRecordStop() = 0;
|
||||
virtual bool RaceRecordIsRecording() = 0;
|
||||
virtual const char *GetCurrentMap() = 0;
|
||||
virtual const char *GetCurrentMapPath() = 0;
|
||||
|
||||
virtual void RaceRecord_GetName(char *pBuf, int Size, int Time = -1) = 0;
|
||||
virtual void RaceRecord_Start() = 0;
|
||||
virtual void RaceRecord_Stop() = 0;
|
||||
virtual bool RaceRecord_IsRecording() = 0;
|
||||
|
||||
virtual void Ghost_GetPath(char *pBuf, int Size, int Time = -1) = 0;
|
||||
virtual void GhostRecorder_Start() = 0;
|
||||
|
|
|
@ -3586,45 +3586,16 @@ int main(int argc, const char **argv) // ignore_convention
|
|||
|
||||
// DDRace
|
||||
|
||||
const char* CClient::GetCurrentMap()
|
||||
const char *CClient::GetCurrentMap()
|
||||
{
|
||||
return m_aCurrentMap;
|
||||
}
|
||||
|
||||
int CClient::GetCurrentMapCrc()
|
||||
{
|
||||
return m_pMap->Crc();
|
||||
}
|
||||
|
||||
const char* CClient::GetCurrentMapPath()
|
||||
const char *CClient::GetCurrentMapPath()
|
||||
{
|
||||
return m_aCurrentMapPath;
|
||||
}
|
||||
|
||||
const char* CClient::RaceRecordStart(const char *pFilename)
|
||||
{
|
||||
char aFilename[128];
|
||||
str_format(aFilename, sizeof(aFilename), "demos/%s_%s.demo", m_aCurrentMap, pFilename);
|
||||
|
||||
if(State() != STATE_ONLINE)
|
||||
dbg_msg("demorec/record", "client is not online");
|
||||
else
|
||||
m_DemoRecorder[RECORDER_RACE].Start(Storage(), m_pConsole, aFilename, GameClient()->NetVersion(), m_aCurrentMap, m_pMap->Crc(), "client", m_pMap->MapSize(), 0, m_pMap->File());
|
||||
|
||||
return m_aCurrentMap;
|
||||
}
|
||||
|
||||
void CClient::RaceRecordStop()
|
||||
{
|
||||
if(m_DemoRecorder[RECORDER_RACE].IsRecording())
|
||||
m_DemoRecorder[RECORDER_RACE].Stop();
|
||||
}
|
||||
|
||||
bool CClient::RaceRecordIsRecording()
|
||||
{
|
||||
return m_DemoRecorder[RECORDER_RACE].IsRecording();
|
||||
}
|
||||
|
||||
void ClearFilename(char *pStr)
|
||||
{
|
||||
while(*pStr)
|
||||
|
@ -3635,6 +3606,48 @@ void ClearFilename(char *pStr)
|
|||
}
|
||||
}
|
||||
|
||||
void CClient::RaceRecord_GetName(char *pBuf, int Size, int Time)
|
||||
{
|
||||
// check the player name
|
||||
char aPlayerName[MAX_NAME_LENGTH];
|
||||
str_copy(aPlayerName, g_Config.m_PlayerName, sizeof(aPlayerName));
|
||||
ClearFilename(aPlayerName);
|
||||
|
||||
if(Time < 0)
|
||||
str_format(pBuf, Size, "%s_tmp_%d", m_aCurrentMap, pid());
|
||||
else if(g_Config.m_ClDemoName)
|
||||
str_format(pBuf, Size, "%s_%d.%03d_%s", m_aCurrentMap, Time / 1000, Time % 1000, aPlayerName);
|
||||
else
|
||||
str_format(pBuf, Size, "%s_%d.%03d", m_aCurrentMap, Time / 1000, Time % 1000);
|
||||
}
|
||||
|
||||
void CClient::RaceRecord_Start()
|
||||
{
|
||||
if(State() != IClient::STATE_ONLINE)
|
||||
m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "demorec/record", "client is not online");
|
||||
else
|
||||
{
|
||||
char aDemoName[128];
|
||||
char aFilename[128];
|
||||
|
||||
RaceRecord_GetName(aDemoName, sizeof(aDemoName));
|
||||
str_format(aFilename, sizeof(aFilename), "demos/%s.demo", aDemoName);
|
||||
|
||||
m_DemoRecorder[RECORDER_RACE].Start(Storage(), m_pConsole, aFilename, GameClient()->NetVersion(), m_aCurrentMap, m_pMap->Crc(), "client", m_pMap->MapSize(), 0, m_pMap->File());
|
||||
}
|
||||
}
|
||||
|
||||
void CClient::RaceRecord_Stop()
|
||||
{
|
||||
if(m_DemoRecorder[RECORDER_RACE].IsRecording())
|
||||
m_DemoRecorder[RECORDER_RACE].Stop();
|
||||
}
|
||||
|
||||
bool CClient::RaceRecord_IsRecording()
|
||||
{
|
||||
return m_DemoRecorder[RECORDER_RACE].IsRecording();
|
||||
}
|
||||
|
||||
void CClient::Ghost_GetPath(char *pBuf, int Size, int Time)
|
||||
{
|
||||
// check the player name
|
||||
|
|
|
@ -383,12 +383,13 @@ public:
|
|||
void GenerateTimeoutSeed();
|
||||
void GenerateTimeoutCodes();
|
||||
|
||||
virtual const char* GetCurrentMap();
|
||||
virtual int GetCurrentMapCrc();
|
||||
virtual const char* GetCurrentMapPath();
|
||||
virtual const char* RaceRecordStart(const char *pFilename);
|
||||
virtual void RaceRecordStop();
|
||||
virtual bool RaceRecordIsRecording();
|
||||
const char *GetCurrentMap();
|
||||
const char *GetCurrentMapPath();
|
||||
|
||||
void RaceRecord_GetName(char *pBuf, int Size, int Time = -1);
|
||||
void RaceRecord_Start();
|
||||
void RaceRecord_Stop();
|
||||
bool RaceRecord_IsRecording();
|
||||
|
||||
void Ghost_GetPath(char *pBuf, int Size, int Time = -1);
|
||||
void GhostRecorder_Start();
|
||||
|
|
|
@ -327,6 +327,8 @@ public:
|
|||
void DemolistPopulate();
|
||||
bool m_Dummy;
|
||||
|
||||
const char *GetCurrentDemoFolder() const { return m_aCurrentDemoFolder; }
|
||||
|
||||
// Ghost
|
||||
struct CGhostItem
|
||||
{
|
||||
|
|
|
@ -9,85 +9,68 @@
|
|||
#include "race.h"
|
||||
#include "race_demo.h"
|
||||
|
||||
CRaceDemo::CRaceDemo()
|
||||
{
|
||||
m_RaceState = RACE_NONE;
|
||||
m_RecordStopTime = 0;
|
||||
m_Time = 0;
|
||||
m_DemoStartTick = 0;
|
||||
}
|
||||
|
||||
void CRaceDemo::Stop()
|
||||
{
|
||||
if(Client()->RaceRecordIsRecording())
|
||||
Client()->RaceRecordStop();
|
||||
|
||||
char aFilename[512];
|
||||
str_format(aFilename, sizeof(aFilename), "demos/%s_tmp_%d.demo", m_pMap, pid());
|
||||
Storage()->RemoveFile(aFilename, IStorage::TYPE_SAVE);
|
||||
|
||||
m_Time = 0;
|
||||
m_RaceState = RACE_NONE;
|
||||
m_RecordStopTime = 0;
|
||||
m_DemoStartTick = 0;
|
||||
}
|
||||
CRaceDemo::CRaceDemo() : m_RaceState(RACE_NONE), m_RecordStartTick(-1), m_RecordStopTick(-1), m_Time(0) {}
|
||||
|
||||
void CRaceDemo::OnStateChange(int NewState, int OldState)
|
||||
{
|
||||
if(OldState == IClient::STATE_ONLINE)
|
||||
Stop();
|
||||
StopRecord();
|
||||
}
|
||||
|
||||
void CRaceDemo::OnRender()
|
||||
{
|
||||
if(!g_Config.m_ClAutoRaceRecord || !m_pClient->m_Snap.m_pGameInfoObj || m_pClient->m_Snap.m_SpecInfo.m_Active || Client()->State() != IClient::STATE_ONLINE)
|
||||
if(!g_Config.m_ClAutoRaceRecord || !m_pClient->m_Snap.m_pLocalCharacter)
|
||||
return;
|
||||
|
||||
// only for race
|
||||
CServerInfo ServerInfo;
|
||||
Client()->GetServerInfo(&ServerInfo);
|
||||
if(!IsRace(&ServerInfo) || !m_pClient->m_NewTick)
|
||||
return;
|
||||
|
||||
// start the demo
|
||||
if((m_RaceState != RACE_STARTED || !m_IsSolo) && m_DemoStartTick < Client()->GameTick() && CRaceHelper::IsStart(m_pClient, m_pClient->m_PredictedPrevChar.m_Pos, m_pClient->m_LocalCharacterPos))
|
||||
if((m_RaceState == RACE_NONE || !m_IsSolo) && m_RecordStartTick + Client()->GameTickSpeed() < Client()->GameTick())
|
||||
{
|
||||
OnReset();
|
||||
char aBuf[512];
|
||||
str_format(aBuf, sizeof(aBuf), "tmp_%d", pid());
|
||||
m_pMap = Client()->RaceRecordStart(aBuf);
|
||||
m_DemoStartTick = Client()->GameTick() + Client()->GameTickSpeed();
|
||||
m_RaceState = RACE_STARTED;
|
||||
vec2 PrevPos = vec2(m_pClient->m_Snap.m_pLocalPrevCharacter->m_X, m_pClient->m_Snap.m_pLocalPrevCharacter->m_Y);
|
||||
vec2 Pos = vec2(m_pClient->m_Snap.m_pLocalCharacter->m_X, m_pClient->m_Snap.m_pLocalCharacter->m_Y);
|
||||
|
||||
if(CRaceHelper::IsStart(m_pClient, m_pClient->m_PredictedPrevChar.m_Pos, m_pClient->m_LocalCharacterPos))
|
||||
{
|
||||
if(m_RaceState == RACE_STARTED)
|
||||
OnReset();
|
||||
Client()->RaceRecord_Start();
|
||||
m_RecordStartTick = Client()->GameTick();
|
||||
m_RaceState = RACE_STARTED;
|
||||
}
|
||||
}
|
||||
|
||||
// stop the demo
|
||||
if(m_RaceState == RACE_FINISHED && m_RecordStopTime < Client()->GameTick() && m_Time > 0)
|
||||
{
|
||||
CheckDemo();
|
||||
OnReset();
|
||||
}
|
||||
if(m_RaceState == RACE_FINISHED && m_RecordStopTick <= Client()->GameTick())
|
||||
StopRecord(m_Time);
|
||||
}
|
||||
|
||||
void CRaceDemo::OnReset()
|
||||
{
|
||||
if(Client()->State() == IClient::STATE_ONLINE)
|
||||
Stop();
|
||||
}
|
||||
|
||||
void CRaceDemo::OnShutdown()
|
||||
{
|
||||
Stop();
|
||||
StopRecord();
|
||||
}
|
||||
|
||||
void CRaceDemo::OnMessage(int MsgType, void *pRawMsg)
|
||||
{
|
||||
if(!g_Config.m_ClAutoRaceRecord || Client()->State() != IClient::STATE_ONLINE || m_pClient->m_Snap.m_SpecInfo.m_Active)
|
||||
if(!g_Config.m_ClAutoRaceRecord || m_pClient->m_Snap.m_SpecInfo.m_Active)
|
||||
return;
|
||||
|
||||
// only for race
|
||||
CServerInfo ServerInfo;
|
||||
Client()->GetServerInfo(&ServerInfo);
|
||||
if(!IsRace(&ServerInfo))
|
||||
return;
|
||||
|
||||
// check for messages from server
|
||||
if(MsgType == NETMSGTYPE_SV_KILLMSG)
|
||||
{
|
||||
CNetMsg_Sv_KillMsg *pMsg = (CNetMsg_Sv_KillMsg *)pRawMsg;
|
||||
if(pMsg->m_Victim == m_pClient->m_Snap.m_LocalClientID && m_RaceState == RACE_FINISHED)
|
||||
{
|
||||
// check for new record
|
||||
CheckDemo();
|
||||
OnReset();
|
||||
}
|
||||
if(pMsg->m_Victim == m_pClient->m_Snap.m_LocalClientID)
|
||||
StopRecord(m_Time);
|
||||
}
|
||||
else if(MsgType == NETMSGTYPE_SV_CHAT)
|
||||
{
|
||||
|
@ -99,7 +82,7 @@ void CRaceDemo::OnMessage(int MsgType, void *pRawMsg)
|
|||
if(Time > 0 && str_comp(aName, m_pClient->m_aClients[m_pClient->m_Snap.m_LocalClientID].m_aName) == 0)
|
||||
{
|
||||
m_RaceState = RACE_FINISHED;
|
||||
m_RecordStopTime = Client()->GameTick() + Client()->GameTickSpeed();
|
||||
m_RecordStopTick = Client()->GameTick() + Client()->GameTickSpeed();
|
||||
m_Time = Time;
|
||||
}
|
||||
}
|
||||
|
@ -111,78 +94,87 @@ void CRaceDemo::OnMapLoad()
|
|||
m_IsSolo = true;
|
||||
}
|
||||
|
||||
void CRaceDemo::CheckDemo()
|
||||
void CRaceDemo::StopRecord(int Time)
|
||||
{
|
||||
// stop the demo recording
|
||||
Client()->RaceRecordStop();
|
||||
if(Client()->RaceRecord_IsRecording())
|
||||
Client()->RaceRecord_Stop();
|
||||
|
||||
char aDemoName[128];
|
||||
char aTmpFilename[512];
|
||||
Client()->RaceRecord_GetName(aDemoName, sizeof(aDemoName));
|
||||
str_format(aTmpFilename, sizeof(aTmpFilename), "demos/%s.demo", aDemoName);
|
||||
|
||||
if(Time > 0 && CheckDemo(Time))
|
||||
{
|
||||
// save file
|
||||
char aNewFilename[512];
|
||||
Client()->RaceRecord_GetName(aDemoName, sizeof(aDemoName), m_Time);
|
||||
str_format(aNewFilename, sizeof(aNewFilename), "demos/%s.demo", aDemoName);
|
||||
|
||||
Storage()->RenameFile(aTmpFilename, aNewFilename, IStorage::TYPE_SAVE);
|
||||
}
|
||||
else // no new record
|
||||
Storage()->RemoveFile(aTmpFilename, IStorage::TYPE_SAVE);
|
||||
|
||||
m_Time = 0;
|
||||
m_RaceState = RACE_NONE;
|
||||
m_RecordStartTick = -1;
|
||||
m_RecordStopTick = -1;
|
||||
}
|
||||
|
||||
bool CRaceDemo::CheckDemo(int Time) const
|
||||
{
|
||||
if(str_comp(m_pClient->m_pMenus->GetCurrentDemoFolder(), "demos") != 0)
|
||||
return true;
|
||||
|
||||
char aTmpDemoName[128];
|
||||
str_format(aTmpDemoName, sizeof(aTmpDemoName), "%s_tmp_%d", m_pMap, pid());
|
||||
Client()->RaceRecord_GetName(aTmpDemoName, sizeof(aTmpDemoName));
|
||||
|
||||
// loop through demo files
|
||||
m_pClient->m_pMenus->DemolistPopulate();
|
||||
for(int i = 0; i < m_pClient->m_pMenus->m_lDemos.size(); i++)
|
||||
{
|
||||
const char *pDemo = m_pClient->m_pMenus->m_lDemos[i].m_aName;
|
||||
if(str_comp(pDemo, aTmpDemoName) == 0)
|
||||
// skip temp file
|
||||
const char *pDemoName = m_pClient->m_pMenus->m_lDemos[i].m_aName;
|
||||
if(str_comp(pDemoName, aTmpDemoName) == 0)
|
||||
continue;
|
||||
|
||||
int MapLen = str_length(m_pMap);
|
||||
if(str_comp_num(pDemo, m_pMap, MapLen) == 0 && pDemo[MapLen] == '_')
|
||||
{
|
||||
// set cursor
|
||||
pDemo += MapLen + 1;
|
||||
int Time = CRaceHelper::TimeFromSecondsStr(pDemo);
|
||||
if(Time > 0 && m_Time < Time)
|
||||
{
|
||||
// save new record
|
||||
SaveDemo(m_pMap);
|
||||
int MapLen = str_length(Client()->GetCurrentMap());
|
||||
if(str_comp_num(pDemoName, Client()->GetCurrentMap(), MapLen) != 0 || pDemoName[MapLen] != '_')
|
||||
continue;
|
||||
|
||||
// delete old demo
|
||||
char aFilename[512];
|
||||
str_format(aFilename, sizeof(aFilename), "demos/%s.demo", m_pClient->m_pMenus->m_lDemos[i].m_aName);
|
||||
Storage()->RemoveFile(aFilename, IStorage::TYPE_SAVE);
|
||||
// set cursor
|
||||
pDemoName += MapLen + 1;
|
||||
|
||||
if(g_Config.m_ClDemoName)
|
||||
{
|
||||
char aPlayerName[MAX_NAME_LENGTH];
|
||||
str_copy(aPlayerName, g_Config.m_PlayerName, sizeof(aPlayerName));
|
||||
char *pStr = aPlayerName;
|
||||
|
||||
while(*pStr)
|
||||
{
|
||||
if(*pStr == '\\' || *pStr == '/' || *pStr == '|' || *pStr == ':' || *pStr == '*' || *pStr == '?' || *pStr == '<' || *pStr == '>' || *pStr == '"')
|
||||
*pStr = '%';
|
||||
pStr++;
|
||||
}
|
||||
|
||||
m_Time = 0;
|
||||
|
||||
return;
|
||||
if(!str_find(pDemoName, aPlayerName))
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// save demo if there is none
|
||||
SaveDemo(m_pMap);
|
||||
|
||||
m_Time = 0;
|
||||
}
|
||||
|
||||
void CRaceDemo::SaveDemo(const char* pDemo)
|
||||
{
|
||||
char aNewFilename[512];
|
||||
char aOldFilename[512];
|
||||
if(g_Config.m_ClDemoName)
|
||||
{
|
||||
char aPlayerName[MAX_NAME_LENGTH];
|
||||
str_copy(aPlayerName, m_pClient->m_aClients[m_pClient->m_Snap.m_LocalClientID].m_aName, sizeof(aPlayerName));
|
||||
|
||||
// check the player name
|
||||
for(int i = 0; i < MAX_NAME_LENGTH; i++)
|
||||
int DemoTime = CRaceHelper::TimeFromSecondsStr(pDemoName);
|
||||
if(DemoTime > 0)
|
||||
{
|
||||
if(!aPlayerName[i])
|
||||
break;
|
||||
if(Time >= DemoTime) // found a better demo
|
||||
return false;
|
||||
|
||||
if(aPlayerName[i] == '\\' || aPlayerName[i] == '/' || aPlayerName[i] == '|' || aPlayerName[i] == ':' || aPlayerName[i] == '*' || aPlayerName[i] == '?' || aPlayerName[i] == '<' || aPlayerName[i] == '>' || aPlayerName[i] == '"')
|
||||
aPlayerName[i] = '%';
|
||||
|
||||
str_format(aNewFilename, sizeof(aNewFilename), "demos/%s_%d.%03d_%s.demo", pDemo, m_Time / 1000, m_Time % 1000, aPlayerName);
|
||||
// delete old demo
|
||||
char aFilename[512];
|
||||
str_format(aFilename, sizeof(aFilename), "demos/%s", m_pClient->m_pMenus->m_lDemos[i].m_aFilename);
|
||||
Storage()->RemoveFile(aFilename, IStorage::TYPE_SAVE);
|
||||
}
|
||||
}
|
||||
else
|
||||
str_format(aNewFilename, sizeof(aNewFilename), "demos/%s_%d.%03d.demo", pDemo, m_Time / 1000, m_Time % 1000);
|
||||
|
||||
str_format(aOldFilename, sizeof(aOldFilename), "demos/%s_tmp_%d.demo", m_pMap, pid());
|
||||
|
||||
Storage()->RenameFile(aOldFilename, aNewFilename, IStorage::TYPE_SAVE);
|
||||
|
||||
dbg_msg("racedemo", "saved better demo");
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -3,23 +3,10 @@
|
|||
#ifndef GAME_CLIENT_COMPONENTS_RACE_DEMO_H
|
||||
#define GAME_CLIENT_COMPONENTS_RACE_DEMO_H
|
||||
|
||||
#include <game/client/gameclient.h>
|
||||
|
||||
#include <game/client/component.h>
|
||||
|
||||
class CRaceDemo : public CComponent
|
||||
{
|
||||
int m_RecordStopTime;
|
||||
int m_DemoStartTick;
|
||||
int m_Time;
|
||||
const char *m_pMap;
|
||||
|
||||
void Stop();
|
||||
|
||||
public:
|
||||
bool m_IsSolo;
|
||||
int m_RaceState;
|
||||
|
||||
enum
|
||||
{
|
||||
RACE_NONE = 0,
|
||||
|
@ -27,16 +14,23 @@ public:
|
|||
RACE_FINISHED,
|
||||
};
|
||||
|
||||
int m_RaceState;
|
||||
int m_RecordStartTick;
|
||||
int m_RecordStopTick;
|
||||
int m_Time;
|
||||
|
||||
void StopRecord(int Time = -1);
|
||||
bool CheckDemo(int Time) const;
|
||||
|
||||
public:
|
||||
bool m_IsSolo;
|
||||
|
||||
CRaceDemo();
|
||||
|
||||
virtual void OnReset();
|
||||
virtual void OnStateChange(int NewState, int OldState);
|
||||
virtual void OnRender();
|
||||
virtual void OnShutdown();
|
||||
virtual void OnMessage(int MsgType, void *pRawMsg);
|
||||
virtual void OnMapLoad();
|
||||
|
||||
void CheckDemo();
|
||||
void SaveDemo(const char* pDemo);
|
||||
};
|
||||
#endif
|
||||
|
|
|
@ -874,7 +874,7 @@ void CGameClient::OnStateChange(int NewState, int OldState)
|
|||
|
||||
void CGameClient::OnShutdown()
|
||||
{
|
||||
m_pRaceDemo->OnShutdown();
|
||||
m_pRaceDemo->OnReset();
|
||||
m_pGhost->OnReset();
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue