1/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
2/* If you are missing that file, acquire a complete release at teeworlds.com. */
3#ifndef ENGINE_SHARED_DEMO_H
4#define ENGINE_SHARED_DEMO_H
5
6#include <base/hash.h>
7
8#include <engine/demo.h>
9#include <engine/shared/protocol.h>
10
11#include <functional>
12#include <vector>
13
14#include "snapshot.h"
15
16typedef std::function<void()> TUpdateIntraTimesFunc;
17
18class CDemoRecorder : public IDemoRecorder
19{
20 class IConsole *m_pConsole;
21 class IStorage *m_pStorage;
22
23 IOHANDLE m_File;
24 char m_aCurrentFilename[IO_MAX_PATH_LENGTH];
25 int m_LastTickMarker;
26 int m_LastKeyFrame;
27 int m_FirstTick;
28
29 unsigned char m_aLastSnapshotData[CSnapshot::MAX_SIZE];
30 class CSnapshotDelta *m_pSnapshotDelta;
31
32 int m_NumTimelineMarkers;
33 int m_aTimelineMarkers[MAX_TIMELINE_MARKERS];
34
35 bool m_NoMapData;
36
37 DEMOFUNC_FILTER m_pfnFilter;
38 void *m_pUser;
39
40 void WriteTickMarker(int Tick, bool Keyframe);
41 void Write(int Type, const void *pData, int Size);
42
43public:
44 CDemoRecorder(class CSnapshotDelta *pSnapshotDelta, bool NoMapData = false);
45 CDemoRecorder() {}
46 ~CDemoRecorder() override;
47
48 int Start(class IStorage *pStorage, class IConsole *pConsole, const char *pFilename, const char *pNetversion, const char *pMap, const SHA256_DIGEST &Sha256, unsigned MapCrc, const char *pType, unsigned MapSize, unsigned char *pMapData, IOHANDLE MapFile = nullptr, DEMOFUNC_FILTER pfnFilter = nullptr, void *pUser = nullptr);
49 int Stop(IDemoRecorder::EStopMode Mode, const char *pTargetFilename = "") override;
50
51 void AddDemoMarker();
52 void AddDemoMarker(int Tick);
53
54 void RecordSnapshot(int Tick, const void *pData, int Size);
55 void RecordMessage(const void *pData, int Size);
56
57 bool IsRecording() const override { return m_File != nullptr; }
58 const char *CurrentFilename() const override { return m_aCurrentFilename; }
59
60 int Length() const override { return (m_LastTickMarker - m_FirstTick) / SERVER_TICK_SPEED; }
61};
62
63class CDemoPlayer : public IDemoPlayer
64{
65public:
66 class IListener
67 {
68 public:
69 virtual ~IListener() {}
70 virtual void OnDemoPlayerSnapshot(void *pData, int Size) = 0;
71 virtual void OnDemoPlayerMessage(void *pData, int Size) = 0;
72 };
73
74 struct CPlaybackInfo
75 {
76 CDemoHeader m_Header;
77 CTimelineMarkers m_TimelineMarkers;
78
79 IDemoPlayer::CInfo m_Info;
80
81 int64_t m_LastUpdate;
82 int64_t m_CurrentTime;
83
84 int m_NextTick;
85 int m_PreviousTick;
86
87 float m_IntraTick;
88 float m_IntraTickSincePrev;
89 float m_TickTime;
90 };
91
92private:
93 IListener *m_pListener;
94
95 TUpdateIntraTimesFunc m_UpdateIntraTimesFunc;
96
97 // Playback
98 struct SKeyFrame
99 {
100 long m_Filepos;
101 int m_Tick;
102
103 SKeyFrame(long Filepos, int Tick) :
104 m_Filepos(Filepos), m_Tick(Tick)
105 {
106 }
107 };
108
109 class IConsole *m_pConsole;
110 IOHANDLE m_File;
111 long m_MapOffset;
112 char m_aFilename[IO_MAX_PATH_LENGTH];
113 char m_aErrorMessage[256];
114 std::vector<SKeyFrame> m_vKeyFrames;
115 CMapInfo m_MapInfo;
116 int m_SpeedIndex;
117
118 CPlaybackInfo m_Info;
119 unsigned char m_aCompressedSnapshotData[CSnapshot::MAX_SIZE];
120 unsigned char m_aDecompressedSnapshotData[CSnapshot::MAX_SIZE];
121
122 // Depending on the chunk header
123 // this is either a full CSnapshot or a CSnapshotDelta.
124 unsigned char m_aChunkData[CSnapshot::MAX_SIZE];
125 // Storage for the full snapshot
126 // where the delta gets unpacked into.
127 unsigned char m_aSnapshot[CSnapshot::MAX_SIZE];
128 unsigned char m_aLastSnapshotData[CSnapshot::MAX_SIZE];
129 int m_LastSnapshotDataSize;
130 class CSnapshotDelta *m_pSnapshotDelta;
131
132 bool m_UseVideo;
133#if defined(CONF_VIDEORECORDER)
134 bool m_WasRecording = false;
135#endif
136
137 enum EReadChunkHeaderResult
138 {
139 CHUNKHEADER_SUCCESS,
140 CHUNKHEADER_ERROR,
141 CHUNKHEADER_EOF,
142 };
143 EReadChunkHeaderResult ReadChunkHeader(int *pType, int *pSize, int *pTick);
144 void DoTick();
145 bool ScanFile();
146
147 int64_t Time();
148
149public:
150 CDemoPlayer(class CSnapshotDelta *pSnapshotDelta, bool UseVideo);
151 CDemoPlayer(class CSnapshotDelta *pSnapshotDelta, bool UseVideo, TUpdateIntraTimesFunc &&UpdateIntraTimesFunc);
152 ~CDemoPlayer() override;
153
154 void Construct(class CSnapshotDelta *pSnapshotDelta, bool UseVideo);
155
156 void SetListener(IListener *pListener);
157
158 int Load(class IStorage *pStorage, class IConsole *pConsole, const char *pFilename, int StorageType);
159 unsigned char *GetMapData(class IStorage *pStorage);
160 bool ExtractMap(class IStorage *pStorage);
161 int Play();
162 void Pause() override;
163 void Unpause() override;
164 void Stop(const char *pErrorMessage = "");
165 void SetSpeed(float Speed) override;
166 void SetSpeedIndex(int SpeedIndex) override;
167 void AdjustSpeedIndex(int Offset) override;
168 int SeekPercent(float Percent) override;
169 int SeekTime(float Seconds) override;
170 int SeekTick(ETickOffset TickOffset) override;
171 int SetPos(int WantedTick) override;
172 const CInfo *BaseInfo() const override { return &m_Info.m_Info; }
173 void GetDemoName(char *pBuffer, size_t BufferSize) const override;
174 bool GetDemoInfo(class IStorage *pStorage, class IConsole *pConsole, const char *pFilename, int StorageType, CDemoHeader *pDemoHeader, CTimelineMarkers *pTimelineMarkers, CMapInfo *pMapInfo, IOHANDLE *pFile = nullptr, char *pErrorMessage = nullptr, size_t ErrorMessageSize = 0) const override;
175 const char *Filename() const { return m_aFilename; }
176 const char *ErrorMessage() const override { return m_aErrorMessage; }
177
178 int Update(bool RealTime = true);
179
180 const CPlaybackInfo *Info() const { return &m_Info; }
181 bool IsPlaying() const override { return m_File != nullptr; }
182 const CMapInfo *GetMapInfo() const { return &m_MapInfo; }
183};
184
185class CDemoEditor : public IDemoEditor
186{
187 IConsole *m_pConsole;
188 IStorage *m_pStorage;
189 class CSnapshotDelta *m_pSnapshotDelta;
190 const char *m_pNetVersion;
191
192public:
193 virtual void Init(const char *pNetVersion, class CSnapshotDelta *pSnapshotDelta, class IConsole *pConsole, class IStorage *pStorage);
194 bool Slice(const char *pDemo, const char *pDst, int StartTick, int EndTick, DEMOFUNC_FILTER pfnFilter, void *pUser) override;
195};
196
197#endif
198