1#ifndef ENGINE_CLIENT_GHOST_H
2#define ENGINE_CLIENT_GHOST_H
3
4#include <engine/ghost.h>
5
6#include <base/system.h>
7
8enum
9{
10 MAX_ITEM_SIZE = 128,
11 NUM_ITEMS_PER_CHUNK = 50,
12};
13
14// version 4-6
15struct CGhostHeader
16{
17 unsigned char m_aMarker[8];
18 unsigned char m_Version;
19 char m_aOwner[MAX_NAME_LENGTH];
20 char m_aMap[64];
21 unsigned char m_aZeroes[sizeof(int32_t)]; // Crc before version 6
22 unsigned char m_aNumTicks[sizeof(int32_t)];
23 unsigned char m_aTime[sizeof(int32_t)];
24 SHA256_DIGEST m_MapSha256;
25
26 int GetTicks() const
27 {
28 return bytes_be_to_uint(bytes: m_aNumTicks);
29 }
30
31 int GetTime() const
32 {
33 return bytes_be_to_uint(bytes: m_aTime);
34 }
35
36 CGhostInfo ToGhostInfo() const
37 {
38 CGhostInfo Result;
39 mem_zero(block: &Result, size: sizeof(Result));
40 str_copy(dst&: Result.m_aOwner, src: m_aOwner);
41 str_copy(dst&: Result.m_aMap, src: m_aMap);
42 Result.m_NumTicks = GetTicks();
43 Result.m_Time = GetTime();
44 return Result;
45 }
46};
47
48class CGhostItem
49{
50public:
51 unsigned char m_aData[MAX_ITEM_SIZE];
52 int m_Type;
53
54 CGhostItem() :
55 m_Type(-1) {}
56 CGhostItem(int Type) :
57 m_Type(Type) {}
58 void Reset() { m_Type = -1; }
59};
60
61class CGhostRecorder : public IGhostRecorder
62{
63 IOHANDLE m_File;
64 class IConsole *m_pConsole;
65 class IStorage *m_pStorage;
66
67 CGhostItem m_LastItem;
68
69 char m_aBuffer[MAX_ITEM_SIZE * NUM_ITEMS_PER_CHUNK];
70 char *m_pBufferPos;
71 int m_BufferNumItems;
72
73 void ResetBuffer();
74 void FlushChunk();
75
76public:
77 CGhostRecorder();
78
79 void Init();
80
81 int Start(const char *pFilename, const char *pMap, SHA256_DIGEST MapSha256, const char *pName) override;
82 int Stop(int Ticks, int Time) override;
83
84 void WriteData(int Type, const void *pData, int Size) override;
85 bool IsRecording() const override { return m_File != nullptr; }
86};
87
88class CGhostLoader : public IGhostLoader
89{
90 IOHANDLE m_File;
91 class IConsole *m_pConsole;
92 class IStorage *m_pStorage;
93
94 CGhostHeader m_Header;
95 CGhostInfo m_Info;
96
97 CGhostItem m_LastItem;
98
99 char m_aBuffer[MAX_ITEM_SIZE * NUM_ITEMS_PER_CHUNK];
100 char *m_pBufferPos;
101 int m_BufferNumItems;
102 int m_BufferCurItem;
103 int m_BufferPrevItem;
104
105 void ResetBuffer();
106 int ReadChunk(int *pType);
107
108public:
109 CGhostLoader();
110
111 void Init();
112
113 int Load(const char *pFilename, const char *pMap, SHA256_DIGEST MapSha256, unsigned MapCrc) override;
114 void Close() override;
115 const CGhostInfo *GetInfo() const override { return &m_Info; }
116
117 bool ReadNextType(int *pType) override;
118 bool ReadData(int Type, void *pData, int Size) override;
119
120 bool GetGhostInfo(const char *pFilename, CGhostInfo *pGhostInfo, const char *pMap, SHA256_DIGEST MapSha256, unsigned MapCrc) override;
121};
122#endif
123