1+ /* ******************************************************************
2+ * @file utils.cpp
3+ * @brief Util functions.
4+ * @author Orsell, Nanoman2525, Nullderef
5+ * @date 06 2025
6+ *********************************************************************/
7+
8+ #include " stdafx.hpp"
9+ #include " modules/utils.h"
10+
11+ #include " utils/loggingsystem.hpp"
12+
13+ #include " modules/cbaseentity.h"
14+
15+ #include " globals.hpp"
16+
17+ struct edict_t ;
18+
19+ /* *
20+ * @brief Get the player's entity index by their user ID.
21+ * @param userid User ID of player.
22+ * @return Player entity index.
23+ */
24+ int Utils::UserIDToPlayerIndex (const int userid)
25+ {
26+ for (int i = 1 ; i <= MAX_PLAYERS; i++)
27+ {
28+ const edict_t * pEdict = nullptr ;
29+ if (i >= 0 && i < g_pGlobals->maxEntities )
30+ pEdict = (g_pGlobals->pEdicts + i);
31+
32+ if (engineServer->GetPlayerUserId (pEdict) == userid)
33+ return i;
34+ }
35+ return 0 ; // Return 0 if the index can't be found
36+ }
37+
38+ /* *
39+ * @brief Get player username by their entity index.
40+ * @param playerIndex Player index.
41+ * @return Player's username.
42+ */
43+ const char * Utils::GetPlayerName (const int playerIndex)
44+ {
45+ if (playerIndex <= 0 || playerIndex > MAX_PLAYERS)
46+ {
47+ Log (WARNING, true , " Invalid index passed to GetPlayerName: %i! Returning " " !" , playerIndex);
48+ return " " ;
49+ }
50+
51+ player_info_t playerInfo;
52+ if (!engineServer->GetPlayerInfo (playerIndex, &playerInfo))
53+ {
54+ Log (WARNING, true , R"( Couldn't retrieve playerInfo of player index in GetPlayerName: %i! Returning ""!)" , playerIndex);
55+ return " " ;
56+ }
57+
58+ return playerInfo.name ;
59+ }
60+
61+ /* *
62+ * @brief Get the account ID component of player SteamID by the player's entity index.
63+ * @param playerIndex Player index.
64+ * @return Steam Account ID of player.
65+ */
66+ int Utils::GetSteamID (const int playerIndex)
67+ {
68+ edict_t * pEdict = nullptr ;
69+ if (playerIndex >= 0 && playerIndex < MAX_PLAYERS)
70+ pEdict = (g_pGlobals->pEdicts + playerIndex);
71+
72+ if (!pEdict)
73+ return -1 ;
74+
75+ player_info_t playerInfo;
76+ if (!engineServer->GetPlayerInfo (playerIndex, &playerInfo))
77+ return -1 ;
78+
79+ const CSteamID* pSteamID = engineServer->GetClientSteamID (pEdict);
80+ if (!pSteamID || pSteamID->GetAccountID () == 0 )
81+ return -1 ;
82+
83+ return static_cast <int >(pSteamID->GetAccountID ());
84+ }
85+
86+ /* *
87+ * @brief Get the integer value of a ConVar.
88+ * @param cvName Name of ConVar to get.
89+ * @return Integer value of ConVar.
90+ */
91+ int Utils::GetConVarInt (const char * cvName)
92+ {
93+ const ConVar* pVar = g_pCVar->FindVar (cvName);
94+ if (!pVar)
95+ {
96+ Log (WARNING, false , R"( Could not find ConVar: "%s"! Returning ""!)" , cvName);
97+ return -1 ;
98+ }
99+
100+ return pVar->GetInt ();
101+ }
102+
103+ /* *
104+ * @brief Get the string value of a ConVar.
105+ * @param cvName Name of ConVar to get.
106+ * @return String value of ConVar.
107+ */
108+ const char * Utils::GetConVarString (const char * cvName)
109+ {
110+ const ConVar* pVar = g_pCVar->FindVar (cvName);
111+ if (!pVar)
112+ {
113+ Log (WARNING, false , R"( Could not find ConVar: "%s"! Returning ""!)" , cvName);
114+ return " " ;
115+ }
116+
117+ return pVar->GetString ();
118+ }
119+
120+ /* *
121+ * @brief Set integer value of a ConVar.
122+ * @param cvName Name of ConVar to set value of.
123+ * @param newValue New value for ConVar.
124+ */
125+ void Utils::SetConVarInt (const char * cvName, const int newValue)
126+ {
127+ ConVar* pVar = g_pCVar->FindVar (cvName);
128+ if (!pVar)
129+ {
130+ Log (WARNING, false , " Could not set ConVar: \" %s\" !" , cvName);
131+ return ;
132+ }
133+ pVar->SetValue (newValue);
134+ }
135+
136+ /* *
137+ * @brief Set string value of a ConVar.
138+ * @param cvName Name of ConVar to set value of.
139+ * @param newValue New value for ConVar.
140+ */
141+ void Utils::SetConVarString (const char * cvName, const char * newValue)
142+ {
143+ ConVar* pVar = g_pCVar->FindVar (cvName);
144+ if (!pVar)
145+ {
146+ Log (WARNING, false , R"( Could not set ConVar: "%s"!)" , cvName);
147+ return ;
148+ }
149+ pVar->SetValue (newValue);
150+ return ;
151+ }
152+
153+ /* *
154+ * @brief Check if player is a bot.
155+ * @param playerIndex Player index.
156+ * @return Returns true if player is a bot.
157+ */
158+ bool Utils::IsBot (const int playerIndex)
159+ {
160+ player_info_t playerInfo;
161+ if (!engineServer->GetPlayerInfo (playerIndex, &playerInfo))
162+ {
163+ Log (WARNING, true , R"( Couldn't retrieve player info of player index "%i" in IsBot!)" , playerIndex);
164+ return false ;
165+ }
166+
167+ return playerInfo.fakeplayer ;
168+ }
169+
170+ /* *
171+ * @brief Get the number of bots in the server.
172+ * @return Number of bots in the server.
173+ */
174+ int Utils::GetBotCount ()
175+ {
176+ int botCount = 0 ;
177+ FOR_ALL_PLAYERS (i)
178+ {
179+ if (IsBot (i))
180+ botCount++;
181+ }
182+ return botCount;
183+ }
184+
185+ /* *
186+ * @brief Get the current player count on the server.
187+ * @return Number of players in the server.
188+ */
189+ int Utils::CurPlayerCount ()
190+ {
191+ int playerCount = 0 ;
192+ for (int i = 1 ; i <= MAX_PLAYERS; i++)
193+ {
194+ if (Utils::PlayerByIndex (i))
195+ playerCount++;
196+ }
197+ return playerCount;
198+ }
199+
200+ /* *
201+ * @brief Entity index to VScript script handle.
202+ * @param entityIndex Entity index.
203+ * @return VScript script handle.
204+ */
205+ HSCRIPT Utils::EntIndexScriptHandle (const int entityIndex)
206+ {
207+ edict_t * pEdict = IndexToEdict (entityIndex);
208+ if (!pEdict->GetUnknown ())
209+ return nullptr ;
210+
211+ CBaseEntity* pBaseEntity = pEdict->GetUnknown ()->GetBaseEntity ();
212+ if (!pBaseEntity)
213+ return nullptr ;
214+
215+ return CBaseEntity::GetScriptInstance (pBaseEntity);
216+ }
217+
218+ /* *
219+ * @brief Get the player's CBasePlayer class by entity index.
220+ * @param playerEntityIndex Player entity index.
221+ * @return Pointer to player's CBasePlayer class.
222+ */
223+ CBasePlayer* Utils::PlayerByIndex (const int playerEntityIndex)
224+ {
225+ static auto playerByIndex = reinterpret_cast <CBasePlayer* (__cdecl*)(int )>(Memory::Scan<void *>(SERVER, " 55 8B EC 8B 4D 08 33 C0 85 C9 7E 30" ));
226+ return playerByIndex (playerEntityIndex);
227+ }
228+
229+ /* *
230+ * @brief Send or print various kinds of styles of messages to players. msg_dest are defined macros in globals.hpp.
231+ * @param player Player's CBasePlayer class.
232+ * @param msgDest Where message will be sent.
233+ * @param msg Message to send.
234+ * @attention The param# parameters are for formatting. Only four max due to hour the message is programmed to be networked.
235+ * @param param1 Formatting. Defaults to nullptr.
236+ * @param param2 Formatting. Defaults to nullptr.
237+ * @param param3 Formatting. Defaults to nullptr.
238+ * @param param4 Formatting. Defaults to nullptr.
239+ */
240+ void Utils::ClientPrint (CBasePlayer* player, const int msgDest, const char * msg, const char * param1, const char * param2, const char * param3, const char * param4)
241+ {
242+ static auto clientPrint = reinterpret_cast <void (__cdecl*)(CBasePlayer*, int , const char *, const char *, const char *, const char *, const char *)>(Memory::Scan<void *>(SERVER, " 55 8B EC 83 EC 20 56 8B 75 08 85 F6 74 4C" ));
243+ clientPrint (player, msgDest, msg, param1, param2, param3, param4);
244+ }
245+
246+ /* *
247+ * @brief Show text on screen just like game_text does.
248+ * @param pPlayer Pointer to player.
249+ * @param textParms HudMessageParams struct passed with the settings for the displayed hud message.
250+ * If not supplied, defaults to default game_text entity parameters.
251+ * @param pMessage Message to display.
252+ */
253+ void Utils::HudMessage (CBasePlayer* pPlayer, const char * pMessage, const HudMessageParams& textParms)
254+ {
255+ static auto hudMessage = reinterpret_cast <void (__cdecl*)(CBasePlayer*, const HudMessageParams&, const char *)>(Memory::Scan (SERVER, " 55 8B EC 83 EC 20 8D 4D ? E8 ? ? ? ? 8B 45 ? 8D 4D ? 85 C0 74 ? 50 E8 ? ? ? ? EB ? E8 ? ? ? ? 56" ));
256+ hudMessage (pPlayer, textParms, pMessage);
257+ }
258+
259+ /* *
260+ * @brief Get the CBasePlayer of the player who executed the ConVar or ConCommand.
261+ * Must be executed inside a ConCommand/ConVar function context.
262+ * @return Pointer to player's CBasePlayer class.
263+ */
264+ CBasePlayer* Utils::GetCommandClient ()
265+ {
266+ static auto getCommandClient = reinterpret_cast <CBasePlayer* (__cdecl*)()>(Memory::Scan (SERVER, " A1 ? ? ? ? 40 85 C0" ));
267+ return getCommandClient ();
268+ }
269+
270+ /* *
271+ * @brief Get the client index of the player who executed the ConVar or ConCommand.
272+ * @warning This is not the player's entity index! Entity index is +1 bigger.
273+ * @return Player's client index.
274+ */
275+ int Utils::GetCommandClientIndex ()
276+ {
277+ static auto getCommandClientIndex = reinterpret_cast <int (__cdecl*)()>(Memory::Scan (SERVER, " A1 ? ? ? ? 40 C3" ));
278+ return getCommandClientIndex ();
279+ }
280+
281+ /* *
282+ * @brief Change a entities origin in the world.
283+ * @param entity Entity to set the new origin of.
284+ * @param vecOrigin New origin of entity.
285+ * @param fireTriggers Have the moved entity trigger triggers.
286+ */
287+ void Utils::SetOrigin (CBaseEntity* entity, const Vector& vecOrigin, const bool fireTriggers)
288+ {
289+ static auto setOrigin = reinterpret_cast <void (__cdecl*)(CBaseEntity*, const Vector&, bool )>(Memory::Scan (SERVER, " 55 8B EC 8B 45 0C 56 8B 75 08 50 8B" ));
290+ setOrigin (entity, vecOrigin, fireTriggers);
291+ }
0 commit comments