| 1 | #ifndef ENGINE_CLIENT_GHOST_H |
| 2 | #define ENGINE_CLIENT_GHOST_H |
| 3 | |
| 4 | #include <engine/ghost.h> |
| 5 | |
| 6 | #include <cstdint> |
| 7 | #include <optional> |
| 8 | |
| 9 | enum |
| 10 | { |
| 11 | MAX_ITEM_SIZE = 128, |
| 12 | NUM_ITEMS_PER_CHUNK = 50, |
| 13 | MAX_CHUNK_SIZE = MAX_ITEM_SIZE * NUM_ITEMS_PER_CHUNK, |
| 14 | }; |
| 15 | static_assert(MAX_CHUNK_SIZE % sizeof(uint32_t) == 0, "Chunk size must be aligned with uint32_t" ); |
| 16 | |
| 17 | // version 4-6 |
| 18 | struct |
| 19 | { |
| 20 | unsigned char [8]; |
| 21 | unsigned char ; |
| 22 | char [MAX_NAME_LENGTH]; |
| 23 | char [64]; |
| 24 | unsigned char [sizeof(int32_t)]; // Crc before version 6 |
| 25 | unsigned char [sizeof(int32_t)]; |
| 26 | unsigned char [sizeof(int32_t)]; |
| 27 | SHA256_DIGEST ; |
| 28 | |
| 29 | int () const; |
| 30 | int () const; |
| 31 | CGhostInfo () const; |
| 32 | }; |
| 33 | |
| 34 | class CGhostItem |
| 35 | { |
| 36 | public: |
| 37 | alignas(uint32_t) unsigned char m_aData[MAX_ITEM_SIZE]; |
| 38 | size_t m_Size; |
| 39 | int m_Type; |
| 40 | }; |
| 41 | |
| 42 | class CGhostRecorder : public IGhostRecorder |
| 43 | { |
| 44 | IOHANDLE m_File; |
| 45 | char m_aFilename[IO_MAX_PATH_LENGTH]; |
| 46 | class IStorage *m_pStorage; |
| 47 | |
| 48 | alignas(uint32_t) char m_aBuffer[MAX_CHUNK_SIZE]; |
| 49 | alignas(uint32_t) char m_aBufferTemp[MAX_CHUNK_SIZE]; |
| 50 | char *m_pBufferPos; |
| 51 | const char *m_pBufferEnd; |
| 52 | int m_BufferNumItems; |
| 53 | std::optional<CGhostItem> m_LastItem; |
| 54 | |
| 55 | void ResetBuffer(); |
| 56 | void FlushChunk(); |
| 57 | |
| 58 | public: |
| 59 | CGhostRecorder(); |
| 60 | |
| 61 | void Init(); |
| 62 | |
| 63 | int Start(const char *pFilename, const char *pMap, const SHA256_DIGEST &MapSha256, const char *pName) override; |
| 64 | void Stop(int Ticks, int Time) override; |
| 65 | |
| 66 | void WriteData(int Type, const void *pData, size_t Size) override; |
| 67 | bool IsRecording() const override { return m_File != nullptr; } |
| 68 | }; |
| 69 | |
| 70 | class CGhostLoader : public IGhostLoader |
| 71 | { |
| 72 | IOHANDLE m_File; |
| 73 | char m_aFilename[IO_MAX_PATH_LENGTH]; |
| 74 | class IStorage *m_pStorage; |
| 75 | |
| 76 | CGhostHeader ; |
| 77 | CGhostInfo m_Info; |
| 78 | |
| 79 | alignas(uint32_t) char m_aBuffer[MAX_CHUNK_SIZE]; |
| 80 | alignas(uint32_t) char m_aBufferTemp[MAX_CHUNK_SIZE]; |
| 81 | char *m_pBufferPos; |
| 82 | const char *m_pBufferEnd; |
| 83 | int m_BufferNumItems; |
| 84 | int m_BufferCurItem; |
| 85 | int m_BufferPrevItem; |
| 86 | std::optional<CGhostItem> m_LastItem; |
| 87 | |
| 88 | void ResetBuffer(); |
| 89 | IOHANDLE (CGhostHeader &, const char *pFilename, const char *pMap, const SHA256_DIGEST &MapSha256, unsigned MapCrc, bool LogMapMismatch) const; |
| 90 | bool (const CGhostHeader &, const char *pFilename) const; |
| 91 | bool (const CGhostHeader &, const char *pFilename, const char *pMap, const SHA256_DIGEST &MapSha256, unsigned MapCrc, bool LogMapMismatch) const; |
| 92 | bool ReadChunk(int *pType); |
| 93 | |
| 94 | public: |
| 95 | CGhostLoader(); |
| 96 | |
| 97 | void Init(); |
| 98 | |
| 99 | bool Load(const char *pFilename, const char *pMap, const SHA256_DIGEST &MapSha256, unsigned MapCrc) override; |
| 100 | void Close() override; |
| 101 | const CGhostInfo *GetInfo() const override { return &m_Info; } |
| 102 | |
| 103 | bool ReadNextType(int *pType) override; |
| 104 | bool ReadData(int Type, void *pData, size_t Size) override; |
| 105 | |
| 106 | bool GetGhostInfo(const char *pFilename, CGhostInfo *pGhostInfo, const char *pMap, const SHA256_DIGEST &MapSha256, unsigned MapCrc) override; |
| 107 | }; |
| 108 | #endif |
| 109 | |