Optimization for faster server side demo recording

This commit is contained in:
def 2014-12-02 15:44:54 +01:00
parent 0947de4b3f
commit 9ea846033b
4 changed files with 79 additions and 54 deletions

View file

@ -72,7 +72,7 @@ class IDemoRecorder : public IInterface
public: public:
~IDemoRecorder() {} ~IDemoRecorder() {}
virtual bool IsRecording() const = 0; virtual bool IsRecording() const = 0;
virtual int Stop() = 0; virtual int Stop(bool Finalize = false) = 0;
virtual int Length() const = 0; virtual int Length() const = 0;
}; };

View file

@ -294,8 +294,9 @@ void CServer::CClient::Reset()
CServer::CServer() CServer::CServer()
{ {
for(int i = 0; i < MAX_CLIENTS+1; i++) for(int i = 0; i < MAX_CLIENTS; i++)
m_aDemoRecorder[i] = CDemoRecorder(&m_SnapshotDelta); m_aDemoRecorder[i] = CDemoRecorder(&m_SnapshotDelta, true);
m_aDemoRecorder[MAX_CLIENTS] = CDemoRecorder(&m_SnapshotDelta, false);
m_TickSpeed = SERVER_TICK_SPEED; m_TickSpeed = SERVER_TICK_SPEED;
@ -1826,7 +1827,7 @@ void CServer::SaveDemo(int ClientID, float Time)
{ {
if(IsRecording(ClientID)) if(IsRecording(ClientID))
{ {
m_aDemoRecorder[ClientID].Stop(); m_aDemoRecorder[ClientID].Stop(true);
// rename the demo // rename the demo
char aOldFilename[256]; char aOldFilename[256];
@ -1843,7 +1844,7 @@ void CServer::StartRecord(int ClientID)
{ {
char aFilename[128]; char aFilename[128];
str_format(aFilename, sizeof(aFilename), "demos/%s_%d_%d_tmp.demo", m_aCurrentMap, g_Config.m_SvPort, ClientID); str_format(aFilename, sizeof(aFilename), "demos/%s_%d_%d_tmp.demo", m_aCurrentMap, g_Config.m_SvPort, ClientID);
m_aDemoRecorder[ClientID].Start(Storage(), Console(), aFilename, GameServer()->NetVersion(), m_aCurrentMap, m_CurrentMapCrc, "client"); m_aDemoRecorder[ClientID].Start(Storage(), Console(), aFilename, GameServer()->NetVersion(), m_aCurrentMap, m_CurrentMapCrc, "client", m_CurrentMapSize, m_pCurrentMapData);
} }
} }

View file

@ -21,16 +21,29 @@ static const int gs_LengthOffset = 152;
static const int gs_NumMarkersOffset = 176; static const int gs_NumMarkersOffset = 176;
CDemoRecorder::CDemoRecorder(class CSnapshotDelta *pSnapshotDelta) CDemoRecorder::CDemoRecorder(class CSnapshotDelta *pSnapshotDelta, bool DelayedMapData)
{ {
m_File = 0; m_File = 0;
m_LastTickMarker = -1; m_LastTickMarker = -1;
m_pSnapshotDelta = pSnapshotDelta; m_pSnapshotDelta = pSnapshotDelta;
m_DelayedMapData = DelayedMapData;
} }
// Record // Record
int CDemoRecorder::Start(class IStorage *pStorage, class IConsole *pConsole, const char *pFilename, const char *pNetVersion, const char *pMap, unsigned Crc, const char *pType) int CDemoRecorder::Start(class IStorage *pStorage, class IConsole *pConsole, const char *pFilename, const char *pNetVersion, const char *pMap, unsigned Crc, const char *pType, unsigned int MapSize, unsigned char *pMapData)
{ {
m_MapSize = MapSize;
m_pMapData = pMapData;
IOHANDLE DemoFile = pStorage->OpenFile(pFilename, IOFLAG_WRITE, IStorage::TYPE_SAVE);
if(!DemoFile)
{
char aBuf[256];
str_format(aBuf, sizeof(aBuf), "Unable to open '%s' for recording", pFilename);
m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "demo_recorder", aBuf);
return -1;
}
CDemoHeader Header; CDemoHeader Header;
CTimelineMarkers TimelineMarkers; CTimelineMarkers TimelineMarkers;
if(m_File) if(m_File)
@ -38,42 +51,36 @@ int CDemoRecorder::Start(class IStorage *pStorage, class IConsole *pConsole, con
m_pConsole = pConsole; m_pConsole = pConsole;
// open mapfile IOHANDLE MapFile = NULL;
char aMapFilename[128];
// try the normal maps folder
str_format(aMapFilename, sizeof(aMapFilename), "maps/%s.map", pMap);
IOHANDLE MapFile = pStorage->OpenFile(aMapFilename, IOFLAG_READ, IStorage::TYPE_ALL);
if(!MapFile)
{
// try the downloaded maps
str_format(aMapFilename, sizeof(aMapFilename), "downloadedmaps/%s_%08x.map", pMap, Crc);
MapFile = pStorage->OpenFile(aMapFilename, IOFLAG_READ, IStorage::TYPE_ALL);
}
if(!MapFile)
{
// search for the map within subfolders
char aBuf[512];
str_format(aMapFilename, sizeof(aMapFilename), "%s.map", pMap);
if(pStorage->FindFile(aMapFilename, "maps", IStorage::TYPE_ALL, aBuf, sizeof(aBuf)))
MapFile = pStorage->OpenFile(aBuf, IOFLAG_READ, IStorage::TYPE_ALL);
}
if(!MapFile)
{
char aBuf[256];
str_format(aBuf, sizeof(aBuf), "Unable to open mapfile '%s'", pMap);
m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "demo_recorder", aBuf);
return -1;
}
IOHANDLE DemoFile = pStorage->OpenFile(pFilename, IOFLAG_WRITE, IStorage::TYPE_SAVE); if(!m_DelayedMapData)
if(!DemoFile)
{ {
io_close(MapFile); // open mapfile
MapFile = 0; char aMapFilename[128];
char aBuf[256]; // try the normal maps folder
str_format(aBuf, sizeof(aBuf), "Unable to open '%s' for recording", pFilename); str_format(aMapFilename, sizeof(aMapFilename), "maps/%s.map", pMap);
m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "demo_recorder", aBuf); MapFile = pStorage->OpenFile(aMapFilename, IOFLAG_READ, IStorage::TYPE_ALL);
return -1; if(!MapFile)
{
// try the downloaded maps
str_format(aMapFilename, sizeof(aMapFilename), "downloadedmaps/%s_%08x.map", pMap, Crc);
MapFile = pStorage->OpenFile(aMapFilename, IOFLAG_READ, IStorage::TYPE_ALL);
}
if(!MapFile)
{
// search for the map within subfolders
char aBuf[512];
str_format(aMapFilename, sizeof(aMapFilename), "%s.map", pMap);
if(pStorage->FindFile(aMapFilename, "maps", IStorage::TYPE_ALL, aBuf, sizeof(aBuf)))
MapFile = pStorage->OpenFile(aBuf, IOFLAG_READ, IStorage::TYPE_ALL);
}
if(!MapFile)
{
char aBuf[256];
str_format(aBuf, sizeof(aBuf), "Unable to open mapfile '%s'", pMap);
m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "demo_recorder", aBuf);
return -1;
}
} }
// write header // write header
@ -82,7 +89,8 @@ int CDemoRecorder::Start(class IStorage *pStorage, class IConsole *pConsole, con
Header.m_Version = gs_ActVersion; Header.m_Version = gs_ActVersion;
str_copy(Header.m_aNetversion, pNetVersion, sizeof(Header.m_aNetversion)); str_copy(Header.m_aNetversion, pNetVersion, sizeof(Header.m_aNetversion));
str_copy(Header.m_aMapName, pMap, sizeof(Header.m_aMapName)); str_copy(Header.m_aMapName, pMap, sizeof(Header.m_aMapName));
unsigned MapSize = io_length(MapFile); if(!m_DelayedMapData)
MapSize = io_length(MapFile);
Header.m_aMapSize[0] = (MapSize>>24)&0xff; Header.m_aMapSize[0] = (MapSize>>24)&0xff;
Header.m_aMapSize[1] = (MapSize>>16)&0xff; Header.m_aMapSize[1] = (MapSize>>16)&0xff;
Header.m_aMapSize[2] = (MapSize>>8)&0xff; Header.m_aMapSize[2] = (MapSize>>8)&0xff;
@ -97,16 +105,23 @@ int CDemoRecorder::Start(class IStorage *pStorage, class IConsole *pConsole, con
io_write(DemoFile, &Header, sizeof(Header)); io_write(DemoFile, &Header, sizeof(Header));
io_write(DemoFile, &TimelineMarkers, sizeof(TimelineMarkers)); // fill this on stop io_write(DemoFile, &TimelineMarkers, sizeof(TimelineMarkers)); // fill this on stop
// write map data if(m_DelayedMapData)
while(1)
{ {
unsigned char aChunk[1024*64]; io_seek(DemoFile, MapSize, IOSEEK_CUR);
int Bytes = io_read(MapFile, &aChunk, sizeof(aChunk)); }
if(Bytes <= 0) else
break; {
io_write(DemoFile, &aChunk, Bytes); // write map data
while(1)
{
unsigned char aChunk[1024*64];
int Bytes = io_read(MapFile, &aChunk, sizeof(aChunk));
if(Bytes <= 0)
break;
io_write(DemoFile, &aChunk, Bytes);
}
io_close(MapFile);
} }
io_close(MapFile);
m_LastKeyFrame = -1; m_LastKeyFrame = -1;
m_LastTickMarker = -1; m_LastTickMarker = -1;
@ -261,7 +276,7 @@ void CDemoRecorder::RecordMessage(const void *pData, int Size)
Write(CHUNKTYPE_MESSAGE, pData, Size); Write(CHUNKTYPE_MESSAGE, pData, Size);
} }
int CDemoRecorder::Stop() int CDemoRecorder::Stop(bool Finalize)
{ {
if(!m_File) if(!m_File)
return -1; return -1;
@ -295,6 +310,12 @@ int CDemoRecorder::Stop()
io_write(m_File, aMarker, sizeof(aMarker)); io_write(m_File, aMarker, sizeof(aMarker));
} }
if(Finalize && m_DelayedMapData)
{
io_seek(m_File, gs_NumMarkersOffset + sizeof(CTimelineMarkers), IOSEEK_START);
io_write(m_File, m_pMapData, m_MapSize);
}
io_close(m_File); io_close(m_File);
m_File = 0; m_File = 0;
m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "demo_recorder", "Stopped recording"); m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "demo_recorder", "Stopped recording");

View file

@ -19,15 +19,18 @@ class CDemoRecorder : public IDemoRecorder
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_DelayedMapData;
unsigned int m_MapSize;
unsigned char *m_pMapData;
void WriteTickMarker(int Tick, int Keyframe); void WriteTickMarker(int Tick, int Keyframe);
void Write(int Type, const void *pData, int Size); void Write(int Type, const void *pData, int Size);
public: public:
CDemoRecorder(class CSnapshotDelta *pSnapshotDelta); CDemoRecorder(class CSnapshotDelta *pSnapshotDelta, bool DelayedMapData = false);
CDemoRecorder() {} CDemoRecorder() {}
int Start(class IStorage *pStorage, class IConsole *pConsole, const char *pFilename, const char *pNetversion, const char *pMap, unsigned MapCrc, const char *pType); int Start(class IStorage *pStorage, class IConsole *pConsole, const char *pFilename, const char *pNetversion, const char *pMap, unsigned MapCrc, const char *pType, unsigned int MapSize = 0, unsigned char *pMapData = NULL);
int Stop(); int Stop(bool Finalize = false);
void AddDemoMarker(); void AddDemoMarker();
void RecordSnapshot(int Tick, const void *pData, int Size); void RecordSnapshot(int Tick, const void *pData, int Size);