From 9ea846033be97b25b68c7e8769b9ee86993f6896 Mon Sep 17 00:00:00 2001 From: def Date: Tue, 2 Dec 2014 15:44:54 +0100 Subject: [PATCH] Optimization for faster server side demo recording --- src/engine/demo.h | 2 +- src/engine/server/server.cpp | 9 +-- src/engine/shared/demo.cpp | 113 +++++++++++++++++++++-------------- src/engine/shared/demo.h | 9 ++- 4 files changed, 79 insertions(+), 54 deletions(-) diff --git a/src/engine/demo.h b/src/engine/demo.h index 322340e09..395726874 100644 --- a/src/engine/demo.h +++ b/src/engine/demo.h @@ -72,7 +72,7 @@ class IDemoRecorder : public IInterface public: ~IDemoRecorder() {} virtual bool IsRecording() const = 0; - virtual int Stop() = 0; + virtual int Stop(bool Finalize = false) = 0; virtual int Length() const = 0; }; diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp index 844809f1a..1468dd476 100644 --- a/src/engine/server/server.cpp +++ b/src/engine/server/server.cpp @@ -294,8 +294,9 @@ void CServer::CClient::Reset() CServer::CServer() { - for(int i = 0; i < MAX_CLIENTS+1; i++) - m_aDemoRecorder[i] = CDemoRecorder(&m_SnapshotDelta); + for(int i = 0; i < MAX_CLIENTS; i++) + m_aDemoRecorder[i] = CDemoRecorder(&m_SnapshotDelta, true); + m_aDemoRecorder[MAX_CLIENTS] = CDemoRecorder(&m_SnapshotDelta, false); m_TickSpeed = SERVER_TICK_SPEED; @@ -1826,7 +1827,7 @@ void CServer::SaveDemo(int ClientID, float Time) { if(IsRecording(ClientID)) { - m_aDemoRecorder[ClientID].Stop(); + m_aDemoRecorder[ClientID].Stop(true); // rename the demo char aOldFilename[256]; @@ -1843,7 +1844,7 @@ void CServer::StartRecord(int ClientID) { char aFilename[128]; 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); } } diff --git a/src/engine/shared/demo.cpp b/src/engine/shared/demo.cpp index 489ee15ae..2860d76b4 100644 --- a/src/engine/shared/demo.cpp +++ b/src/engine/shared/demo.cpp @@ -21,16 +21,29 @@ static const int gs_LengthOffset = 152; static const int gs_NumMarkersOffset = 176; -CDemoRecorder::CDemoRecorder(class CSnapshotDelta *pSnapshotDelta) +CDemoRecorder::CDemoRecorder(class CSnapshotDelta *pSnapshotDelta, bool DelayedMapData) { m_File = 0; m_LastTickMarker = -1; m_pSnapshotDelta = pSnapshotDelta; + m_DelayedMapData = DelayedMapData; } // 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; CTimelineMarkers TimelineMarkers; if(m_File) @@ -38,42 +51,36 @@ int CDemoRecorder::Start(class IStorage *pStorage, class IConsole *pConsole, con m_pConsole = pConsole; - // open mapfile - 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 MapFile = NULL; - IOHANDLE DemoFile = pStorage->OpenFile(pFilename, IOFLAG_WRITE, IStorage::TYPE_SAVE); - if(!DemoFile) + if(!m_DelayedMapData) { - io_close(MapFile); - MapFile = 0; - 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; + // open mapfile + char aMapFilename[128]; + // try the normal maps folder + str_format(aMapFilename, sizeof(aMapFilename), "maps/%s.map", pMap); + 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; + } } // write header @@ -82,7 +89,8 @@ int CDemoRecorder::Start(class IStorage *pStorage, class IConsole *pConsole, con Header.m_Version = gs_ActVersion; str_copy(Header.m_aNetversion, pNetVersion, sizeof(Header.m_aNetversion)); 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[1] = (MapSize>>16)&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, &TimelineMarkers, sizeof(TimelineMarkers)); // fill this on stop - // write map data - while(1) + if(m_DelayedMapData) { - unsigned char aChunk[1024*64]; - int Bytes = io_read(MapFile, &aChunk, sizeof(aChunk)); - if(Bytes <= 0) - break; - io_write(DemoFile, &aChunk, Bytes); + io_seek(DemoFile, MapSize, IOSEEK_CUR); + } + else + { + // 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_LastTickMarker = -1; @@ -261,7 +276,7 @@ void CDemoRecorder::RecordMessage(const void *pData, int Size) Write(CHUNKTYPE_MESSAGE, pData, Size); } -int CDemoRecorder::Stop() +int CDemoRecorder::Stop(bool Finalize) { if(!m_File) return -1; @@ -295,6 +310,12 @@ int CDemoRecorder::Stop() 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); m_File = 0; m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "demo_recorder", "Stopped recording"); diff --git a/src/engine/shared/demo.h b/src/engine/shared/demo.h index 96e1e5804..152c03fce 100644 --- a/src/engine/shared/demo.h +++ b/src/engine/shared/demo.h @@ -19,15 +19,18 @@ class CDemoRecorder : public IDemoRecorder class CSnapshotDelta *m_pSnapshotDelta; int m_NumTimelineMarkers; int m_aTimelineMarkers[MAX_TIMELINE_MARKERS]; + bool m_DelayedMapData; + unsigned int m_MapSize; + unsigned char *m_pMapData; void WriteTickMarker(int Tick, int Keyframe); void Write(int Type, const void *pData, int Size); public: - CDemoRecorder(class CSnapshotDelta *pSnapshotDelta); + CDemoRecorder(class CSnapshotDelta *pSnapshotDelta, bool DelayedMapData = false); CDemoRecorder() {} - int Start(class IStorage *pStorage, class IConsole *pConsole, const char *pFilename, const char *pNetversion, const char *pMap, unsigned MapCrc, const char *pType); - int Stop(); + 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(bool Finalize = false); void AddDemoMarker(); void RecordSnapshot(int Tick, const void *pData, int Size);