1/* (c) Rajh, Redix and Sushi. */
2
3#ifndef GAME_CLIENT_COMPONENTS_GHOST_H
4#define GAME_CLIENT_COMPONENTS_GHOST_H
5
6#include <game/client/component.h>
7#include <game/client/components/menus.h>
8#include <game/generated/protocol.h>
9
10#include <game/client/render.h>
11
12struct CNetObj_Character;
13
14enum
15{
16 GHOSTDATA_TYPE_SKIN = 0,
17 GHOSTDATA_TYPE_CHARACTER_NO_TICK,
18 GHOSTDATA_TYPE_CHARACTER,
19 GHOSTDATA_TYPE_START_TICK
20};
21
22struct CGhostSkin
23{
24 int m_Skin0;
25 int m_Skin1;
26 int m_Skin2;
27 int m_Skin3;
28 int m_Skin4;
29 int m_Skin5;
30 int m_UseCustomColor;
31 int m_ColorBody;
32 int m_ColorFeet;
33};
34
35struct CGhostCharacter_NoTick
36{
37 int m_X;
38 int m_Y;
39 int m_VelX;
40 int m_VelY;
41 int m_Angle;
42 int m_Direction;
43 int m_Weapon;
44 int m_HookState;
45 int m_HookX;
46 int m_HookY;
47 int m_AttackTick;
48};
49
50struct CGhostCharacter : public CGhostCharacter_NoTick
51{
52 int m_Tick;
53};
54
55class CGhost : public CComponent
56{
57private:
58 enum
59 {
60 MAX_ACTIVE_GHOSTS = 256,
61 };
62
63 class CGhostPath
64 {
65 int m_ChunkSize;
66 int m_NumItems;
67
68 std::vector<CGhostCharacter *> m_vpChunks;
69
70 public:
71 CGhostPath() { Reset(); }
72 ~CGhostPath() { Reset(); }
73 CGhostPath(const CGhostPath &Other) = delete;
74 CGhostPath &operator=(const CGhostPath &Other) = delete;
75
76 CGhostPath(CGhostPath &&Other) noexcept;
77 CGhostPath &operator=(CGhostPath &&Other) noexcept;
78
79 void Reset(int ChunkSize = 25 * 60); // one minute with default snap rate
80 void SetSize(int Items);
81 int Size() const { return m_NumItems; }
82
83 void Add(const CGhostCharacter &Char);
84 CGhostCharacter *Get(int Index);
85 };
86
87 class CGhostItem
88 {
89 public:
90 CTeeRenderInfo m_RenderInfo;
91 CGhostSkin m_Skin;
92 CGhostPath m_Path;
93 int m_StartTick;
94 char m_aPlayer[MAX_NAME_LENGTH];
95 int m_PlaybackPos;
96
97 CGhostItem() { Reset(); }
98
99 bool Empty() const { return m_Path.Size() == 0; }
100 void Reset()
101 {
102 m_Path.Reset();
103 m_StartTick = -1;
104 m_PlaybackPos = -1;
105 }
106 };
107
108 static const char *ms_pGhostDir;
109
110 class IGhostLoader *m_pGhostLoader;
111 class IGhostRecorder *m_pGhostRecorder;
112
113 CGhostItem m_aActiveGhosts[MAX_ACTIVE_GHOSTS];
114 CGhostItem m_CurGhost;
115
116 char m_aTmpFilename[128];
117
118 int m_NewRenderTick;
119 int m_StartRenderTick;
120 int m_LastDeathTick;
121 int m_LastRaceTick;
122 bool m_Recording;
123 bool m_Rendering;
124
125 bool m_RenderingStartedByServer;
126
127 static void GetGhostSkin(CGhostSkin *pSkin, const char *pSkinName, int UseCustomColor, int ColorBody, int ColorFeet);
128 static void GetGhostCharacter(CGhostCharacter *pGhostChar, const CNetObj_Character *pChar, const CNetObj_DDNetCharacter *pDDnetChar);
129 static void GetNetObjCharacter(CNetObj_Character *pChar, const CGhostCharacter *pGhostChar);
130
131 void GetPath(char *pBuf, int Size, const char *pPlayerName, int Time = -1) const;
132
133 void AddInfos(const CNetObj_Character *pChar, const CNetObj_DDNetCharacter *pDDnetChar);
134 int GetSlot() const;
135
136 void CheckStart();
137 void CheckStartLocal(bool Predicted);
138 void TryRenderStart(int Tick, bool ServerControl);
139
140 void StartRecord(int Tick);
141 void StopRecord(int Time = -1);
142 void StartRender(int Tick);
143 void StopRender();
144
145 void InitRenderInfos(CGhostItem *pGhost);
146
147 static void ConGPlay(IConsole::IResult *pResult, void *pUserData);
148
149public:
150 bool m_AllowRestart;
151
152 CGhost();
153 virtual int Sizeof() const override { return sizeof(*this); }
154
155 virtual void OnRender() override;
156 virtual void OnConsoleInit() override;
157 virtual void OnReset() override;
158 virtual void OnRefreshSkins() override;
159 virtual void OnMessage(int MsgType, void *pRawMsg) override;
160 virtual void OnMapLoad() override;
161 virtual void OnShutdown() override;
162 virtual void OnNewSnapshot() override;
163
164 void OnNewPredictedSnapshot();
165
166 int FreeSlots() const;
167 int Load(const char *pFilename);
168 void Unload(int Slot);
169 void UnloadAll();
170
171 void SaveGhost(CMenus::CGhostItem *pItem);
172
173 const char *GetGhostDir() const { return ms_pGhostDir; }
174
175 class IGhostLoader *GhostLoader() const { return m_pGhostLoader; }
176 class IGhostRecorder *GhostRecorder() const { return m_pGhostRecorder; }
177
178 int GetLastRaceTick() const;
179};
180
181#endif
182