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 | |
12 | struct CNetObj_Character; |
13 | |
14 | enum |
15 | { |
16 | GHOSTDATA_TYPE_SKIN = 0, |
17 | GHOSTDATA_TYPE_CHARACTER_NO_TICK, |
18 | GHOSTDATA_TYPE_CHARACTER, |
19 | GHOSTDATA_TYPE_START_TICK |
20 | }; |
21 | |
22 | struct 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 | |
35 | struct 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 | |
50 | struct CGhostCharacter : public CGhostCharacter_NoTick |
51 | { |
52 | int m_Tick; |
53 | }; |
54 | |
55 | class CGhost : public CComponent |
56 | { |
57 | private: |
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 | |
149 | public: |
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 (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 | |