mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-10 10:08:18 +00:00
Merge #3054
3054: Remove CRC in all possible places r=def- a=heinrich5991 Some places remain due to net/file format compatibility. Co-authored-by: heinrich5991 <heinrich5991@gmail.com>
This commit is contained in:
commit
3fdfe7ea2d
|
@ -1485,8 +1485,6 @@ set_src(ENGINE_SHARED GLOB src/engine/shared
|
|||
fifo.h
|
||||
filecollection.cpp
|
||||
filecollection.h
|
||||
ghost.cpp
|
||||
ghost.h
|
||||
global_uuid_manager.cpp
|
||||
huffman.cpp
|
||||
huffman.h
|
||||
|
@ -1638,6 +1636,8 @@ if(CLIENT)
|
|||
demoedit.h
|
||||
friends.cpp
|
||||
friends.h
|
||||
ghost.cpp
|
||||
ghost.h
|
||||
graphics_threaded.cpp
|
||||
graphics_threaded.h
|
||||
http.cpp
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "graphics.h"
|
||||
#include "message.h"
|
||||
#include <base/hash.h>
|
||||
#include <engine/friends.h>
|
||||
|
||||
struct SWarning;
|
||||
|
@ -193,7 +194,8 @@ public:
|
|||
|
||||
virtual const char *GetCurrentMap() = 0;
|
||||
virtual const char *GetCurrentMapPath() = 0;
|
||||
virtual unsigned GetMapCrc() = 0;
|
||||
virtual SHA256_DIGEST GetCurrentMapSha256() = 0;
|
||||
virtual unsigned GetCurrentMapCrc() = 0;
|
||||
|
||||
virtual int GetCurrentRaceTime() = 0;
|
||||
|
||||
|
|
|
@ -41,7 +41,6 @@
|
|||
#include <engine/shared/demo.h>
|
||||
#include <engine/shared/fifo.h>
|
||||
#include <engine/shared/filecollection.h>
|
||||
#include <engine/shared/ghost.h>
|
||||
#include <engine/shared/json.h>
|
||||
#include <engine/shared/network.h>
|
||||
#include <engine/shared/packer.h>
|
||||
|
@ -1165,8 +1164,8 @@ const char *CClient::LoadMap(const char *pName, const char *pFilename, SHA256_DI
|
|||
return s_aErrorMsg;
|
||||
}
|
||||
|
||||
// get the crc of the map
|
||||
if(m_pMap->Crc() != WantedCrc)
|
||||
// Only check CRC if we don't have the secure SHA256.
|
||||
if(!pWantedSha256 && m_pMap->Crc() != WantedCrc)
|
||||
{
|
||||
str_format(s_aErrorMsg, sizeof(s_aErrorMsg), "map differs from the server. %08x != %08x", m_pMap->Crc(), WantedCrc);
|
||||
m_pConsole->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "client", s_aErrorMsg);
|
||||
|
@ -1196,15 +1195,17 @@ const char *CClient::LoadMapSearch(const char *pMapName, SHA256_DIGEST *pWantedS
|
|||
char aWanted[256];
|
||||
char aWantedSha256[SHA256_MAXSTRSIZE];
|
||||
|
||||
aWanted[0] = 0;
|
||||
|
||||
if(pWantedSha256)
|
||||
{
|
||||
sha256_str(*pWantedSha256, aWantedSha256, sizeof(aWantedSha256));
|
||||
str_format(aWanted, sizeof(aWanted), " sha256=%s", aWantedSha256);
|
||||
str_format(aWanted, sizeof(aWanted), "sha256=%s", aWantedSha256);
|
||||
}
|
||||
else
|
||||
{
|
||||
str_format(aWanted, sizeof(aWanted), "crc=%08x", WantedCrc);
|
||||
}
|
||||
|
||||
str_format(aBuf, sizeof(aBuf), "loading map, map=%s wanted%s crc=%08x", pMapName, aWanted, WantedCrc);
|
||||
str_format(aBuf, sizeof(aBuf), "loading map, map=%s wanted %s", pMapName, aWanted);
|
||||
m_pConsole->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "client", aBuf);
|
||||
SetState(IClient::STATE_LOADING);
|
||||
|
||||
|
@ -1217,14 +1218,15 @@ const char *CClient::LoadMapSearch(const char *pMapName, SHA256_DIGEST *pWantedS
|
|||
// try the downloaded maps
|
||||
if(pWantedSha256)
|
||||
{
|
||||
str_format(aBuf, sizeof(aBuf), "downloadedmaps/%s_%08x_%s.map", pMapName, WantedCrc, aWantedSha256);
|
||||
str_format(aBuf, sizeof(aBuf), "downloadedmaps/%s_%s.map", pMapName, aWantedSha256);
|
||||
}
|
||||
else
|
||||
{
|
||||
str_format(aBuf, sizeof(aBuf), "downloadedmaps/%s_%08x.map", pMapName, WantedCrc);
|
||||
pError = LoadMap(pMapName, aBuf, pWantedSha256, WantedCrc);
|
||||
if(!pError)
|
||||
return pError;
|
||||
}
|
||||
|
||||
// try the downloaded maps folder without appending the sha256
|
||||
str_format(aBuf, sizeof(aBuf), "downloadedmaps/%s_%08x.map", pMapName, WantedCrc);
|
||||
pError = LoadMap(pMapName, aBuf, pWantedSha256, WantedCrc);
|
||||
if(!pError)
|
||||
return pError;
|
||||
|
@ -1566,28 +1568,23 @@ bool CClient::ShouldSendChatTimeoutCodeHeuristic()
|
|||
|
||||
static void FormatMapDownloadFilename(const char *pName, SHA256_DIGEST *pSha256, int Crc, bool Temp, char *pBuffer, int BufferSize)
|
||||
{
|
||||
char aSha256[SHA256_MAXSTRSIZE + 1];
|
||||
aSha256[0] = 0;
|
||||
char aHash[SHA256_MAXSTRSIZE];
|
||||
if(pSha256)
|
||||
{
|
||||
aSha256[0] = '_';
|
||||
sha256_str(*pSha256, aSha256 + 1, sizeof(aSha256) - 1);
|
||||
sha256_str(*pSha256, aHash, sizeof(aHash));
|
||||
}
|
||||
else
|
||||
{
|
||||
str_format(aHash, sizeof(aHash), "%08x", Crc);
|
||||
}
|
||||
|
||||
if(Temp)
|
||||
{
|
||||
str_format(pBuffer, BufferSize, "%s_%08x%s.map.%d.tmp",
|
||||
pName,
|
||||
Crc,
|
||||
aSha256,
|
||||
pid());
|
||||
str_format(pBuffer, BufferSize, "%s_%s.map.%d.tmp", pName, aHash, pid());
|
||||
}
|
||||
else
|
||||
{
|
||||
str_format(pBuffer, BufferSize, "%s_%08x%s.map",
|
||||
pName,
|
||||
Crc,
|
||||
aSha256);
|
||||
str_format(pBuffer, BufferSize, "%s_%s.map", pName, aHash);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4373,7 +4370,12 @@ const char *CClient::GetCurrentMapPath()
|
|||
return m_aCurrentMapPath;
|
||||
}
|
||||
|
||||
unsigned CClient::GetMapCrc()
|
||||
SHA256_DIGEST CClient::GetCurrentMapSha256()
|
||||
{
|
||||
return m_pMap->Sha256();
|
||||
}
|
||||
|
||||
unsigned CClient::GetCurrentMapCrc()
|
||||
{
|
||||
return m_pMap->Crc();
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <engine/client.h>
|
||||
#include <engine/client/demoedit.h>
|
||||
#include <engine/client/friends.h>
|
||||
#include <engine/client/ghost.h>
|
||||
#include <engine/client/http.h>
|
||||
#include <engine/client/serverbrowser.h>
|
||||
#include <engine/client/updater.h>
|
||||
|
@ -22,7 +23,6 @@
|
|||
#include <engine/shared/config.h>
|
||||
#include <engine/shared/demo.h>
|
||||
#include <engine/shared/fifo.h>
|
||||
#include <engine/shared/ghost.h>
|
||||
#include <engine/shared/network.h>
|
||||
#include <engine/sound.h>
|
||||
#include <engine/steam.h>
|
||||
|
@ -471,7 +471,8 @@ public:
|
|||
|
||||
virtual const char *GetCurrentMap();
|
||||
virtual const char *GetCurrentMapPath();
|
||||
virtual unsigned GetMapCrc();
|
||||
virtual SHA256_DIGEST GetCurrentMapSha256();
|
||||
virtual unsigned GetCurrentMapCrc();
|
||||
|
||||
virtual void RaceRecord_Start(const char *pFilename);
|
||||
virtual void RaceRecord_Stop();
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
#include "ghost.h"
|
||||
|
||||
#include <base/system.h>
|
||||
|
||||
#include <engine/console.h>
|
||||
#include <engine/shared/compression.h>
|
||||
#include <engine/shared/network.h>
|
||||
#include <engine/storage.h>
|
||||
|
||||
#include "compression.h"
|
||||
#include "ghost.h"
|
||||
#include "network.h"
|
||||
|
||||
static const unsigned char gs_aHeaderMarker[8] = {'T', 'W', 'G', 'H', 'O', 'S', 'T', 0};
|
||||
static const unsigned char gs_ActVersion = 5;
|
||||
static const unsigned char gs_CurVersion = 6;
|
||||
static const int gs_NumTicksOffset = 93;
|
||||
|
||||
CGhostRecorder::CGhostRecorder()
|
||||
|
@ -24,7 +24,7 @@ void CGhostRecorder::Init()
|
|||
}
|
||||
|
||||
// Record
|
||||
int CGhostRecorder::Start(const char *pFilename, const char *pMap, unsigned Crc, const char *pName)
|
||||
int CGhostRecorder::Start(const char *pFilename, const char *pMap, SHA256_DIGEST MapSha256, const char *pName)
|
||||
{
|
||||
m_File = m_pStorage->OpenFile(pFilename, IOFLAG_WRITE, IStorage::TYPE_SAVE);
|
||||
if(!m_File)
|
||||
|
@ -39,20 +39,17 @@ int CGhostRecorder::Start(const char *pFilename, const char *pMap, unsigned Crc,
|
|||
CGhostHeader Header;
|
||||
mem_zero(&Header, sizeof(Header));
|
||||
mem_copy(Header.m_aMarker, gs_aHeaderMarker, sizeof(Header.m_aMarker));
|
||||
Header.m_Version = gs_ActVersion;
|
||||
Header.m_Version = gs_CurVersion;
|
||||
str_copy(Header.m_aOwner, pName, sizeof(Header.m_aOwner));
|
||||
str_copy(Header.m_aMap, pMap, sizeof(Header.m_aMap));
|
||||
Header.m_aCrc[0] = (Crc >> 24) & 0xff;
|
||||
Header.m_aCrc[1] = (Crc >> 16) & 0xff;
|
||||
Header.m_aCrc[2] = (Crc >> 8) & 0xff;
|
||||
Header.m_aCrc[3] = (Crc)&0xff;
|
||||
Header.m_MapSha256 = MapSha256;
|
||||
io_write(m_File, &Header, sizeof(Header));
|
||||
|
||||
m_LastItem.Reset();
|
||||
ResetBuffer();
|
||||
|
||||
char aBuf[256];
|
||||
str_format(aBuf, sizeof(aBuf), "Ghost recording to '%s'", pFilename);
|
||||
str_format(aBuf, sizeof(aBuf), "ghost recording to '%s'", pFilename);
|
||||
m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "ghost_recorder", aBuf);
|
||||
return 0;
|
||||
}
|
||||
|
@ -185,7 +182,7 @@ void CGhostLoader::ResetBuffer()
|
|||
m_BufferPrevItem = -1;
|
||||
}
|
||||
|
||||
int CGhostLoader::Load(const char *pFilename, const char *pMap, unsigned Crc)
|
||||
int CGhostLoader::Load(const char *pFilename, const char *pMap, SHA256_DIGEST MapSha256, unsigned MapCrc)
|
||||
{
|
||||
m_File = m_pStorage->OpenFile(pFilename, IOFLAG_READ, IStorage::TYPE_SAVE);
|
||||
if(!m_File)
|
||||
|
@ -209,7 +206,7 @@ int CGhostLoader::Load(const char *pFilename, const char *pMap, unsigned Crc)
|
|||
return -1;
|
||||
}
|
||||
|
||||
if(m_Header.m_Version != gs_ActVersion && m_Header.m_Version != 4)
|
||||
if(!(4 <= m_Header.m_Version && m_Header.m_Version <= gs_CurVersion))
|
||||
{
|
||||
char aBuf[256];
|
||||
str_format(aBuf, sizeof(aBuf), "ghost version %d is not supported", m_Header.m_Version);
|
||||
|
@ -219,14 +216,47 @@ int CGhostLoader::Load(const char *pFilename, const char *pMap, unsigned Crc)
|
|||
return -1;
|
||||
}
|
||||
|
||||
unsigned GhostMapCrc = (m_Header.m_aCrc[0] << 24) | (m_Header.m_aCrc[1] << 16) | (m_Header.m_aCrc[2] << 8) | (m_Header.m_aCrc[3]);
|
||||
if(str_comp(m_Header.m_aMap, pMap) != 0 || GhostMapCrc != Crc)
|
||||
if(str_comp(m_Header.m_aMap, pMap) != 0)
|
||||
{
|
||||
char aBuf[256];
|
||||
str_format(aBuf, sizeof(aBuf), "ghost map name '%s' does not match current map '%s'", m_Header.m_aMap, pMap);
|
||||
m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "ghost_loader", aBuf);
|
||||
io_close(m_File);
|
||||
m_File = 0;
|
||||
return -1;
|
||||
}
|
||||
if(m_Header.m_Version >= 6)
|
||||
{
|
||||
if(m_Header.m_MapSha256 != MapSha256)
|
||||
{
|
||||
char aGhostSha256[SHA256_MAXSTRSIZE];
|
||||
sha256_str(m_Header.m_MapSha256, aGhostSha256, sizeof(aGhostSha256));
|
||||
char aMapSha256[SHA256_MAXSTRSIZE];
|
||||
sha256_str(MapSha256, aMapSha256, sizeof(aMapSha256));
|
||||
char aBuf[256];
|
||||
str_format(aBuf, sizeof(aBuf), "ghost map '%s' sha256 mismatch, wanted=%s ghost=%s", pMap, aMapSha256, aGhostSha256);
|
||||
m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "ghost_loader", aBuf);
|
||||
io_close(m_File);
|
||||
m_File = 0;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
io_skip(m_File, -(int)sizeof(SHA256_DIGEST));
|
||||
unsigned GhostMapCrc = (m_Header.m_aZeroes[0] << 24) | (m_Header.m_aZeroes[1] << 16) | (m_Header.m_aZeroes[2] << 8) | (m_Header.m_aZeroes[3]);
|
||||
if(str_comp(m_Header.m_aMap, pMap) != 0 || GhostMapCrc != MapCrc)
|
||||
{
|
||||
char aBuf[256];
|
||||
str_format(aBuf, sizeof(aBuf), "ghost map '%s' crc mismatch, wanted=%08x ghost=%08x", pMap, MapCrc, GhostMapCrc);
|
||||
m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "ghost_loader", aBuf);
|
||||
io_close(m_File);
|
||||
m_File = 0;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
m_Info = m_Header.ToGhostInfo();
|
||||
m_LastItem.Reset();
|
||||
ResetBuffer();
|
||||
|
||||
|
@ -336,177 +366,41 @@ void CGhostLoader::Close()
|
|||
m_File = 0;
|
||||
}
|
||||
|
||||
bool CGhostLoader::GetGhostInfo(const char *pFilename, CGhostHeader *pGhostHeader, const char *pMap, unsigned Crc)
|
||||
bool CGhostLoader::GetGhostInfo(const char *pFilename, CGhostInfo *pInfo, const char *pMap, SHA256_DIGEST MapSha256, unsigned MapCrc)
|
||||
{
|
||||
if(!pGhostHeader)
|
||||
return false;
|
||||
|
||||
mem_zero(pGhostHeader, sizeof(CGhostHeader));
|
||||
CGhostHeader Header;
|
||||
mem_zero(&Header, sizeof(Header));
|
||||
|
||||
IOHANDLE File = m_pStorage->OpenFile(pFilename, IOFLAG_READ, IStorage::TYPE_SAVE);
|
||||
if(!File)
|
||||
return false;
|
||||
|
||||
io_read(File, pGhostHeader, sizeof(CGhostHeader));
|
||||
|
||||
if(mem_comp(pGhostHeader->m_aMarker, gs_aHeaderMarker, sizeof(gs_aHeaderMarker)) == 0 && (pGhostHeader->m_Version == 2 || pGhostHeader->m_Version == 3))
|
||||
{
|
||||
io_close(File);
|
||||
// old version... try to update
|
||||
IGhostRecorder *pRecorder = Kernel()->RequestInterface<IGhostRecorder>();
|
||||
if(CGhostUpdater::Update(pRecorder, m_pStorage, m_pConsole, pFilename))
|
||||
{
|
||||
// try again
|
||||
File = m_pStorage->OpenFile(pFilename, IOFLAG_READ, IStorage::TYPE_SAVE);
|
||||
io_read(File, pGhostHeader, sizeof(CGhostHeader));
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
io_read(File, &Header, sizeof(Header));
|
||||
io_close(File);
|
||||
|
||||
if(mem_comp(pGhostHeader->m_aMarker, gs_aHeaderMarker, sizeof(gs_aHeaderMarker)) || (pGhostHeader->m_Version != gs_ActVersion && pGhostHeader->m_Version != 4))
|
||||
if(mem_comp(Header.m_aMarker, gs_aHeaderMarker, sizeof(gs_aHeaderMarker)) || !(4 <= Header.m_Version && Header.m_Version <= gs_CurVersion))
|
||||
return false;
|
||||
|
||||
unsigned GhostMapCrc = (pGhostHeader->m_aCrc[0] << 24) | (pGhostHeader->m_aCrc[1] << 16) | (pGhostHeader->m_aCrc[2] << 8) | (pGhostHeader->m_aCrc[3]);
|
||||
if(str_comp(pGhostHeader->m_aMap, pMap) != 0 || GhostMapCrc != Crc)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void StrToInts(int *pInts, int Num, const char *pStr)
|
||||
{
|
||||
int Index = 0;
|
||||
while(Num)
|
||||
if(str_comp(Header.m_aMap, pMap) != 0)
|
||||
{
|
||||
char aBuf[4] = {0, 0, 0, 0};
|
||||
for(int c = 0; c < 4 && pStr[Index]; c++, Index++)
|
||||
aBuf[c] = pStr[Index];
|
||||
*pInts = ((aBuf[0] + 128) << 24) | ((aBuf[1] + 128) << 16) | ((aBuf[2] + 128) << 8) | (aBuf[3] + 128);
|
||||
pInts++;
|
||||
Num--;
|
||||
}
|
||||
|
||||
// null terminate
|
||||
pInts[-1] &= 0xffffff00;
|
||||
}
|
||||
|
||||
bool CGhostUpdater::Update(class IGhostRecorder *pRecorder, class IStorage *pStorage, class IConsole *pConsole, const char *pFilename)
|
||||
{
|
||||
pStorage->CreateFolder("ghosts/backup", IStorage::TYPE_SAVE);
|
||||
|
||||
const char *pExtractedName = pFilename;
|
||||
for(const char *pSrc = pFilename; *pSrc; pSrc++)
|
||||
if(*pSrc == '/' || *pSrc == '\\')
|
||||
pExtractedName = pSrc + 1;
|
||||
|
||||
char aBackupFilename[512];
|
||||
str_format(aBackupFilename, sizeof(aBackupFilename), "ghosts/backup/%s", pExtractedName);
|
||||
if(!pStorage->RenameFile(pFilename, aBackupFilename, IStorage::TYPE_SAVE))
|
||||
return false;
|
||||
|
||||
IOHANDLE File = pStorage->OpenFile(aBackupFilename, IOFLAG_READ, IStorage::TYPE_SAVE);
|
||||
if(!File)
|
||||
return false;
|
||||
|
||||
// read header
|
||||
CGhostHeaderMain Header;
|
||||
io_read(File, &Header, sizeof(Header));
|
||||
if(mem_comp(Header.m_aMarker, gs_aHeaderMarker, sizeof(gs_aHeaderMarker)) != 0 || (Header.m_Version != 2 && Header.m_Version != 3))
|
||||
{
|
||||
pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "ghost/updater", "error: no valid ghost file");
|
||||
io_close(File);
|
||||
return false;
|
||||
}
|
||||
|
||||
io_seek(File, 0, IOSEEK_START);
|
||||
|
||||
int Ticks, Time;
|
||||
if(Header.m_Version == 2)
|
||||
if(Header.m_Version >= 6)
|
||||
{
|
||||
pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "ghost/updater", "updating v2 ghost file");
|
||||
CGhostHeaderV2 ExtHeader;
|
||||
char aSkinData[ms_SkinSizeV2];
|
||||
io_read(File, &ExtHeader, sizeof(ExtHeader));
|
||||
io_read(File, aSkinData, sizeof(aSkinData));
|
||||
|
||||
Ticks = ExtHeader.m_NumShots;
|
||||
Time = ExtHeader.m_Time * 1000;
|
||||
|
||||
unsigned Crc = (ExtHeader.m_aCrc[0] << 24) | (ExtHeader.m_aCrc[1] << 16) | (ExtHeader.m_aCrc[2] << 8) | (ExtHeader.m_aCrc[3]);
|
||||
pRecorder->Start(pFilename, ExtHeader.m_aMap, Crc, ExtHeader.m_aOwner);
|
||||
|
||||
CGhostSkin Skin;
|
||||
mem_copy(&Skin, aSkinData + ms_SkinOffsetV2, sizeof(Skin));
|
||||
pRecorder->WriteData(0 /* GHOSTDATA_TYPE_SKIN */, &Skin, sizeof(Skin));
|
||||
if(Header.m_MapSha256 != MapSha256)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "ghost/updater", "updating v3 ghost file");
|
||||
CGhostHeaderV3 ExtHeader;
|
||||
io_read(File, &ExtHeader, sizeof(ExtHeader));
|
||||
|
||||
Ticks = ExtHeader.m_NumShots;
|
||||
Time = ExtHeader.m_Time * 1000;
|
||||
|
||||
unsigned Crc = (ExtHeader.m_aCrc[0] << 24) | (ExtHeader.m_aCrc[1] << 16) | (ExtHeader.m_aCrc[2] << 8) | (ExtHeader.m_aCrc[3]);
|
||||
pRecorder->Start(pFilename, ExtHeader.m_aMap, Crc, ExtHeader.m_aOwner);
|
||||
|
||||
CGhostSkin Skin;
|
||||
StrToInts(&Skin.m_Skin0, 6, ExtHeader.m_aSkinName);
|
||||
Skin.m_UseCustomColor = ExtHeader.m_UseCustomColor;
|
||||
Skin.m_ColorBody = ExtHeader.m_ColorBody;
|
||||
Skin.m_ColorFeet = ExtHeader.m_ColorFeet;
|
||||
pRecorder->WriteData(0 /* GHOSTDATA_TYPE_SKIN */, &Skin, sizeof(Skin));
|
||||
}
|
||||
|
||||
// read data
|
||||
int Index = 0;
|
||||
while(Index < Ticks)
|
||||
{
|
||||
static char s_aCompresseddata[100 * 500];
|
||||
static char s_aDecompressed[100 * 500];
|
||||
static char s_aData[100 * 500];
|
||||
|
||||
unsigned char aSize[4];
|
||||
if(io_read(File, aSize, sizeof(aSize)) != sizeof(aSize))
|
||||
break;
|
||||
unsigned Size = (aSize[0] << 24) | (aSize[1] << 16) | (aSize[2] << 8) | aSize[3];
|
||||
|
||||
if(io_read(File, s_aCompresseddata, Size) != Size)
|
||||
unsigned GhostMapCrc = (Header.m_aZeroes[0] << 24) | (Header.m_aZeroes[1] << 16) | (Header.m_aZeroes[2] << 8) | (Header.m_aZeroes[3]);
|
||||
if(GhostMapCrc != MapCrc)
|
||||
{
|
||||
pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "ghost/updater", "error reading chunk");
|
||||
break;
|
||||
}
|
||||
|
||||
int DataSize = CNetBase::Decompress(s_aCompresseddata, Size, s_aDecompressed, sizeof(s_aDecompressed));
|
||||
if(DataSize < 0)
|
||||
{
|
||||
pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "ghost/updater", "error during network decompression");
|
||||
break;
|
||||
}
|
||||
|
||||
DataSize = CVariableInt::Decompress(s_aDecompressed, DataSize, s_aData, sizeof(s_aData));
|
||||
if(DataSize < 0)
|
||||
{
|
||||
pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "ghost/updater", "error during intpack decompression");
|
||||
break;
|
||||
}
|
||||
|
||||
char *pTmp = s_aData;
|
||||
for(int i = 0; i < DataSize / ms_GhostCharacterSize; i++)
|
||||
{
|
||||
pRecorder->WriteData(1 /* GHOSTDATA_TYPE_CHARACTER_NO_TICK */, pTmp, ms_GhostCharacterSize);
|
||||
pTmp += ms_GhostCharacterSize;
|
||||
Index++;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
*pInfo = Header.ToGhostInfo();
|
||||
|
||||
io_close(File);
|
||||
|
||||
bool Error = Ticks != Index;
|
||||
pRecorder->Stop(Index, Error ? 0 : Time);
|
||||
return !Error;
|
||||
return true;
|
||||
}
|
120
src/engine/client/ghost.h
Normal file
120
src/engine/client/ghost.h
Normal file
|
@ -0,0 +1,120 @@
|
|||
#ifndef ENGINE_CLIENT_GHOST_H
|
||||
#define ENGINE_CLIENT_GHOST_H
|
||||
|
||||
#include <engine/ghost.h>
|
||||
|
||||
enum
|
||||
{
|
||||
MAX_ITEM_SIZE = 128,
|
||||
NUM_ITEMS_PER_CHUNK = 50,
|
||||
};
|
||||
|
||||
// version 4-6
|
||||
struct CGhostHeader
|
||||
{
|
||||
unsigned char m_aMarker[8];
|
||||
unsigned char m_Version;
|
||||
char m_aOwner[MAX_NAME_LENGTH];
|
||||
char m_aMap[64];
|
||||
unsigned char m_aZeroes[4]; // Crc before version 6
|
||||
unsigned char m_aNumTicks[4];
|
||||
unsigned char m_aTime[4];
|
||||
SHA256_DIGEST m_MapSha256;
|
||||
|
||||
int GetTicks() const
|
||||
{
|
||||
return (m_aNumTicks[0] << 24) | (m_aNumTicks[1] << 16) | (m_aNumTicks[2] << 8) | (m_aNumTicks[3]);
|
||||
}
|
||||
|
||||
int GetTime() const
|
||||
{
|
||||
return (m_aTime[0] << 24) | (m_aTime[1] << 16) | (m_aTime[2] << 8) | (m_aTime[3]);
|
||||
}
|
||||
|
||||
CGhostInfo ToGhostInfo() const
|
||||
{
|
||||
CGhostInfo Result;
|
||||
mem_zero(&Result, sizeof(Result));
|
||||
str_copy(Result.m_aOwner, m_aOwner, sizeof(Result.m_aOwner));
|
||||
str_copy(Result.m_aMap, m_aMap, sizeof(Result.m_aMap));
|
||||
Result.m_NumTicks = GetTicks();
|
||||
Result.m_Time = GetTime();
|
||||
return Result;
|
||||
}
|
||||
};
|
||||
|
||||
class CGhostItem
|
||||
{
|
||||
public:
|
||||
unsigned char m_aData[MAX_ITEM_SIZE];
|
||||
int m_Type;
|
||||
|
||||
CGhostItem() :
|
||||
m_Type(-1) {}
|
||||
CGhostItem(int Type) :
|
||||
m_Type(Type) {}
|
||||
void Reset() { m_Type = -1; }
|
||||
};
|
||||
|
||||
class CGhostRecorder : public IGhostRecorder
|
||||
{
|
||||
IOHANDLE m_File;
|
||||
class IConsole *m_pConsole;
|
||||
class IStorage *m_pStorage;
|
||||
|
||||
CGhostItem m_LastItem;
|
||||
|
||||
char m_aBuffer[MAX_ITEM_SIZE * NUM_ITEMS_PER_CHUNK];
|
||||
char *m_pBufferPos;
|
||||
int m_BufferNumItems;
|
||||
|
||||
void ResetBuffer();
|
||||
void FlushChunk();
|
||||
|
||||
public:
|
||||
CGhostRecorder();
|
||||
|
||||
void Init();
|
||||
|
||||
int Start(const char *pFilename, const char *pMap, SHA256_DIGEST MapSha256, const char *pName);
|
||||
int Stop(int Ticks, int Time);
|
||||
|
||||
void WriteData(int Type, const void *pData, int Size);
|
||||
bool IsRecording() const { return m_File != 0; }
|
||||
};
|
||||
|
||||
class CGhostLoader : public IGhostLoader
|
||||
{
|
||||
IOHANDLE m_File;
|
||||
class IConsole *m_pConsole;
|
||||
class IStorage *m_pStorage;
|
||||
|
||||
CGhostHeader m_Header;
|
||||
CGhostInfo m_Info;
|
||||
|
||||
CGhostItem m_LastItem;
|
||||
|
||||
char m_aBuffer[MAX_ITEM_SIZE * NUM_ITEMS_PER_CHUNK];
|
||||
char *m_pBufferPos;
|
||||
int m_BufferNumItems;
|
||||
int m_BufferCurItem;
|
||||
int m_BufferPrevItem;
|
||||
|
||||
void ResetBuffer();
|
||||
int ReadChunk(int *pType);
|
||||
|
||||
public:
|
||||
CGhostLoader();
|
||||
|
||||
void Init();
|
||||
|
||||
int Load(const char *pFilename, const char *pMap, SHA256_DIGEST MapSha256, unsigned MapCrc);
|
||||
void Close();
|
||||
const CGhostInfo *GetInfo() const { return &m_Info; }
|
||||
|
||||
bool ReadNextType(int *pType);
|
||||
bool ReadData(int Type, void *pData, int Size);
|
||||
|
||||
bool GetGhostInfo(const char *pFilename, CGhostInfo *pGhostInfo, const char *pMap, SHA256_DIGEST MapSha256, unsigned MapCrc);
|
||||
};
|
||||
#endif
|
|
@ -1,31 +1,19 @@
|
|||
#ifndef ENGINE_GHOST_H
|
||||
#define ENGINE_GHOST_H
|
||||
|
||||
#include <base/hash.h>
|
||||
#include <engine/map.h>
|
||||
#include <engine/shared/protocol.h>
|
||||
|
||||
#include "kernel.h"
|
||||
|
||||
class CGhostHeader
|
||||
class CGhostInfo
|
||||
{
|
||||
public:
|
||||
unsigned char m_aMarker[8];
|
||||
unsigned char m_Version;
|
||||
char m_aOwner[MAX_NAME_LENGTH];
|
||||
char m_aMap[64];
|
||||
unsigned char m_aCrc[4];
|
||||
unsigned char m_aNumTicks[4];
|
||||
unsigned char m_aTime[4];
|
||||
|
||||
int GetTime() const
|
||||
{
|
||||
return (m_aTime[0] << 24) | (m_aTime[1] << 16) | (m_aTime[2] << 8) | (m_aTime[3]);
|
||||
}
|
||||
|
||||
int GetTicks() const
|
||||
{
|
||||
return (m_aNumTicks[0] << 24) | (m_aNumTicks[1] << 16) | (m_aNumTicks[2] << 8) | (m_aNumTicks[3]);
|
||||
}
|
||||
int m_NumTicks;
|
||||
int m_Time;
|
||||
};
|
||||
|
||||
class IGhostRecorder : public IInterface
|
||||
|
@ -34,7 +22,7 @@ class IGhostRecorder : public IInterface
|
|||
public:
|
||||
virtual ~IGhostRecorder() {}
|
||||
|
||||
virtual int Start(const char *pFilename, const char *pMap, unsigned MapCrc, const char *pName) = 0;
|
||||
virtual int Start(const char *pFilename, const char *pMap, SHA256_DIGEST MapSha256, const char *pName) = 0;
|
||||
virtual int Stop(int Ticks, int Time) = 0;
|
||||
|
||||
virtual void WriteData(int Type, const void *pData, int Size) = 0;
|
||||
|
@ -47,15 +35,15 @@ class IGhostLoader : public IInterface
|
|||
public:
|
||||
virtual ~IGhostLoader() {}
|
||||
|
||||
virtual int Load(const char *pFilename, const char *pMap, unsigned Crc) = 0;
|
||||
virtual int Load(const char *pFilename, const char *pMap, SHA256_DIGEST MapSha256, unsigned MapCrc) = 0;
|
||||
virtual void Close() = 0;
|
||||
|
||||
virtual const CGhostHeader *GetHeader() const = 0;
|
||||
virtual const CGhostInfo *GetInfo() const = 0;
|
||||
|
||||
virtual bool ReadNextType(int *pType) = 0;
|
||||
virtual bool ReadData(int Type, void *pData, int Size) = 0;
|
||||
|
||||
virtual bool GetGhostInfo(const char *pFilename, CGhostHeader *pGhostHeader, const char *pMap, unsigned Crc) = 0;
|
||||
virtual bool GetGhostInfo(const char *pFilename, CGhostInfo *pInfo, const char *pMap, SHA256_DIGEST MapSha256, unsigned MapCrc) = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -2265,8 +2265,6 @@ int CServer::LoadMap(const char *pMapName)
|
|||
sha256_str(m_aCurrentMapSha256[SIX], aSha256, sizeof(aSha256));
|
||||
str_format(aBufMsg, sizeof(aBufMsg), "%s sha256 is %s", aBuf, aSha256);
|
||||
Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "server", aBufMsg);
|
||||
str_format(aBufMsg, sizeof(aBufMsg), "%s crc is %08x", aBuf, m_aCurrentMapCrc[SIX]);
|
||||
Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "server", aBufMsg);
|
||||
|
||||
str_copy(m_aCurrentMap, pMapName, sizeof(m_aCurrentMap));
|
||||
|
||||
|
@ -2304,8 +2302,6 @@ int CServer::LoadMap(const char *pMapName)
|
|||
sha256_str(m_aCurrentMapSha256[SIXUP], aSha256, sizeof(aSha256));
|
||||
str_format(aBufMsg, sizeof(aBufMsg), "%s sha256 is %s", aBuf, aSha256);
|
||||
Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "sixup", aBufMsg);
|
||||
str_format(aBufMsg, sizeof(aBufMsg), "%s crc is %08x", aBuf, m_aCurrentMapCrc[SIXUP]);
|
||||
Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "sixup", aBufMsg);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -84,15 +84,13 @@ int CDemoRecorder::Start(class IStorage *pStorage, class IConsole *pConsole, con
|
|||
// try the downloaded maps
|
||||
if(pSha256)
|
||||
{
|
||||
str_format(aMapFilename, sizeof(aMapFilename), "downloadedmaps/%s_%08x_%s.map", pMap, Crc, aSha256);
|
||||
MapFile = pStorage->OpenFile(aMapFilename, IOFLAG_READ, IStorage::TYPE_ALL);
|
||||
str_format(aMapFilename, sizeof(aMapFilename), "downloadedmaps/%s_%s.map", pMap, aSha256);
|
||||
}
|
||||
if(!MapFile)
|
||||
else
|
||||
{
|
||||
// try the downloaded maps without sha
|
||||
str_format(aMapFilename, sizeof(aMapFilename), "downloadedmaps/%s_%08x.map", pMap, Crc);
|
||||
MapFile = pStorage->OpenFile(aMapFilename, IOFLAG_READ, IStorage::TYPE_ALL);
|
||||
}
|
||||
MapFile = pStorage->OpenFile(aMapFilename, IOFLAG_READ, IStorage::TYPE_ALL);
|
||||
if(!MapFile)
|
||||
{
|
||||
// try the normal maps folder
|
||||
|
@ -849,7 +847,7 @@ bool CDemoPlayer::ExtractMap(class IStorage *pStorage)
|
|||
// construct name
|
||||
char aSha[SHA256_MAXSTRSIZE], aMapFilename[128];
|
||||
sha256_str(Sha256, aSha, sizeof(aSha));
|
||||
str_format(aMapFilename, sizeof(aMapFilename), "downloadedmaps/%s_%08x_%s.map", m_Info.m_Header.m_aMapName, m_MapInfo.m_Crc, aSha);
|
||||
str_format(aMapFilename, sizeof(aMapFilename), "downloadedmaps/%s_%s.map", m_Info.m_Header.m_aMapName, aSha);
|
||||
|
||||
// save map
|
||||
IOHANDLE MapFile = pStorage->OpenFile(aMapFilename, IOFLAG_WRITE, IStorage::TYPE_SAVE);
|
||||
|
|
|
@ -1,146 +0,0 @@
|
|||
#ifndef ENGINE_SHARED_GHOST_H
|
||||
#define ENGINE_SHARED_GHOST_H
|
||||
|
||||
#include <engine/ghost.h>
|
||||
|
||||
enum
|
||||
{
|
||||
MAX_ITEM_SIZE = 128,
|
||||
NUM_ITEMS_PER_CHUNK = 50,
|
||||
};
|
||||
|
||||
class CGhostItem
|
||||
{
|
||||
public:
|
||||
unsigned char m_aData[MAX_ITEM_SIZE];
|
||||
int m_Type;
|
||||
|
||||
CGhostItem() :
|
||||
m_Type(-1) {}
|
||||
CGhostItem(int Type) :
|
||||
m_Type(Type) {}
|
||||
void Reset() { m_Type = -1; }
|
||||
};
|
||||
|
||||
class CGhostRecorder : public IGhostRecorder
|
||||
{
|
||||
IOHANDLE m_File;
|
||||
class IConsole *m_pConsole;
|
||||
class IStorage *m_pStorage;
|
||||
|
||||
CGhostItem m_LastItem;
|
||||
|
||||
char m_aBuffer[MAX_ITEM_SIZE * NUM_ITEMS_PER_CHUNK];
|
||||
char *m_pBufferPos;
|
||||
int m_BufferNumItems;
|
||||
|
||||
void ResetBuffer();
|
||||
void FlushChunk();
|
||||
|
||||
public:
|
||||
CGhostRecorder();
|
||||
|
||||
void Init();
|
||||
|
||||
int Start(const char *pFilename, const char *pMap, unsigned MapCrc, const char *pName);
|
||||
int Stop(int Ticks, int Time);
|
||||
|
||||
void WriteData(int Type, const void *pData, int Size);
|
||||
bool IsRecording() const { return m_File != 0; }
|
||||
};
|
||||
|
||||
class CGhostLoader : public IGhostLoader
|
||||
{
|
||||
IOHANDLE m_File;
|
||||
class IConsole *m_pConsole;
|
||||
class IStorage *m_pStorage;
|
||||
|
||||
CGhostHeader m_Header;
|
||||
|
||||
CGhostItem m_LastItem;
|
||||
|
||||
char m_aBuffer[MAX_ITEM_SIZE * NUM_ITEMS_PER_CHUNK];
|
||||
char *m_pBufferPos;
|
||||
int m_BufferNumItems;
|
||||
int m_BufferCurItem;
|
||||
int m_BufferPrevItem;
|
||||
|
||||
void ResetBuffer();
|
||||
int ReadChunk(int *pType);
|
||||
|
||||
public:
|
||||
CGhostLoader();
|
||||
|
||||
void Init();
|
||||
|
||||
int Load(const char *pFilename, const char *pMap, unsigned Crc);
|
||||
void Close();
|
||||
const CGhostHeader *GetHeader() const { return &m_Header; }
|
||||
|
||||
bool ReadNextType(int *pType);
|
||||
bool ReadData(int Type, void *pData, int Size);
|
||||
|
||||
bool GetGhostInfo(const char *pFilename, CGhostHeader *pGhostHeader, const char *pMap, unsigned Crc);
|
||||
};
|
||||
|
||||
class CGhostUpdater
|
||||
{
|
||||
// all
|
||||
struct CGhostHeaderMain
|
||||
{
|
||||
unsigned char m_aMarker[8];
|
||||
unsigned char m_Version;
|
||||
};
|
||||
|
||||
// version 2
|
||||
struct CGhostHeaderV2
|
||||
{
|
||||
unsigned char m_aMarker[8];
|
||||
unsigned char m_Version;
|
||||
char m_aOwner[MAX_NAME_LENGTH];
|
||||
char m_aMap[64];
|
||||
unsigned char m_aCrc[4];
|
||||
int m_NumShots;
|
||||
float m_Time;
|
||||
};
|
||||
|
||||
static const int ms_SkinSizeV2 = 17 * sizeof(int);
|
||||
static const int ms_SkinOffsetV2 = 8 * sizeof(int);
|
||||
|
||||
// version 3
|
||||
struct CGhostHeaderV3
|
||||
{
|
||||
unsigned char m_aMarker[8];
|
||||
unsigned char m_Version;
|
||||
char m_aOwner[MAX_NAME_LENGTH];
|
||||
char m_aSkinName[64];
|
||||
int m_UseCustomColor;
|
||||
int m_ColorBody;
|
||||
int m_ColorFeet;
|
||||
char m_aMap[64];
|
||||
unsigned char m_aCrc[4];
|
||||
int m_NumShots;
|
||||
float m_Time;
|
||||
};
|
||||
|
||||
// actual version
|
||||
struct CGhostSkin
|
||||
{
|
||||
int m_Skin0;
|
||||
int m_Skin1;
|
||||
int m_Skin2;
|
||||
int m_Skin3;
|
||||
int m_Skin4;
|
||||
int m_Skin5;
|
||||
int m_UseCustomColor;
|
||||
int m_ColorBody;
|
||||
int m_ColorFeet;
|
||||
};
|
||||
|
||||
static const int ms_GhostCharacterSize = 11 * sizeof(int);
|
||||
|
||||
public:
|
||||
static bool Update(class IGhostRecorder *pRecorder, class IStorage *pStorage, class IConsole *pConsole, const char *pFilename);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -119,16 +119,18 @@ CGhostCharacter *CGhost::CGhostPath::Get(int Index)
|
|||
void CGhost::GetPath(char *pBuf, int Size, const char *pPlayerName, int Time) const
|
||||
{
|
||||
const char *pMap = Client()->GetCurrentMap();
|
||||
unsigned Crc = Client()->GetMapCrc();
|
||||
SHA256_DIGEST Sha256 = Client()->GetCurrentMapSha256();
|
||||
char aSha256[SHA256_MAXSTRSIZE];
|
||||
sha256_str(Sha256, aSha256, sizeof(aSha256));
|
||||
|
||||
char aPlayerName[MAX_NAME_LENGTH];
|
||||
str_copy(aPlayerName, pPlayerName, sizeof(aPlayerName));
|
||||
str_sanitize_filename(aPlayerName);
|
||||
|
||||
if(Time < 0)
|
||||
str_format(pBuf, Size, "%s/%s_%s_%08x_tmp_%d.gho", ms_pGhostDir, pMap, aPlayerName, Crc, pid());
|
||||
str_format(pBuf, Size, "%s/%s_%s_%s_tmp_%d.gho", ms_pGhostDir, pMap, aPlayerName, aSha256, pid());
|
||||
else
|
||||
str_format(pBuf, Size, "%s/%s_%s_%d.%03d_%08x.gho", ms_pGhostDir, pMap, aPlayerName, Time / 1000, Time % 1000, Crc);
|
||||
str_format(pBuf, Size, "%s/%s_%s_%d.%03d_%s.gho", ms_pGhostDir, pMap, aPlayerName, Time / 1000, Time % 1000, aSha256);
|
||||
}
|
||||
|
||||
void CGhost::AddInfos(const CNetObj_Character *pChar)
|
||||
|
@ -139,7 +141,7 @@ void CGhost::AddInfos(const CNetObj_Character *pChar)
|
|||
if(g_Config.m_ClRaceSaveGhost && !GhostRecorder()->IsRecording() && NumTicks > 0)
|
||||
{
|
||||
GetPath(m_aTmpFilename, sizeof(m_aTmpFilename), m_CurGhost.m_aPlayer);
|
||||
GhostRecorder()->Start(m_aTmpFilename, Client()->GetCurrentMap(), Client()->GetMapCrc(), m_CurGhost.m_aPlayer);
|
||||
GhostRecorder()->Start(m_aTmpFilename, Client()->GetCurrentMap(), Client()->GetCurrentMapSha256(), m_CurGhost.m_aPlayer);
|
||||
|
||||
GhostRecorder()->WriteData(GHOSTDATA_TYPE_START_TICK, &m_CurGhost.m_StartTick, sizeof(int));
|
||||
GhostRecorder()->WriteData(GHOSTDATA_TYPE_SKIN, &m_CurGhost.m_Skin, sizeof(CGhostSkin));
|
||||
|
@ -445,15 +447,14 @@ int CGhost::Load(const char *pFilename)
|
|||
if(Slot == -1)
|
||||
return -1;
|
||||
|
||||
if(GhostLoader()->Load(pFilename, Client()->GetCurrentMap(), Client()->GetMapCrc()) != 0)
|
||||
if(GhostLoader()->Load(pFilename, Client()->GetCurrentMap(), Client()->GetCurrentMapSha256(), Client()->GetCurrentMapCrc()) != 0)
|
||||
return -1;
|
||||
|
||||
const CGhostHeader *pHeader = GhostLoader()->GetHeader();
|
||||
const CGhostInfo *pInfo = GhostLoader()->GetInfo();
|
||||
|
||||
int NumTicks = pHeader->GetTicks();
|
||||
int Time = pHeader->GetTime();
|
||||
if(NumTicks <= 0 || Time <= 0)
|
||||
if(pInfo->m_NumTicks <= 0 || pInfo->m_Time <= 0)
|
||||
{
|
||||
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "ghost", "invalid header info");
|
||||
GhostLoader()->Close();
|
||||
return -1;
|
||||
}
|
||||
|
@ -461,9 +462,9 @@ int CGhost::Load(const char *pFilename)
|
|||
// select ghost
|
||||
CGhostItem *pGhost = &m_aActiveGhosts[Slot];
|
||||
pGhost->Reset();
|
||||
pGhost->m_Path.SetSize(NumTicks);
|
||||
pGhost->m_Path.SetSize(pInfo->m_NumTicks);
|
||||
|
||||
str_copy(pGhost->m_aPlayer, pHeader->m_aOwner, sizeof(pGhost->m_aPlayer));
|
||||
str_copy(pGhost->m_aPlayer, pInfo->m_aOwner, sizeof(pGhost->m_aPlayer));
|
||||
|
||||
int Index = 0;
|
||||
bool FoundSkin = false;
|
||||
|
@ -473,7 +474,7 @@ int CGhost::Load(const char *pFilename)
|
|||
int Type;
|
||||
while(!Error && GhostLoader()->ReadNextType(&Type))
|
||||
{
|
||||
if(Index == NumTicks && (Type == GHOSTDATA_TYPE_CHARACTER || Type == GHOSTDATA_TYPE_CHARACTER_NO_TICK))
|
||||
if(Index == pInfo->m_NumTicks && (Type == GHOSTDATA_TYPE_CHARACTER || Type == GHOSTDATA_TYPE_CHARACTER_NO_TICK))
|
||||
{
|
||||
Error = true;
|
||||
break;
|
||||
|
@ -505,8 +506,9 @@ int CGhost::Load(const char *pFilename)
|
|||
|
||||
GhostLoader()->Close();
|
||||
|
||||
if(Error || Index != NumTicks)
|
||||
if(Error || Index != pInfo->m_NumTicks)
|
||||
{
|
||||
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "ghost", "invalid ghost data");
|
||||
pGhost->Reset();
|
||||
return -1;
|
||||
}
|
||||
|
@ -514,10 +516,10 @@ int CGhost::Load(const char *pFilename)
|
|||
if(NoTick)
|
||||
{
|
||||
int StartTick = 0;
|
||||
for(int i = 1; i < NumTicks; i++) // estimate start tick
|
||||
for(int i = 1; i < pInfo->m_NumTicks; i++) // estimate start tick
|
||||
if(pGhost->m_Path.Get(i)->m_AttackTick != pGhost->m_Path.Get(i - 1)->m_AttackTick)
|
||||
StartTick = pGhost->m_Path.Get(i)->m_AttackTick - i;
|
||||
for(int i = 0; i < NumTicks; i++)
|
||||
for(int i = 0; i < pInfo->m_NumTicks; i++)
|
||||
pGhost->m_Path.Get(i)->m_Tick = StartTick + i;
|
||||
}
|
||||
|
||||
|
@ -552,7 +554,7 @@ void CGhost::SaveGhost(CMenus::CGhostItem *pItem)
|
|||
|
||||
int NumTicks = pGhost->m_Path.Size();
|
||||
GetPath(pItem->m_aFilename, sizeof(pItem->m_aFilename), pItem->m_aPlayer, pItem->m_Time);
|
||||
GhostRecorder()->Start(pItem->m_aFilename, Client()->GetCurrentMap(), Client()->GetMapCrc(), pItem->m_aPlayer);
|
||||
GhostRecorder()->Start(pItem->m_aFilename, Client()->GetCurrentMap(), Client()->GetCurrentMapSha256(), pItem->m_aPlayer);
|
||||
|
||||
GhostRecorder()->WriteData(GHOSTDATA_TYPE_START_TICK, &pGhost->m_StartTick, sizeof(int));
|
||||
GhostRecorder()->WriteData(GHOSTDATA_TYPE_SKIN, &pGhost->m_Skin, sizeof(CGhostSkin));
|
||||
|
|
|
@ -958,22 +958,21 @@ void CMenus::RenderDemoList(CUIRect MainView)
|
|||
Labels.HSplitTop(5.0f, 0, &Labels);
|
||||
Labels.HSplitTop(20.0f, &Left, &Labels);
|
||||
Left.VSplitLeft(150.0f, &Left, &Right);
|
||||
UI()->DoLabelScaled(&Left, Localize("Crc:"), 14.0f, -1);
|
||||
str_format(aBuf, sizeof(aBuf), "%08x", m_lDemos[m_DemolistSelectedIndex].m_MapInfo.m_Crc);
|
||||
UI()->DoLabelScaled(&Right, aBuf, 14.0f, -1);
|
||||
Labels.HSplitTop(5.0f, 0, &Labels);
|
||||
Labels.HSplitTop(20.0f, &Left, &Labels);
|
||||
|
||||
if(m_lDemos[m_DemolistSelectedIndex].m_MapInfo.m_Sha256 != SHA256_ZEROED)
|
||||
{
|
||||
Left.VSplitLeft(150.0f, &Left, &Right);
|
||||
UI()->DoLabelScaled(&Left, "SHA256:", 14.0f, -1);
|
||||
char aSha[SHA256_MAXSTRSIZE];
|
||||
sha256_str(m_lDemos[m_DemolistSelectedIndex].m_MapInfo.m_Sha256, aSha, sizeof(aSha) / 2);
|
||||
UI()->DoLabelScaled(&Right, aSha, Right.w > 235 ? 14.0f : 11.0f, -1);
|
||||
Labels.HSplitTop(5.0f, 0, &Labels);
|
||||
Labels.HSplitTop(20.0f, &Left, &Labels);
|
||||
}
|
||||
else
|
||||
{
|
||||
UI()->DoLabelScaled(&Left, Localize("Crc:"), 14.0f, -1);
|
||||
str_format(aBuf, sizeof(aBuf), "%08x", m_lDemos[m_DemolistSelectedIndex].m_MapInfo.m_Crc);
|
||||
UI()->DoLabelScaled(&Right, aBuf, 14.0f, -1);
|
||||
}
|
||||
Labels.HSplitTop(5.0f, 0, &Labels);
|
||||
Labels.HSplitTop(20.0f, &Left, &Labels);
|
||||
|
||||
Left.VSplitLeft(150.0f, &Left, &Right);
|
||||
UI()->DoLabelScaled(&Left, Localize("Netversion:"), 14.0f, -1);
|
||||
|
|
|
@ -882,14 +882,14 @@ int CMenus::GhostlistFetchCallback(const char *pName, int IsDir, int StorageType
|
|||
char aFilename[256];
|
||||
str_format(aFilename, sizeof(aFilename), "%s/%s", pSelf->m_pClient->m_pGhost->GetGhostDir(), pName);
|
||||
|
||||
CGhostHeader Header;
|
||||
if(!pSelf->m_pClient->m_pGhost->GhostLoader()->GetGhostInfo(aFilename, &Header, pMap, pSelf->Client()->GetMapCrc()))
|
||||
CGhostInfo Info;
|
||||
if(!pSelf->m_pClient->m_pGhost->GhostLoader()->GetGhostInfo(aFilename, &Info, pMap, pSelf->Client()->GetCurrentMapSha256(), pSelf->Client()->GetCurrentMapCrc()))
|
||||
return 0;
|
||||
|
||||
CGhostItem Item;
|
||||
str_copy(Item.m_aFilename, aFilename, sizeof(Item.m_aFilename));
|
||||
str_copy(Item.m_aPlayer, Header.m_aOwner, sizeof(Item.m_aPlayer));
|
||||
Item.m_Time = Header.GetTime();
|
||||
str_copy(Item.m_aPlayer, Info.m_aOwner, sizeof(Item.m_aPlayer));
|
||||
Item.m_Time = Info.m_Time;
|
||||
if(Item.m_Time > 0)
|
||||
pSelf->m_lGhosts.add(Item);
|
||||
return 0;
|
||||
|
|
|
@ -7,13 +7,11 @@ struct CMapDescription
|
|||
const char *m_pName;
|
||||
int m_Size;
|
||||
SHA256_DIGEST m_Sha256;
|
||||
int m_Crc;
|
||||
|
||||
bool operator==(const CMapDescription &Other) const
|
||||
{
|
||||
return str_comp(m_pName, Other.m_pName) == 0 &&
|
||||
m_Size == Other.m_Size &&
|
||||
m_Crc == Other.m_Crc;
|
||||
m_Size == Other.m_Size;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -45,11 +43,11 @@ static SHA256_DIGEST s(const char *pSha256)
|
|||
|
||||
static CMapBugsInternal MAP_BUGS[] =
|
||||
{
|
||||
{{"Binary", 2022597, s("65b410e197fd2298ec270e89a84b762f6739d1d18089529f8ef6cf2104d3d600"), 0x0ae3a3d5}, BugToFlag(BUG_GRENADE_DOUBLEEXPLOSION)}};
|
||||
{{"Binary", 2022597, s("65b410e197fd2298ec270e89a84b762f6739d1d18089529f8ef6cf2104d3d600")}, BugToFlag(BUG_GRENADE_DOUBLEEXPLOSION)}};
|
||||
|
||||
CMapBugs GetMapBugs(const char *pName, int Size, SHA256_DIGEST Sha256, int Crc)
|
||||
CMapBugs GetMapBugs(const char *pName, int Size, SHA256_DIGEST Sha256)
|
||||
{
|
||||
CMapDescription Map = {pName, Size, Sha256, Crc};
|
||||
CMapDescription Map = {pName, Size, Sha256};
|
||||
CMapBugs Result;
|
||||
Result.m_Extra = 0;
|
||||
for(unsigned int i = 0; i < sizeof(MAP_BUGS) / sizeof(MAP_BUGS[0]); i++)
|
||||
|
@ -122,10 +120,9 @@ void CMapBugs::Dump() const
|
|||
{
|
||||
char aSha256[SHA256_MAXSTRSIZE];
|
||||
sha256_str(pInternal->m_Map.m_Sha256, aSha256, sizeof(aSha256));
|
||||
dbg_msg("mapbugs", "map='%s' map_size=%d map_sha256=%s map_crc=%08x",
|
||||
dbg_msg("mapbugs", "map='%s' map_size=%d map_sha256=%s",
|
||||
pInternal->m_Map.m_pName,
|
||||
pInternal->m_Map.m_Size,
|
||||
aSha256,
|
||||
pInternal->m_Map.m_Crc);
|
||||
aSha256);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ enum
|
|||
|
||||
class CMapBugs
|
||||
{
|
||||
friend CMapBugs GetMapBugs(const char *pName, int Size, SHA256_DIGEST Sha256, int Crc);
|
||||
friend CMapBugs GetMapBugs(const char *pName, int Size, SHA256_DIGEST Sha256);
|
||||
void *m_pData;
|
||||
unsigned int m_Extra;
|
||||
|
||||
|
@ -30,5 +30,5 @@ public:
|
|||
void Dump() const;
|
||||
};
|
||||
|
||||
CMapBugs GetMapBugs(const char *pName, int Size, SHA256_DIGEST Sha256, int Crc);
|
||||
CMapBugs GetMapBugs(const char *pName, int Size, SHA256_DIGEST Sha256);
|
||||
#endif // GAME_MAPBUGS_H
|
||||
|
|
|
@ -3019,7 +3019,7 @@ void CGameContext::OnInit(/*class IKernel *pKernel*/)
|
|||
SHA256_DIGEST MapSha256;
|
||||
int MapCrc;
|
||||
Server()->GetMapInfo(aMapName, sizeof(aMapName), &MapSize, &MapSha256, &MapCrc);
|
||||
m_MapBugs = GetMapBugs(aMapName, MapSize, MapSha256, MapCrc);
|
||||
m_MapBugs = GetMapBugs(aMapName, MapSize, MapSha256);
|
||||
|
||||
// reset everything here
|
||||
//world = new GAMEWORLD;
|
||||
|
|
|
@ -6,32 +6,31 @@
|
|||
static const char *BINARY_SHA256 = "65b410e197fd2298ec270e89a84b762f6739d1d18089529f8ef6cf2104d3d600";
|
||||
static const char *DM1_SHA256 = "0b0c481d77519c32fbe85624ef16ec0fa9991aec7367ad538bd280f28d8c26cf";
|
||||
|
||||
static CMapBugs GetMapBugsImpl(const char *pName, int Size, const char *pSha256, int Crc)
|
||||
static CMapBugs GetMapBugsImpl(const char *pName, int Size, const char *pSha256)
|
||||
{
|
||||
SHA256_DIGEST Sha256 = {{0}};
|
||||
dbg_assert(sha256_from_str(&Sha256, pSha256) == 0, "invalid sha256 in tests");
|
||||
return GetMapBugs(pName, Size, Sha256, Crc);
|
||||
return GetMapBugs(pName, Size, Sha256);
|
||||
}
|
||||
|
||||
TEST(MapBugs, Contains)
|
||||
{
|
||||
EXPECT_TRUE(GetMapBugsImpl("Binary", 2022597, BINARY_SHA256, 0x0ae3a3d5).Contains(BUG_GRENADE_DOUBLEEXPLOSION));
|
||||
EXPECT_FALSE(GetMapBugsImpl("Binarx", 2022597, BINARY_SHA256, 0x0ae3a3d5).Contains(BUG_GRENADE_DOUBLEEXPLOSION));
|
||||
EXPECT_FALSE(GetMapBugsImpl("Binary", 2022597, BINARY_SHA256, 0x0ae3a3d6).Contains(BUG_GRENADE_DOUBLEEXPLOSION));
|
||||
EXPECT_FALSE(GetMapBugsImpl("Binary", 2022598, BINARY_SHA256, 0x0ae3a3d5).Contains(BUG_GRENADE_DOUBLEEXPLOSION));
|
||||
EXPECT_FALSE(GetMapBugsImpl("dm1", 5805, DM1_SHA256, 0xf2159e6e).Contains(BUG_GRENADE_DOUBLEEXPLOSION));
|
||||
EXPECT_TRUE(GetMapBugsImpl("Binary", 2022597, BINARY_SHA256).Contains(BUG_GRENADE_DOUBLEEXPLOSION));
|
||||
EXPECT_FALSE(GetMapBugsImpl("Binarx", 2022597, BINARY_SHA256).Contains(BUG_GRENADE_DOUBLEEXPLOSION));
|
||||
EXPECT_FALSE(GetMapBugsImpl("Binary", 2022598, BINARY_SHA256).Contains(BUG_GRENADE_DOUBLEEXPLOSION));
|
||||
EXPECT_FALSE(GetMapBugsImpl("dm1", 5805, DM1_SHA256).Contains(BUG_GRENADE_DOUBLEEXPLOSION));
|
||||
}
|
||||
|
||||
TEST(MapBugs, Update)
|
||||
{
|
||||
{
|
||||
CMapBugs Binary = GetMapBugsImpl("Binary", 2022597, BINARY_SHA256, 0x0ae3a3d5);
|
||||
CMapBugs Binary = GetMapBugsImpl("Binary", 2022597, BINARY_SHA256);
|
||||
EXPECT_EQ(Binary.Update("grenade-doubleexplosion@ddnet.tw"), MAPBUGUPDATE_OVERRIDDEN);
|
||||
EXPECT_EQ(Binary.Update("doesntexist@invalid"), MAPBUGUPDATE_NOTFOUND);
|
||||
EXPECT_TRUE(Binary.Contains(BUG_GRENADE_DOUBLEEXPLOSION));
|
||||
}
|
||||
{
|
||||
CMapBugs Dm1 = GetMapBugsImpl("dm1", 5805, DM1_SHA256, 0xf2159e6e);
|
||||
CMapBugs Dm1 = GetMapBugsImpl("dm1", 5805, DM1_SHA256);
|
||||
EXPECT_FALSE(Dm1.Contains(BUG_GRENADE_DOUBLEEXPLOSION));
|
||||
EXPECT_EQ(Dm1.Update("doesntexist@invalid"), MAPBUGUPDATE_NOTFOUND);
|
||||
EXPECT_FALSE(Dm1.Contains(BUG_GRENADE_DOUBLEEXPLOSION));
|
||||
|
@ -42,6 +41,6 @@ TEST(MapBugs, Update)
|
|||
|
||||
TEST(MapBugs, Dump)
|
||||
{
|
||||
GetMapBugsImpl("Binary", 2022597, BINARY_SHA256, 0x0ae3a3d5).Dump();
|
||||
GetMapBugsImpl("dm1", 5805, DM1_SHA256, 0xf2159e6e).Dump();
|
||||
GetMapBugsImpl("Binary", 2022597, BINARY_SHA256).Dump();
|
||||
GetMapBugsImpl("dm1", 5805, DM1_SHA256).Dump();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue