Skip to content

Improve map search for client and demo recorder/player #3131 #48

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: community
Choose a base branch
from
17 changes: 3 additions & 14 deletions src/engine/client/client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -912,9 +912,9 @@ const char *CClient::LoadMapSearch(const char *pMapName, const SHA256_DIGEST *pW
}

// search for the map within subfolders
char aFilename[128];
char aFilename[IO_MAX_PATH_LENGTH];
str_format(aFilename, sizeof(aFilename), "%s.map", pMapName);
if(Storage()->FindFile(aFilename, "maps", IStorage::TYPE_ALL, aBuf, sizeof(aBuf)))
if(Storage()->FindFile(aFilename, "maps", IStorage::TYPE_ALL, aBuf, sizeof(aBuf), pWantedSha256, WantedCrc))
pError = LoadMap(pMapName, aBuf, pWantedSha256, WantedCrc);

return pError;
Expand Down Expand Up @@ -2339,18 +2339,7 @@ void CClient::DemoRecorder_Start(const char *pFilename, bool WithTimestamp)
if(State() != IClient::STATE_ONLINE)
m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "demorec/record", "client is not online");
else
{
char aFilename[128];
if(WithTimestamp)
{
char aDate[20];
str_timestamp(aDate, sizeof(aDate));
str_format(aFilename, sizeof(aFilename), "demos/%s_%s.demo", pFilename, aDate);
}
else
str_format(aFilename, sizeof(aFilename), "demos/%s.demo", pFilename);
m_DemoRecorder.Start(aFilename, GameClient()->NetVersion(), m_aCurrentMap, m_CurrentMapSha256, m_CurrentMapCrc, "client");
}
m_DemoRecorder.Start(pFilename, WithTimestamp, GameClient()->NetVersion(), m_aCurrentMap, m_CurrentMapSha256, m_CurrentMapCrc, "client");
}

void CClient::DemoRecorder_HandleAutoStart()
Expand Down
2 changes: 2 additions & 0 deletions src/engine/server.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,9 @@ class IServer : public IInterface
virtual void Kick(int ClientID, const char *pReason) = 0;
virtual void ChangeMap(const char *pMap) = 0;

virtual void DemoRecorder_Start(const char *pFilename, bool WithTimestamp) = 0;
virtual void DemoRecorder_HandleAutoStart() = 0;
virtual void DemoRecorder_Stop(bool ErrorIfNotRecording = false) = 0;
virtual bool DemoRecorder_IsRecording() = 0;
};

Expand Down
38 changes: 19 additions & 19 deletions src/engine/server/server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1243,8 +1243,7 @@ int CServer::LoadMap(const char *pMapName)
return 0;

// stop recording when we change map
if(m_DemoRecorder.IsRecording())
m_DemoRecorder.Stop();
DemoRecorder_Stop();

// reinit snapshot ids
m_IDPool.TimeoutIDs();
Expand Down Expand Up @@ -1605,17 +1604,17 @@ void CServer::ConShutdown(IConsole::IResult *pResult, void *pUser)
}
}

void CServer::DemoRecorder_Start(const char *pFilename, bool WithTimestamp)
{
m_DemoRecorder.Start(pFilename, WithTimestamp, GameServer()->NetVersion(), m_aCurrentMap, m_CurrentMapSha256, m_CurrentMapCrc, "server");
}

void CServer::DemoRecorder_HandleAutoStart()
{
if(Config()->m_SvAutoDemoRecord)
{
if(m_DemoRecorder.IsRecording())
m_DemoRecorder.Stop();
char aFilename[128];
char aDate[20];
str_timestamp(aDate, sizeof(aDate));
str_format(aFilename, sizeof(aFilename), "demos/%s_%s.demo", "auto/autorecord", aDate);
m_DemoRecorder.Start(aFilename, GameServer()->NetVersion(), m_aCurrentMap, m_CurrentMapSha256, m_CurrentMapCrc, "server");
DemoRecorder_Stop();
DemoRecorder_Start("auto/autorecord", true);
if(Config()->m_SvAutoDemoMax)
{
// clean up auto recorded demos
Expand All @@ -1625,29 +1624,30 @@ void CServer::DemoRecorder_HandleAutoStart()
}
}

void CServer::DemoRecorder_Stop(bool ErrorIfNotRecording)
{
if(ErrorIfNotRecording || m_DemoRecorder.IsRecording())
m_DemoRecorder.Stop();
}

bool CServer::DemoRecorder_IsRecording()
{
return m_DemoRecorder.IsRecording();
}

void CServer::ConRecord(IConsole::IResult *pResult, void *pUser)
{
CServer* pServer = (CServer *)pUser;
char aFilename[128];
CServer *pServer = (CServer *)pUser;

if(pResult->NumArguments())
str_format(aFilename, sizeof(aFilename), "demos/%s.demo", pResult->GetString(0));
pServer->DemoRecorder_Start(pResult->GetString(0), false);
else
{
char aDate[20];
str_timestamp(aDate, sizeof(aDate));
str_format(aFilename, sizeof(aFilename), "demos/demo_%s.demo", aDate);
}
pServer->m_DemoRecorder.Start(aFilename, pServer->GameServer()->NetVersion(), pServer->m_aCurrentMap, pServer->m_CurrentMapSha256, pServer->m_CurrentMapCrc, "server");
pServer->DemoRecorder_Start("demo", true);
}

void CServer::ConStopRecord(IConsole::IResult *pResult, void *pUser)
{
((CServer *)pUser)->m_DemoRecorder.Stop();
((CServer *)pUser)->DemoRecorder_Stop(true);
}

void CServer::ConMapReload(IConsole::IResult *pResult, void *pUser)
Expand Down
2 changes: 2 additions & 0 deletions src/engine/server/server.h
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,9 @@ class CServer : public IServer

void Kick(int ClientID, const char *pReason);

void DemoRecorder_Start(const char *pFilename, bool WithTimestamp);
void DemoRecorder_HandleAutoStart();
void DemoRecorder_Stop(bool ErrorIfNotRecording = false);
bool DemoRecorder_IsRecording();

int64 TickStartTime(int Tick);
Expand Down
25 changes: 21 additions & 4 deletions src/engine/shared/datafile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -481,12 +481,11 @@ unsigned CDataFileReader::Crc() const

bool CDataFileReader::CheckSha256(IOHANDLE Handle, const void *pSha256)
{
// read the hash of the file
SHA256_CTX Sha256Ctx;
sha256_init(&Sha256Ctx);
unsigned char aBuffer[64*1024];
while(1)

while(true)
{
unsigned Bytes = io_read(Handle, aBuffer, sizeof(aBuffer));
if(Bytes == 0)
Expand All @@ -497,7 +496,25 @@ bool CDataFileReader::CheckSha256(IOHANDLE Handle, const void *pSha256)
io_seek(Handle, 0, IOSEEK_START);
SHA256_DIGEST Sha256 = sha256_finish(&Sha256Ctx);

return !sha256_comp(*(const SHA256_DIGEST *)pSha256, Sha256);
return *(const SHA256_DIGEST *)pSha256 == Sha256;
}

bool CDataFileReader::CheckCrc(IOHANDLE Handle, const void *pCrc)
{
unsigned Crc = crc32(0L, 0x0, 0);
unsigned char aBuffer[64*1024];

while(true)
{
unsigned Bytes = io_read(Handle, aBuffer, sizeof(aBuffer));
if(Bytes == 0)
break;
Crc = crc32(Crc, aBuffer, Bytes);
}

io_seek(Handle, 0, IOSEEK_START);

return *(const unsigned *)pCrc == Crc;
}


Expand Down
1 change: 1 addition & 0 deletions src/engine/shared/datafile.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class CDataFileReader
unsigned Crc() const;

static bool CheckSha256(IOHANDLE Handle, const void *pSha256);
static bool CheckCrc(IOHANDLE Handle, const void *pCrc);
};

// write access
Expand Down
54 changes: 40 additions & 14 deletions src/engine/shared/demo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ void CDemoRecorder::Init(class IConsole *pConsole, class IStorage *pStorage)
}

// Record
int CDemoRecorder::Start(const char *pFilename, const char *pNetVersion, const char *pMap, SHA256_DIGEST Sha256, unsigned Crc, const char *pType)
int CDemoRecorder::Start(const char *pFilename, bool WithTimestamp, const char *pNetVersion, const char *pMap, SHA256_DIGEST Sha256, unsigned Crc, const char *pType)
{
CDemoHeader Header;
if(m_File)
Expand All @@ -43,7 +43,7 @@ int CDemoRecorder::Start(const char *pFilename, const char *pNetVersion, const c
}

// open mapfile
char aMapFilename[128];
char aMapFilename[IO_MAX_PATH_LENGTH];
// try the normal maps folder
str_format(aMapFilename, sizeof(aMapFilename), "maps/%s.map", pMap);
IOHANDLE MapFile = m_pStorage->OpenFile(aMapFilename, IOFLAG_READ, IStorage::TYPE_ALL, 0, 0, CDataFileReader::CheckSha256, &Sha256);
Expand All @@ -66,8 +66,8 @@ int CDemoRecorder::Start(const char *pFilename, const char *pNetVersion, const c
// search for the map within subfolders
char aBuf[IO_MAX_PATH_LENGTH];
str_format(aMapFilename, sizeof(aMapFilename), "%s.map", pMap);
if(m_pStorage->FindFile(aMapFilename, "maps", IStorage::TYPE_ALL, aBuf, sizeof(aBuf)))
MapFile = m_pStorage->OpenFile(aBuf, IOFLAG_READ, IStorage::TYPE_ALL, 0, 0, CDataFileReader::CheckSha256, &Sha256);
if(m_pStorage->FindFile(aMapFilename, "maps", IStorage::TYPE_ALL, aBuf, sizeof(aBuf), &Sha256, Crc))
MapFile = m_pStorage->OpenFile(aBuf, IOFLAG_READ, IStorage::TYPE_ALL);
}
if(!MapFile)
{
Expand All @@ -77,13 +77,23 @@ int CDemoRecorder::Start(const char *pFilename, const char *pNetVersion, const c
return -1;
}

IOHANDLE DemoFile = m_pStorage->OpenFile(pFilename, IOFLAG_WRITE, IStorage::TYPE_SAVE);
char aDemoFilename[IO_MAX_PATH_LENGTH];
if(WithTimestamp)
{
char aDate[20];
str_timestamp(aDate, sizeof(aDate));
str_format(aDemoFilename, sizeof(aDemoFilename), "demos/%s_%s.demo", pFilename, aDate);
}
else
str_format(aDemoFilename, sizeof(aDemoFilename), "demos/%s.demo", pFilename);

IOHANDLE DemoFile = m_pStorage->OpenFile(aDemoFilename, IOFLAG_WRITE, IStorage::TYPE_SAVE);
if(!DemoFile)
{
io_close(MapFile);
MapFile = 0;
char aBuf[256];
str_format(aBuf, sizeof(aBuf), "Unable to open '%s' for recording", pFilename);
str_format(aBuf, sizeof(aBuf), "Unable to open '%s' for recording", aDemoFilename);
m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "demo_recorder", aBuf);
return -1;
}
Expand Down Expand Up @@ -121,7 +131,7 @@ int CDemoRecorder::Start(const char *pFilename, const char *pNetVersion, const c
m_NumTimelineMarkers = 0;

char aBuf[256];
str_format(aBuf, sizeof(aBuf), "Recording to '%s'", pFilename);
str_format(aBuf, sizeof(aBuf), "Recording to '%s'", aDemoFilename);
m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "demo_recorder", aBuf);
m_File = DemoFile;

Expand Down Expand Up @@ -675,14 +685,30 @@ const char *CDemoPlayer::Load(const char *pFilename, int StorageType, const char
m_DemoType = DEMOTYPE_INVALID;

// read map
unsigned MapSize = bytes_be_to_uint(m_Info.m_Header.m_aMapSize);
const unsigned MapSize = bytes_be_to_uint(m_Info.m_Header.m_aMapSize);
const unsigned Crc = bytes_be_to_uint(m_Info.m_Header.m_aMapCrc);

// check if we already have the map
// TODO: improve map checking (maps folder, check crc)
unsigned Crc = bytes_be_to_uint(m_Info.m_Header.m_aMapCrc);
char aMapFilename[128];
str_format(aMapFilename, sizeof(aMapFilename), "downloadedmaps/%s_%08x.map", m_Info.m_Header.m_aMapName, Crc);
IOHANDLE MapFile = m_pStorage->OpenFile(aMapFilename, IOFLAG_READ, IStorage::TYPE_ALL);
// TODO: add map sha256 to demo file and check for correct sha256 if available instead of crc
char aMapFilename[IO_MAX_PATH_LENGTH];
char aMapFilenameOutput[IO_MAX_PATH_LENGTH];
// try the normal maps folder
str_format(aMapFilename, sizeof(aMapFilename), "maps/%s.map", m_Info.m_Header.m_aMapName);
IOHANDLE MapFile = m_pStorage->OpenFile(aMapFilename, IOFLAG_READ, IStorage::TYPE_ALL, 0, 0, CDataFileReader::CheckCrc, &Crc);
if(!MapFile)
{
// try the downloaded maps (crc)
str_format(aMapFilenameOutput, sizeof(aMapFilenameOutput), "downloadedmaps/%s_%08x.map", m_Info.m_Header.m_aMapName, Crc);
MapFile = m_pStorage->OpenFile(aMapFilenameOutput, IOFLAG_READ, IStorage::TYPE_ALL);
}
if(!MapFile)
{
// search for the map within subfolders
char aBuf[IO_MAX_PATH_LENGTH];
str_format(aMapFilename, sizeof(aMapFilename), "%s.map", m_Info.m_Header.m_aMapName);
if(m_pStorage->FindFile(aMapFilename, "maps", IStorage::TYPE_ALL, aBuf, sizeof(aBuf), 0, Crc))
MapFile = m_pStorage->OpenFile(aBuf, IOFLAG_READ, IStorage::TYPE_ALL);
}

if(MapFile)
{
Expand All @@ -696,7 +722,7 @@ const char *CDemoPlayer::Load(const char *pFilename, int StorageType, const char
io_read(m_File, pMapData, MapSize);

// save map
MapFile = m_pStorage->OpenFile(aMapFilename, IOFLAG_WRITE, IStorage::TYPE_SAVE);
MapFile = m_pStorage->OpenFile(aMapFilenameOutput, IOFLAG_WRITE, IStorage::TYPE_SAVE);
io_write(MapFile, pMapData, MapSize);
io_close(MapFile);

Expand Down
2 changes: 1 addition & 1 deletion src/engine/shared/demo.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class CDemoRecorder : public IDemoRecorder
CDemoRecorder(class CSnapshotDelta *pSnapshotDelta);
void Init(class IConsole *pConsole, class IStorage *pStorage);

int Start(const char *pFilename, const char *pNetversion, const char *pMap, SHA256_DIGEST MapSha256, unsigned MapCrc, const char *pType);
int Start(const char *pFilename, bool WithTimestamp, const char *pNetversion, const char *pMap, SHA256_DIGEST MapSha256, unsigned MapCrc, const char *pType);
int Stop();
void AddDemoMarker();

Expand Down
31 changes: 26 additions & 5 deletions src/engine/shared/storage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,8 @@ class CStorage : public IStorage
const SHA256_DIGEST *m_pWantedSha256;
unsigned m_WantedCrc;
unsigned m_WantedSize;
bool m_CheckHashAndSize;
bool m_CheckHash;
bool m_CheckSize;
};

static int FindFileCallback(const char *pName, int IsDir, int Type, void *pUser)
Expand All @@ -452,13 +453,15 @@ class CStorage : public IStorage
// found the file
str_format(Data.m_pBuffer, Data.m_BufferSize, "%s/%s", Data.m_pPath, Data.m_pFilename);

if(Data.m_CheckHashAndSize)
if(Data.m_CheckHash || Data.m_CheckSize)
{
// check crc and size
SHA256_DIGEST Sha256;
unsigned Crc = 0;
unsigned Size = 0;
if(!Data.m_pStorage->GetHashAndSize(Data.m_pBuffer, Type, &Sha256, &Crc, &Size) || (Data.m_pWantedSha256 && Sha256 != *Data.m_pWantedSha256) || Crc != Data.m_WantedCrc || Size != Data.m_WantedSize)
if(!Data.m_pStorage->GetHashAndSize(Data.m_pBuffer, Type, &Sha256, &Crc, &Size)
|| (Data.m_CheckHash && ((Data.m_pWantedSha256 && Sha256 != *Data.m_pWantedSha256) || Crc != Data.m_WantedCrc))
|| (Data.m_CheckSize && Size != Data.m_WantedSize))
{
Data.m_pBuffer[0] = 0;
return 0;
Expand Down Expand Up @@ -510,7 +513,24 @@ class CStorage : public IStorage
Data.m_pWantedSha256 = 0;
Data.m_WantedCrc = 0;
Data.m_WantedSize = 0;
Data.m_CheckHashAndSize = false;
Data.m_CheckHash = false;
Data.m_CheckSize = false;
return FindFileImpl(Type, &Data);
}

virtual bool FindFile(const char *pFilename, const char *pPath, int Type, char *pBuffer, int BufferSize, const SHA256_DIGEST *pWantedSha256, unsigned WantedCrc)
{
CFindCBData Data;
Data.m_pStorage = this;
Data.m_pFilename = pFilename;
Data.m_pPath = pPath;
Data.m_pBuffer = pBuffer;
Data.m_BufferSize = BufferSize;
Data.m_pWantedSha256 = pWantedSha256;
Data.m_WantedCrc = WantedCrc;
Data.m_WantedSize = 0;
Data.m_CheckHash = true;
Data.m_CheckSize = false;
return FindFileImpl(Type, &Data);
}

Expand All @@ -525,7 +545,8 @@ class CStorage : public IStorage
Data.m_pWantedSha256 = pWantedSha256;
Data.m_WantedCrc = WantedCrc;
Data.m_WantedSize = WantedSize;
Data.m_CheckHashAndSize = true;
Data.m_CheckHash = true;
Data.m_CheckSize = true;
return FindFileImpl(Type, &Data);
}

Expand Down
1 change: 1 addition & 0 deletions src/engine/storage.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class IStorage : public IInterface
virtual bool ReadFile(const char *pFilename, int Type, void **ppResult, unsigned *pResultLen) = 0;
virtual char *ReadFileStr(const char *pFilename, int Type) = 0;
virtual bool FindFile(const char *pFilename, const char *pPath, int Type, char *pBuffer, int BufferSize) = 0;
virtual bool FindFile(const char *pFilename, const char *pPath, int Type, char *pBuffer, int BufferSize, const SHA256_DIGEST *pWantedSha256, unsigned WantedCrc) = 0;
virtual bool FindFile(const char *pFilename, const char *pPath, int Type, char *pBuffer, int BufferSize, const SHA256_DIGEST *pWantedSha256, unsigned WantedCrc, unsigned WantedSize) = 0;
virtual bool RemoveFile(const char *pFilename, int Type) = 0;
virtual bool RenameFile(const char* pOldFilename, const char* pNewFilename, int Type) = 0;
Expand Down
12 changes: 12 additions & 0 deletions src/test/storage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ TEST(Storage, FindFile)
EXPECT_TRUE(pStorage->FindFile(Info.m_aFilename, ".", IStorage::TYPE_ALL, aFound, sizeof(aFound), &Sha256, 0x3bb935c6, 5));
EXPECT_STREQ(aFound, aFilenameWithDot);

EXPECT_TRUE(pStorage->FindFile(Info.m_aFilename, ".", IStorage::TYPE_ALL, aFound, sizeof(aFound), 0, 0x3bb935c6));
EXPECT_STREQ(aFound, aFilenameWithDot);

EXPECT_TRUE(pStorage->FindFile(Info.m_aFilename, ".", IStorage::TYPE_ALL, aFound, sizeof(aFound), &Sha256, 0x3bb935c6));
EXPECT_STREQ(aFound, aFilenameWithDot);

EXPECT_FALSE(pStorage->FindFile(Info.m_aFilename, ".", IStorage::TYPE_ALL, aFound, sizeof(aFound), 0, 0, 0));
EXPECT_FALSE(pStorage->FindFile(Info.m_aFilename, ".", IStorage::TYPE_ALL, aFound, sizeof(aFound), 0, 0x3bb935c6, 0));
EXPECT_FALSE(pStorage->FindFile(Info.m_aFilename, ".", IStorage::TYPE_ALL, aFound, sizeof(aFound), 0, 0, 5));
Expand All @@ -41,5 +47,11 @@ TEST(Storage, FindFile)
EXPECT_FALSE(pStorage->FindFile(Info.m_aFilename, ".", IStorage::TYPE_ALL, aFound, sizeof(aFound), &WrongSha256, 0x3bb935c6, 5));
EXPECT_FALSE(pStorage->FindFile(Info.m_aFilename, ".", IStorage::TYPE_ALL, aFound, sizeof(aFound), &SHA256_ZEROED, 0x3bb935c6, 5));

EXPECT_FALSE(pStorage->FindFile(Info.m_aFilename, ".", IStorage::TYPE_ALL, aFound, sizeof(aFound), 0, 0));
EXPECT_FALSE(pStorage->FindFile(Info.m_aFilename, ".", IStorage::TYPE_ALL, aFound, sizeof(aFound), 0, 0x3bb935c5));

EXPECT_FALSE(pStorage->FindFile(Info.m_aFilename, ".", IStorage::TYPE_ALL, aFound, sizeof(aFound), &WrongSha256, 0x3bb935c6));
EXPECT_FALSE(pStorage->FindFile(Info.m_aFilename, ".", IStorage::TYPE_ALL, aFound, sizeof(aFound), &SHA256_ZEROED, 0x3bb935c6));

EXPECT_TRUE(pStorage->RemoveFile(Info.m_aFilename, IStorage::TYPE_SAVE));
}