mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-10 18:18:18 +00:00
Optimization for faster server side demo recording
This commit is contained in:
parent
0947de4b3f
commit
9ea846033b
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue