1 | /* (c) Shereef Marzouk. See "licence DDRace.txt" and the readme.txt in the root of the distribution for more information. */ |
2 | #include "gamecontext.h" |
3 | |
4 | #include <engine/antibot.h> |
5 | |
6 | #include <engine/shared/config.h> |
7 | #include <game/server/entities/character.h> |
8 | #include <game/server/gamemodes/DDRace.h> |
9 | #include <game/server/player.h> |
10 | #include <game/server/save.h> |
11 | #include <game/server/teams.h> |
12 | |
13 | bool CheckClientId(int ClientId); |
14 | |
15 | void CGameContext::ConGoLeft(IConsole::IResult *pResult, void *pUserData) |
16 | { |
17 | CGameContext *pSelf = (CGameContext *)pUserData; |
18 | int Tiles = pResult->NumArguments() == 1 ? pResult->GetInteger(Index: 0) : 1; |
19 | |
20 | if(!CheckClientId(ClientId: pResult->m_ClientId)) |
21 | return; |
22 | pSelf->MoveCharacter(ClientId: pResult->m_ClientId, X: -1 * Tiles, Y: 0); |
23 | } |
24 | |
25 | void CGameContext::ConGoRight(IConsole::IResult *pResult, void *pUserData) |
26 | { |
27 | CGameContext *pSelf = (CGameContext *)pUserData; |
28 | int Tiles = pResult->NumArguments() == 1 ? pResult->GetInteger(Index: 0) : 1; |
29 | |
30 | if(!CheckClientId(ClientId: pResult->m_ClientId)) |
31 | return; |
32 | pSelf->MoveCharacter(ClientId: pResult->m_ClientId, X: Tiles, Y: 0); |
33 | } |
34 | |
35 | void CGameContext::ConGoDown(IConsole::IResult *pResult, void *pUserData) |
36 | { |
37 | CGameContext *pSelf = (CGameContext *)pUserData; |
38 | int Tiles = pResult->NumArguments() == 1 ? pResult->GetInteger(Index: 0) : 1; |
39 | |
40 | if(!CheckClientId(ClientId: pResult->m_ClientId)) |
41 | return; |
42 | pSelf->MoveCharacter(ClientId: pResult->m_ClientId, X: 0, Y: Tiles); |
43 | } |
44 | |
45 | void CGameContext::ConGoUp(IConsole::IResult *pResult, void *pUserData) |
46 | { |
47 | CGameContext *pSelf = (CGameContext *)pUserData; |
48 | int Tiles = pResult->NumArguments() == 1 ? pResult->GetInteger(Index: 0) : 1; |
49 | |
50 | if(!CheckClientId(ClientId: pResult->m_ClientId)) |
51 | return; |
52 | pSelf->MoveCharacter(ClientId: pResult->m_ClientId, X: 0, Y: -1 * Tiles); |
53 | } |
54 | |
55 | void CGameContext::ConMove(IConsole::IResult *pResult, void *pUserData) |
56 | { |
57 | CGameContext *pSelf = (CGameContext *)pUserData; |
58 | if(!CheckClientId(ClientId: pResult->m_ClientId)) |
59 | return; |
60 | pSelf->MoveCharacter(ClientId: pResult->m_ClientId, X: pResult->GetInteger(Index: 0), |
61 | Y: pResult->GetInteger(Index: 1)); |
62 | } |
63 | |
64 | void CGameContext::ConMoveRaw(IConsole::IResult *pResult, void *pUserData) |
65 | { |
66 | CGameContext *pSelf = (CGameContext *)pUserData; |
67 | if(!CheckClientId(ClientId: pResult->m_ClientId)) |
68 | return; |
69 | pSelf->MoveCharacter(ClientId: pResult->m_ClientId, X: pResult->GetInteger(Index: 0), |
70 | Y: pResult->GetInteger(Index: 1), Raw: true); |
71 | } |
72 | |
73 | void CGameContext::MoveCharacter(int ClientId, int X, int Y, bool Raw) |
74 | { |
75 | CCharacter *pChr = GetPlayerChar(ClientId); |
76 | |
77 | if(!pChr) |
78 | return; |
79 | |
80 | pChr->Move(RelPos: vec2((Raw ? 1 : 32) * X, (Raw ? 1 : 32) * Y)); |
81 | pChr->m_DDRaceState = DDRACE_CHEAT; |
82 | } |
83 | |
84 | void CGameContext::ConKillPlayer(IConsole::IResult *pResult, void *pUserData) |
85 | { |
86 | CGameContext *pSelf = (CGameContext *)pUserData; |
87 | if(!CheckClientId(ClientId: pResult->m_ClientId)) |
88 | return; |
89 | int Victim = pResult->GetVictim(); |
90 | |
91 | if(pSelf->m_apPlayers[Victim]) |
92 | { |
93 | pSelf->m_apPlayers[Victim]->KillCharacter(Weapon: WEAPON_GAME); |
94 | char aBuf[512]; |
95 | str_format(buffer: aBuf, buffer_size: sizeof(aBuf), format: "%s was killed by %s" , |
96 | pSelf->Server()->ClientName(ClientId: Victim), |
97 | pSelf->Server()->ClientName(ClientId: pResult->m_ClientId)); |
98 | pSelf->SendChat(ClientId: -1, Team: TEAM_ALL, pText: aBuf); |
99 | } |
100 | } |
101 | |
102 | void CGameContext::ConNinja(IConsole::IResult *pResult, void *pUserData) |
103 | { |
104 | CGameContext *pSelf = (CGameContext *)pUserData; |
105 | pSelf->ModifyWeapons(pResult, pUserData, Weapon: WEAPON_NINJA, Remove: false); |
106 | } |
107 | |
108 | void CGameContext::ConUnNinja(IConsole::IResult *pResult, void *pUserData) |
109 | { |
110 | CGameContext *pSelf = (CGameContext *)pUserData; |
111 | pSelf->ModifyWeapons(pResult, pUserData, Weapon: WEAPON_NINJA, Remove: true); |
112 | } |
113 | |
114 | void CGameContext::ConEndlessHook(IConsole::IResult *pResult, void *pUserData) |
115 | { |
116 | CGameContext *pSelf = (CGameContext *)pUserData; |
117 | if(!CheckClientId(ClientId: pResult->m_ClientId)) |
118 | return; |
119 | CCharacter *pChr = pSelf->GetPlayerChar(ClientId: pResult->m_ClientId); |
120 | if(pChr) |
121 | { |
122 | pChr->SetEndlessHook(true); |
123 | } |
124 | } |
125 | |
126 | void CGameContext::ConUnEndlessHook(IConsole::IResult *pResult, void *pUserData) |
127 | { |
128 | CGameContext *pSelf = (CGameContext *)pUserData; |
129 | if(!CheckClientId(ClientId: pResult->m_ClientId)) |
130 | return; |
131 | CCharacter *pChr = pSelf->GetPlayerChar(ClientId: pResult->m_ClientId); |
132 | if(pChr) |
133 | { |
134 | pChr->SetEndlessHook(false); |
135 | } |
136 | } |
137 | |
138 | void CGameContext::ConSuper(IConsole::IResult *pResult, void *pUserData) |
139 | { |
140 | CGameContext *pSelf = (CGameContext *)pUserData; |
141 | if(!CheckClientId(ClientId: pResult->m_ClientId)) |
142 | return; |
143 | CCharacter *pChr = pSelf->GetPlayerChar(ClientId: pResult->m_ClientId); |
144 | if(pChr && !pChr->IsSuper()) |
145 | { |
146 | pChr->SetSuper(true); |
147 | pChr->UnFreeze(); |
148 | } |
149 | } |
150 | |
151 | void CGameContext::ConUnSuper(IConsole::IResult *pResult, void *pUserData) |
152 | { |
153 | CGameContext *pSelf = (CGameContext *)pUserData; |
154 | if(!CheckClientId(ClientId: pResult->m_ClientId)) |
155 | return; |
156 | CCharacter *pChr = pSelf->GetPlayerChar(ClientId: pResult->m_ClientId); |
157 | if(pChr && pChr->IsSuper()) |
158 | { |
159 | pChr->SetSuper(false); |
160 | } |
161 | } |
162 | |
163 | void CGameContext::ConSolo(IConsole::IResult *pResult, void *pUserData) |
164 | { |
165 | CGameContext *pSelf = (CGameContext *)pUserData; |
166 | if(!CheckClientId(ClientId: pResult->m_ClientId)) |
167 | return; |
168 | CCharacter *pChr = pSelf->GetPlayerChar(ClientId: pResult->m_ClientId); |
169 | if(pChr) |
170 | pChr->SetSolo(true); |
171 | } |
172 | |
173 | void CGameContext::ConUnSolo(IConsole::IResult *pResult, void *pUserData) |
174 | { |
175 | CGameContext *pSelf = (CGameContext *)pUserData; |
176 | if(!CheckClientId(ClientId: pResult->m_ClientId)) |
177 | return; |
178 | CCharacter *pChr = pSelf->GetPlayerChar(ClientId: pResult->m_ClientId); |
179 | if(pChr) |
180 | pChr->SetSolo(false); |
181 | } |
182 | |
183 | void CGameContext::ConFreeze(IConsole::IResult *pResult, void *pUserData) |
184 | { |
185 | CGameContext *pSelf = (CGameContext *)pUserData; |
186 | if(!CheckClientId(ClientId: pResult->m_ClientId)) |
187 | return; |
188 | CCharacter *pChr = pSelf->GetPlayerChar(ClientId: pResult->m_ClientId); |
189 | if(pChr) |
190 | pChr->Freeze(); |
191 | } |
192 | |
193 | void CGameContext::ConUnFreeze(IConsole::IResult *pResult, void *pUserData) |
194 | { |
195 | CGameContext *pSelf = (CGameContext *)pUserData; |
196 | if(!CheckClientId(ClientId: pResult->m_ClientId)) |
197 | return; |
198 | CCharacter *pChr = pSelf->GetPlayerChar(ClientId: pResult->m_ClientId); |
199 | if(pChr) |
200 | pChr->UnFreeze(); |
201 | } |
202 | |
203 | void CGameContext::ConDeep(IConsole::IResult *pResult, void *pUserData) |
204 | { |
205 | CGameContext *pSelf = (CGameContext *)pUserData; |
206 | if(!CheckClientId(ClientId: pResult->m_ClientId)) |
207 | return; |
208 | CCharacter *pChr = pSelf->GetPlayerChar(ClientId: pResult->m_ClientId); |
209 | if(pChr) |
210 | pChr->SetDeepFrozen(true); |
211 | } |
212 | |
213 | void CGameContext::ConUnDeep(IConsole::IResult *pResult, void *pUserData) |
214 | { |
215 | CGameContext *pSelf = (CGameContext *)pUserData; |
216 | if(!CheckClientId(ClientId: pResult->m_ClientId)) |
217 | return; |
218 | CCharacter *pChr = pSelf->GetPlayerChar(ClientId: pResult->m_ClientId); |
219 | if(pChr) |
220 | { |
221 | pChr->SetDeepFrozen(false); |
222 | pChr->UnFreeze(); |
223 | } |
224 | } |
225 | |
226 | void CGameContext::ConLiveFreeze(IConsole::IResult *pResult, void *pUserData) |
227 | { |
228 | CGameContext *pSelf = (CGameContext *)pUserData; |
229 | if(!CheckClientId(ClientId: pResult->m_ClientId)) |
230 | return; |
231 | CCharacter *pChr = pSelf->GetPlayerChar(ClientId: pResult->m_ClientId); |
232 | if(pChr) |
233 | pChr->SetLiveFrozen(true); |
234 | } |
235 | |
236 | void CGameContext::ConUnLiveFreeze(IConsole::IResult *pResult, void *pUserData) |
237 | { |
238 | CGameContext *pSelf = (CGameContext *)pUserData; |
239 | if(!CheckClientId(ClientId: pResult->m_ClientId)) |
240 | return; |
241 | CCharacter *pChr = pSelf->GetPlayerChar(ClientId: pResult->m_ClientId); |
242 | if(pChr) |
243 | pChr->SetLiveFrozen(false); |
244 | } |
245 | |
246 | void CGameContext::ConShotgun(IConsole::IResult *pResult, void *pUserData) |
247 | { |
248 | CGameContext *pSelf = (CGameContext *)pUserData; |
249 | pSelf->ModifyWeapons(pResult, pUserData, Weapon: WEAPON_SHOTGUN, Remove: false); |
250 | } |
251 | |
252 | void CGameContext::ConGrenade(IConsole::IResult *pResult, void *pUserData) |
253 | { |
254 | CGameContext *pSelf = (CGameContext *)pUserData; |
255 | pSelf->ModifyWeapons(pResult, pUserData, Weapon: WEAPON_GRENADE, Remove: false); |
256 | } |
257 | |
258 | void CGameContext::ConLaser(IConsole::IResult *pResult, void *pUserData) |
259 | { |
260 | CGameContext *pSelf = (CGameContext *)pUserData; |
261 | pSelf->ModifyWeapons(pResult, pUserData, Weapon: WEAPON_LASER, Remove: false); |
262 | } |
263 | |
264 | void CGameContext::ConJetpack(IConsole::IResult *pResult, void *pUserData) |
265 | { |
266 | CGameContext *pSelf = (CGameContext *)pUserData; |
267 | CCharacter *pChr = pSelf->GetPlayerChar(ClientId: pResult->m_ClientId); |
268 | if(pChr) |
269 | pChr->SetJetpack(true); |
270 | } |
271 | |
272 | void CGameContext::ConWeapons(IConsole::IResult *pResult, void *pUserData) |
273 | { |
274 | CGameContext *pSelf = (CGameContext *)pUserData; |
275 | pSelf->ModifyWeapons(pResult, pUserData, Weapon: -1, Remove: false); |
276 | } |
277 | |
278 | void CGameContext::ConUnShotgun(IConsole::IResult *pResult, void *pUserData) |
279 | { |
280 | CGameContext *pSelf = (CGameContext *)pUserData; |
281 | pSelf->ModifyWeapons(pResult, pUserData, Weapon: WEAPON_SHOTGUN, Remove: true); |
282 | } |
283 | |
284 | void CGameContext::ConUnGrenade(IConsole::IResult *pResult, void *pUserData) |
285 | { |
286 | CGameContext *pSelf = (CGameContext *)pUserData; |
287 | pSelf->ModifyWeapons(pResult, pUserData, Weapon: WEAPON_GRENADE, Remove: true); |
288 | } |
289 | |
290 | void CGameContext::ConUnLaser(IConsole::IResult *pResult, void *pUserData) |
291 | { |
292 | CGameContext *pSelf = (CGameContext *)pUserData; |
293 | pSelf->ModifyWeapons(pResult, pUserData, Weapon: WEAPON_LASER, Remove: true); |
294 | } |
295 | |
296 | void CGameContext::ConUnJetpack(IConsole::IResult *pResult, void *pUserData) |
297 | { |
298 | CGameContext *pSelf = (CGameContext *)pUserData; |
299 | CCharacter *pChr = pSelf->GetPlayerChar(ClientId: pResult->m_ClientId); |
300 | if(pChr) |
301 | pChr->SetJetpack(false); |
302 | } |
303 | |
304 | void CGameContext::ConUnWeapons(IConsole::IResult *pResult, void *pUserData) |
305 | { |
306 | CGameContext *pSelf = (CGameContext *)pUserData; |
307 | pSelf->ModifyWeapons(pResult, pUserData, Weapon: -1, Remove: true); |
308 | } |
309 | |
310 | void CGameContext::ConAddWeapon(IConsole::IResult *pResult, void *pUserData) |
311 | { |
312 | CGameContext *pSelf = (CGameContext *)pUserData; |
313 | pSelf->ModifyWeapons(pResult, pUserData, Weapon: pResult->GetInteger(Index: 0), Remove: false); |
314 | } |
315 | |
316 | void CGameContext::ConRemoveWeapon(IConsole::IResult *pResult, void *pUserData) |
317 | { |
318 | CGameContext *pSelf = (CGameContext *)pUserData; |
319 | pSelf->ModifyWeapons(pResult, pUserData, Weapon: pResult->GetInteger(Index: 0), Remove: true); |
320 | } |
321 | |
322 | void CGameContext::ModifyWeapons(IConsole::IResult *pResult, void *pUserData, |
323 | int Weapon, bool Remove) |
324 | { |
325 | CGameContext *pSelf = (CGameContext *)pUserData; |
326 | CCharacter *pChr = GetPlayerChar(ClientId: pResult->m_ClientId); |
327 | if(!pChr) |
328 | return; |
329 | |
330 | if(clamp(val: Weapon, lo: -1, hi: NUM_WEAPONS - 1) != Weapon) |
331 | { |
332 | pSelf->Console()->Print(Level: IConsole::OUTPUT_LEVEL_STANDARD, pFrom: "info" , |
333 | pStr: "invalid weapon id" ); |
334 | return; |
335 | } |
336 | |
337 | if(Weapon == -1) |
338 | { |
339 | pChr->GiveWeapon(Weapon: WEAPON_SHOTGUN, Remove); |
340 | pChr->GiveWeapon(Weapon: WEAPON_GRENADE, Remove); |
341 | pChr->GiveWeapon(Weapon: WEAPON_LASER, Remove); |
342 | } |
343 | else |
344 | { |
345 | pChr->GiveWeapon(Weapon, Remove); |
346 | } |
347 | |
348 | pChr->m_DDRaceState = DDRACE_CHEAT; |
349 | } |
350 | |
351 | void CGameContext::Teleport(CCharacter *pChr, vec2 Pos) |
352 | { |
353 | pChr->SetPosition(Pos); |
354 | pChr->m_Pos = Pos; |
355 | pChr->m_PrevPos = Pos; |
356 | pChr->m_DDRaceState = DDRACE_CHEAT; |
357 | } |
358 | |
359 | void CGameContext::ConToTeleporter(IConsole::IResult *pResult, void *pUserData) |
360 | { |
361 | CGameContext *pSelf = (CGameContext *)pUserData; |
362 | unsigned int TeleTo = pResult->GetInteger(Index: 0); |
363 | |
364 | if(!pSelf->Collision()->TeleOuts(Number: TeleTo - 1).empty()) |
365 | { |
366 | CCharacter *pChr = pSelf->GetPlayerChar(ClientId: pResult->m_ClientId); |
367 | if(pChr) |
368 | { |
369 | int TeleOut = pSelf->m_World.m_Core.RandomOr0(BelowThis: pSelf->Collision()->TeleOuts(Number: TeleTo - 1).size()); |
370 | pSelf->Teleport(pChr, Pos: pSelf->Collision()->TeleOuts(Number: TeleTo - 1)[TeleOut]); |
371 | } |
372 | } |
373 | } |
374 | |
375 | void CGameContext::ConToCheckTeleporter(IConsole::IResult *pResult, void *pUserData) |
376 | { |
377 | CGameContext *pSelf = (CGameContext *)pUserData; |
378 | unsigned int TeleTo = pResult->GetInteger(Index: 0); |
379 | |
380 | if(!pSelf->Collision()->TeleCheckOuts(Number: TeleTo - 1).empty()) |
381 | { |
382 | CCharacter *pChr = pSelf->GetPlayerChar(ClientId: pResult->m_ClientId); |
383 | if(pChr) |
384 | { |
385 | int TeleOut = pSelf->m_World.m_Core.RandomOr0(BelowThis: pSelf->Collision()->TeleCheckOuts(Number: TeleTo - 1).size()); |
386 | pSelf->Teleport(pChr, Pos: pSelf->Collision()->TeleCheckOuts(Number: TeleTo - 1)[TeleOut]); |
387 | pChr->m_TeleCheckpoint = TeleTo; |
388 | } |
389 | } |
390 | } |
391 | |
392 | void CGameContext::ConTeleport(IConsole::IResult *pResult, void *pUserData) |
393 | { |
394 | CGameContext *pSelf = (CGameContext *)pUserData; |
395 | int Tele = pResult->NumArguments() == 2 ? pResult->GetInteger(Index: 0) : pResult->m_ClientId; |
396 | int TeleTo = pResult->NumArguments() ? pResult->GetInteger(Index: pResult->NumArguments() - 1) : pResult->m_ClientId; |
397 | int AuthLevel = pSelf->Server()->GetAuthedState(ClientId: pResult->m_ClientId); |
398 | |
399 | if(Tele != pResult->m_ClientId && AuthLevel < g_Config.m_SvTeleOthersAuthLevel) |
400 | { |
401 | pSelf->Console()->Print(Level: IConsole::OUTPUT_LEVEL_STANDARD, pFrom: "tele" , pStr: "you aren't allowed to tele others" ); |
402 | return; |
403 | } |
404 | |
405 | CCharacter *pChr = pSelf->GetPlayerChar(ClientId: Tele); |
406 | CPlayer *pPlayer = pSelf->m_apPlayers[pResult->m_ClientId]; |
407 | |
408 | if(pChr && pPlayer && pSelf->GetPlayerChar(ClientId: TeleTo)) |
409 | { |
410 | vec2 Pos = pSelf->m_apPlayers[TeleTo]->m_ViewPos; |
411 | if(!pPlayer->IsPaused() && !pResult->NumArguments()) |
412 | { |
413 | Pos += vec2(pChr->Core()->m_Input.m_TargetX, pChr->Core()->m_Input.m_TargetY); |
414 | } |
415 | pSelf->Teleport(pChr, Pos); |
416 | pChr->ResetJumps(); |
417 | pChr->UnFreeze(); |
418 | pChr->SetVelocity(vec2(0, 0)); |
419 | } |
420 | } |
421 | |
422 | void CGameContext::ConKill(IConsole::IResult *pResult, void *pUserData) |
423 | { |
424 | CGameContext *pSelf = (CGameContext *)pUserData; |
425 | if(!CheckClientId(ClientId: pResult->m_ClientId)) |
426 | return; |
427 | CPlayer *pPlayer = pSelf->m_apPlayers[pResult->m_ClientId]; |
428 | |
429 | if(!pPlayer || (pPlayer->m_LastKill && pPlayer->m_LastKill + pSelf->Server()->TickSpeed() * g_Config.m_SvKillDelay > pSelf->Server()->Tick())) |
430 | return; |
431 | |
432 | pPlayer->m_LastKill = pSelf->Server()->Tick(); |
433 | pPlayer->KillCharacter(Weapon: WEAPON_SELF); |
434 | } |
435 | |
436 | void CGameContext::ConForcePause(IConsole::IResult *pResult, void *pUserData) |
437 | { |
438 | CGameContext *pSelf = (CGameContext *)pUserData; |
439 | int Victim = pResult->GetVictim(); |
440 | int Seconds = 0; |
441 | if(pResult->NumArguments() > 1) |
442 | Seconds = clamp(val: pResult->GetInteger(Index: 1), lo: 0, hi: 360); |
443 | |
444 | CPlayer *pPlayer = pSelf->m_apPlayers[Victim]; |
445 | if(!pPlayer) |
446 | return; |
447 | |
448 | pPlayer->ForcePause(Time: Seconds); |
449 | } |
450 | |
451 | bool CGameContext::TryVoteMute(const NETADDR *pAddr, int Secs, const char *pReason) |
452 | { |
453 | // find a matching vote mute for this ip, update expiration time if found |
454 | for(int i = 0; i < m_NumVoteMutes; i++) |
455 | { |
456 | if(net_addr_comp_noport(a: &m_aVoteMutes[i].m_Addr, b: pAddr) == 0) |
457 | { |
458 | m_aVoteMutes[i].m_Expire = Server()->Tick() + Secs * Server()->TickSpeed(); |
459 | str_copy(dst: m_aVoteMutes[i].m_aReason, src: pReason, dst_size: sizeof(m_aVoteMutes[i].m_aReason)); |
460 | return true; |
461 | } |
462 | } |
463 | |
464 | // nothing to update create new one |
465 | if(m_NumVoteMutes < MAX_VOTE_MUTES) |
466 | { |
467 | m_aVoteMutes[m_NumVoteMutes].m_Addr = *pAddr; |
468 | m_aVoteMutes[m_NumVoteMutes].m_Expire = Server()->Tick() + Secs * Server()->TickSpeed(); |
469 | str_copy(dst: m_aVoteMutes[m_NumVoteMutes].m_aReason, src: pReason, dst_size: sizeof(m_aVoteMutes[m_NumVoteMutes].m_aReason)); |
470 | m_NumVoteMutes++; |
471 | return true; |
472 | } |
473 | // no free slot found |
474 | Console()->Print(Level: IConsole::OUTPUT_LEVEL_STANDARD, pFrom: "votemute" , pStr: "vote mute array is full" ); |
475 | return false; |
476 | } |
477 | |
478 | void CGameContext::VoteMute(const NETADDR *pAddr, int Secs, const char *pReason, const char *pDisplayName, int AuthedId) |
479 | { |
480 | if(!TryVoteMute(pAddr, Secs, pReason)) |
481 | return; |
482 | if(!pDisplayName) |
483 | return; |
484 | |
485 | char aBuf[128]; |
486 | if(pReason[0]) |
487 | str_format(buffer: aBuf, buffer_size: sizeof(aBuf), format: "'%s' banned '%s' for %d seconds from voting (%s)" , |
488 | Server()->ClientName(ClientId: AuthedId), pDisplayName, Secs, pReason); |
489 | else |
490 | str_format(buffer: aBuf, buffer_size: sizeof(aBuf), format: "'%s' banned '%s' for %d seconds from voting" , |
491 | Server()->ClientName(ClientId: AuthedId), pDisplayName, Secs); |
492 | SendChat(ClientId: -1, Team: TEAM_ALL, pText: aBuf); |
493 | } |
494 | |
495 | bool CGameContext::VoteUnmute(const NETADDR *pAddr, const char *pDisplayName, int AuthedId) |
496 | { |
497 | for(int i = 0; i < m_NumVoteMutes; i++) |
498 | { |
499 | if(net_addr_comp_noport(a: &m_aVoteMutes[i].m_Addr, b: pAddr) == 0) |
500 | { |
501 | m_NumVoteMutes--; |
502 | m_aVoteMutes[i] = m_aVoteMutes[m_NumVoteMutes]; |
503 | if(pDisplayName) |
504 | { |
505 | char aBuf[128]; |
506 | str_format(buffer: aBuf, buffer_size: sizeof(aBuf), format: "'%s' unbanned '%s' from voting." , |
507 | Server()->ClientName(ClientId: AuthedId), pDisplayName); |
508 | Console()->Print(Level: IConsole::OUTPUT_LEVEL_STANDARD, pFrom: "voteunmute" , pStr: aBuf); |
509 | } |
510 | return true; |
511 | } |
512 | } |
513 | return false; |
514 | } |
515 | |
516 | bool CGameContext::TryMute(const NETADDR *pAddr, int Secs, const char *pReason, bool InitialChatDelay) |
517 | { |
518 | // find a matching mute for this ip, update expiration time if found |
519 | for(int i = 0; i < m_NumMutes; i++) |
520 | { |
521 | if(net_addr_comp_noport(a: &m_aMutes[i].m_Addr, b: pAddr) == 0) |
522 | { |
523 | const int NewExpire = Server()->Tick() + Secs * Server()->TickSpeed(); |
524 | if(NewExpire > m_aMutes[i].m_Expire) |
525 | { |
526 | m_aMutes[i].m_Expire = NewExpire; |
527 | str_copy(dst: m_aMutes[i].m_aReason, src: pReason, dst_size: sizeof(m_aMutes[i].m_aReason)); |
528 | m_aMutes[i].m_InitialChatDelay = InitialChatDelay; |
529 | } |
530 | return true; |
531 | } |
532 | } |
533 | |
534 | // nothing to update create new one |
535 | if(m_NumMutes < MAX_MUTES) |
536 | { |
537 | m_aMutes[m_NumMutes].m_Addr = *pAddr; |
538 | m_aMutes[m_NumMutes].m_Expire = Server()->Tick() + Secs * Server()->TickSpeed(); |
539 | str_copy(dst: m_aMutes[m_NumMutes].m_aReason, src: pReason, dst_size: sizeof(m_aMutes[m_NumMutes].m_aReason)); |
540 | m_aMutes[m_NumMutes].m_InitialChatDelay = InitialChatDelay; |
541 | m_NumMutes++; |
542 | return true; |
543 | } |
544 | // no free slot found |
545 | Console()->Print(Level: IConsole::OUTPUT_LEVEL_STANDARD, pFrom: "mutes" , pStr: "mute array is full" ); |
546 | return false; |
547 | } |
548 | |
549 | void CGameContext::Mute(const NETADDR *pAddr, int Secs, const char *pDisplayName, const char *pReason, bool InitialChatDelay) |
550 | { |
551 | if(Secs <= 0) |
552 | return; |
553 | if(!TryMute(pAddr, Secs, pReason, InitialChatDelay)) |
554 | return; |
555 | if(InitialChatDelay) |
556 | return; |
557 | if(!pDisplayName) |
558 | return; |
559 | |
560 | char aBuf[128]; |
561 | if(pReason[0]) |
562 | str_format(buffer: aBuf, buffer_size: sizeof(aBuf), format: "'%s' has been muted for %d seconds (%s)" , pDisplayName, Secs, pReason); |
563 | else |
564 | str_format(buffer: aBuf, buffer_size: sizeof(aBuf), format: "'%s' has been muted for %d seconds" , pDisplayName, Secs); |
565 | SendChat(ClientId: -1, Team: TEAM_ALL, pText: aBuf); |
566 | } |
567 | |
568 | void CGameContext::ConVoteMute(IConsole::IResult *pResult, void *pUserData) |
569 | { |
570 | CGameContext *pSelf = (CGameContext *)pUserData; |
571 | int Victim = pResult->GetVictim(); |
572 | |
573 | if(Victim < 0 || Victim > MAX_CLIENTS || !pSelf->m_apPlayers[Victim]) |
574 | { |
575 | pSelf->Console()->Print(Level: IConsole::OUTPUT_LEVEL_STANDARD, pFrom: "votemute" , pStr: "Client ID not found" ); |
576 | return; |
577 | } |
578 | |
579 | NETADDR Addr; |
580 | pSelf->Server()->GetClientAddr(ClientId: Victim, pAddr: &Addr); |
581 | |
582 | int Seconds = clamp(val: pResult->GetInteger(Index: 1), lo: 1, hi: 86400); |
583 | const char *pReason = pResult->NumArguments() > 2 ? pResult->GetString(Index: 2) : "" ; |
584 | pSelf->VoteMute(pAddr: &Addr, Secs: Seconds, pReason, pDisplayName: pSelf->Server()->ClientName(ClientId: Victim), AuthedId: pResult->m_ClientId); |
585 | } |
586 | |
587 | void CGameContext::ConVoteUnmute(IConsole::IResult *pResult, void *pUserData) |
588 | { |
589 | CGameContext *pSelf = (CGameContext *)pUserData; |
590 | int Victim = pResult->GetVictim(); |
591 | |
592 | if(Victim < 0 || Victim > MAX_CLIENTS || !pSelf->m_apPlayers[Victim]) |
593 | { |
594 | pSelf->Console()->Print(Level: IConsole::OUTPUT_LEVEL_STANDARD, pFrom: "voteunmute" , pStr: "Client ID not found" ); |
595 | return; |
596 | } |
597 | |
598 | NETADDR Addr; |
599 | pSelf->Server()->GetClientAddr(ClientId: Victim, pAddr: &Addr); |
600 | |
601 | bool Found = pSelf->VoteUnmute(pAddr: &Addr, pDisplayName: pSelf->Server()->ClientName(ClientId: Victim), AuthedId: pResult->m_ClientId); |
602 | if(Found) |
603 | { |
604 | char aBuf[128]; |
605 | str_format(buffer: aBuf, buffer_size: sizeof(aBuf), format: "'%s' unbanned '%s' from voting." , |
606 | pSelf->Server()->ClientName(ClientId: pResult->m_ClientId), pSelf->Server()->ClientName(ClientId: Victim)); |
607 | pSelf->SendChat(ClientId: -1, Team: 0, pText: aBuf); |
608 | } |
609 | } |
610 | |
611 | void CGameContext::ConVoteMutes(IConsole::IResult *pResult, void *pUserData) |
612 | { |
613 | CGameContext *pSelf = (CGameContext *)pUserData; |
614 | |
615 | if(pSelf->m_NumVoteMutes <= 0) |
616 | { |
617 | // Just to make sure. |
618 | pSelf->m_NumVoteMutes = 0; |
619 | pSelf->Console()->Print(Level: IConsole::OUTPUT_LEVEL_STANDARD, pFrom: "votemutes" , |
620 | pStr: "There are no active vote mutes." ); |
621 | return; |
622 | } |
623 | |
624 | char aIpBuf[64]; |
625 | char aBuf[128]; |
626 | pSelf->Console()->Print(Level: IConsole::OUTPUT_LEVEL_STANDARD, pFrom: "votemutes" , |
627 | pStr: "Active vote mutes:" ); |
628 | for(int i = 0; i < pSelf->m_NumVoteMutes; i++) |
629 | { |
630 | net_addr_str(addr: &pSelf->m_aVoteMutes[i].m_Addr, string: aIpBuf, max_length: sizeof(aIpBuf), add_port: false); |
631 | str_format(buffer: aBuf, buffer_size: sizeof(aBuf), format: "%d: \"%s\", %d seconds left (%s)" , i, |
632 | aIpBuf, (pSelf->m_aVoteMutes[i].m_Expire - pSelf->Server()->Tick()) / pSelf->Server()->TickSpeed(), pSelf->m_aVoteMutes[i].m_aReason); |
633 | pSelf->Console()->Print(Level: IConsole::OUTPUT_LEVEL_STANDARD, pFrom: "votemutes" , pStr: aBuf); |
634 | } |
635 | } |
636 | |
637 | void CGameContext::ConMute(IConsole::IResult *pResult, void *pUserData) |
638 | { |
639 | CGameContext *pSelf = (CGameContext *)pUserData; |
640 | pSelf->Console()->Print( |
641 | Level: IConsole::OUTPUT_LEVEL_STANDARD, |
642 | pFrom: "mutes" , |
643 | pStr: "Use either 'muteid <client_id> <seconds> <reason>' or 'muteip <ip> <seconds> <reason>'" ); |
644 | } |
645 | |
646 | // mute through client id |
647 | void CGameContext::ConMuteId(IConsole::IResult *pResult, void *pUserData) |
648 | { |
649 | CGameContext *pSelf = (CGameContext *)pUserData; |
650 | int Victim = pResult->GetVictim(); |
651 | |
652 | if(Victim < 0 || Victim > MAX_CLIENTS || !pSelf->m_apPlayers[Victim]) |
653 | { |
654 | pSelf->Console()->Print(Level: IConsole::OUTPUT_LEVEL_STANDARD, pFrom: "muteid" , pStr: "Client id not found." ); |
655 | return; |
656 | } |
657 | |
658 | NETADDR Addr; |
659 | pSelf->Server()->GetClientAddr(ClientId: Victim, pAddr: &Addr); |
660 | |
661 | const char *pReason = pResult->NumArguments() > 2 ? pResult->GetString(Index: 2) : "" ; |
662 | |
663 | pSelf->Mute(pAddr: &Addr, Secs: clamp(val: pResult->GetInteger(Index: 1), lo: 1, hi: 86400), |
664 | pDisplayName: pSelf->Server()->ClientName(ClientId: Victim), pReason); |
665 | } |
666 | |
667 | // mute through ip, arguments reversed to workaround parsing |
668 | void CGameContext::ConMuteIp(IConsole::IResult *pResult, void *pUserData) |
669 | { |
670 | CGameContext *pSelf = (CGameContext *)pUserData; |
671 | NETADDR Addr; |
672 | if(net_addr_from_str(addr: &Addr, string: pResult->GetString(Index: 0))) |
673 | { |
674 | pSelf->Console()->Print(Level: IConsole::OUTPUT_LEVEL_STANDARD, pFrom: "mutes" , |
675 | pStr: "Invalid network address to mute" ); |
676 | } |
677 | const char *pReason = pResult->NumArguments() > 2 ? pResult->GetString(Index: 2) : "" ; |
678 | pSelf->Mute(pAddr: &Addr, Secs: clamp(val: pResult->GetInteger(Index: 1), lo: 1, hi: 86400), NULL, pReason); |
679 | } |
680 | |
681 | // unmute by mute list index |
682 | void CGameContext::ConUnmute(IConsole::IResult *pResult, void *pUserData) |
683 | { |
684 | CGameContext *pSelf = (CGameContext *)pUserData; |
685 | int Index = pResult->GetInteger(Index: 0); |
686 | |
687 | if(Index < 0 || Index >= pSelf->m_NumMutes) |
688 | return; |
689 | |
690 | char aIpBuf[64]; |
691 | char aBuf[64]; |
692 | net_addr_str(addr: &pSelf->m_aMutes[Index].m_Addr, string: aIpBuf, max_length: sizeof(aIpBuf), add_port: false); |
693 | str_format(buffer: aBuf, buffer_size: sizeof(aBuf), format: "Unmuted %s" , aIpBuf); |
694 | pSelf->Console()->Print(Level: IConsole::OUTPUT_LEVEL_STANDARD, pFrom: "mutes" , pStr: aBuf); |
695 | |
696 | pSelf->m_NumMutes--; |
697 | pSelf->m_aMutes[Index] = pSelf->m_aMutes[pSelf->m_NumMutes]; |
698 | } |
699 | |
700 | // unmute by player id |
701 | void CGameContext::ConUnmuteId(IConsole::IResult *pResult, void *pUserData) |
702 | { |
703 | CGameContext *pSelf = (CGameContext *)pUserData; |
704 | int Victim = pResult->GetVictim(); |
705 | |
706 | if(Victim < 0 || Victim > MAX_CLIENTS || !pSelf->m_apPlayers[Victim]) |
707 | return; |
708 | |
709 | NETADDR Addr; |
710 | pSelf->Server()->GetClientAddr(ClientId: Victim, pAddr: &Addr); |
711 | |
712 | for(int i = 0; i < pSelf->m_NumMutes; i++) |
713 | { |
714 | if(net_addr_comp_noport(a: &pSelf->m_aMutes[i].m_Addr, b: &Addr) == 0) |
715 | { |
716 | char aIpBuf[64]; |
717 | char aBuf[64]; |
718 | net_addr_str(addr: &pSelf->m_aMutes[i].m_Addr, string: aIpBuf, max_length: sizeof(aIpBuf), add_port: false); |
719 | str_format(buffer: aBuf, buffer_size: sizeof(aBuf), format: "Unmuted %s" , aIpBuf); |
720 | pSelf->Console()->Print(Level: IConsole::OUTPUT_LEVEL_STANDARD, pFrom: "mutes" , pStr: aBuf); |
721 | pSelf->m_NumMutes--; |
722 | pSelf->m_aMutes[i] = pSelf->m_aMutes[pSelf->m_NumMutes]; |
723 | return; |
724 | } |
725 | } |
726 | } |
727 | |
728 | // list mutes |
729 | void CGameContext::ConMutes(IConsole::IResult *pResult, void *pUserData) |
730 | { |
731 | CGameContext *pSelf = (CGameContext *)pUserData; |
732 | |
733 | if(pSelf->m_NumMutes <= 0) |
734 | { |
735 | // Just to make sure. |
736 | pSelf->m_NumMutes = 0; |
737 | pSelf->Console()->Print(Level: IConsole::OUTPUT_LEVEL_STANDARD, pFrom: "mutes" , |
738 | pStr: "There are no active mutes." ); |
739 | return; |
740 | } |
741 | |
742 | char aIpBuf[64]; |
743 | char aBuf[128]; |
744 | pSelf->Console()->Print(Level: IConsole::OUTPUT_LEVEL_STANDARD, pFrom: "mutes" , |
745 | pStr: "Active mutes:" ); |
746 | for(int i = 0; i < pSelf->m_NumMutes; i++) |
747 | { |
748 | net_addr_str(addr: &pSelf->m_aMutes[i].m_Addr, string: aIpBuf, max_length: sizeof(aIpBuf), add_port: false); |
749 | str_format(buffer: aBuf, buffer_size: sizeof(aBuf), format: "%d: \"%s\", %d seconds left (%s)" , i, aIpBuf, |
750 | (pSelf->m_aMutes[i].m_Expire - pSelf->Server()->Tick()) / pSelf->Server()->TickSpeed(), pSelf->m_aMutes[i].m_aReason); |
751 | pSelf->Console()->Print(Level: IConsole::OUTPUT_LEVEL_STANDARD, pFrom: "mutes" , pStr: aBuf); |
752 | } |
753 | } |
754 | |
755 | void CGameContext::ConModerate(IConsole::IResult *pResult, void *pUserData) |
756 | { |
757 | CGameContext *pSelf = (CGameContext *)pUserData; |
758 | if(!CheckClientId(ClientId: pResult->m_ClientId)) |
759 | return; |
760 | |
761 | bool HadModerator = pSelf->PlayerModerating(); |
762 | |
763 | CPlayer *pPlayer = pSelf->m_apPlayers[pResult->m_ClientId]; |
764 | pPlayer->m_Moderating = !pPlayer->m_Moderating; |
765 | |
766 | if(!HadModerator && pPlayer->m_Moderating) |
767 | pSelf->SendChat(ClientId: -1, Team: TEAM_ALL, pText: "Server kick/spec votes will now be actively moderated." , SpamProtectionClientId: 0); |
768 | |
769 | if(!pSelf->PlayerModerating()) |
770 | pSelf->SendChat(ClientId: -1, Team: TEAM_ALL, pText: "Server kick/spec votes are no longer actively moderated." , SpamProtectionClientId: 0); |
771 | |
772 | if(pPlayer->m_Moderating) |
773 | pSelf->SendChatTarget(To: pResult->m_ClientId, pText: "Active moderator mode enabled for you." ); |
774 | else |
775 | pSelf->SendChatTarget(To: pResult->m_ClientId, pText: "Active moderator mode disabled for you." ); |
776 | } |
777 | |
778 | void CGameContext::ConSetDDRTeam(IConsole::IResult *pResult, void *pUserData) |
779 | { |
780 | CGameContext *pSelf = (CGameContext *)pUserData; |
781 | auto *pController = pSelf->m_pController; |
782 | |
783 | if(g_Config.m_SvTeam == SV_TEAM_FORBIDDEN || g_Config.m_SvTeam == SV_TEAM_FORCED_SOLO) |
784 | { |
785 | pSelf->Console()->Print(Level: IConsole::OUTPUT_LEVEL_STANDARD, pFrom: "join" , |
786 | pStr: "Teams are disabled" ); |
787 | return; |
788 | } |
789 | |
790 | int Target = pResult->GetVictim(); |
791 | int Team = pResult->GetInteger(Index: 1); |
792 | |
793 | if(Team < TEAM_FLOCK || Team >= TEAM_SUPER) |
794 | return; |
795 | |
796 | CCharacter *pChr = pSelf->GetPlayerChar(ClientId: Target); |
797 | |
798 | if((pSelf->GetDDRaceTeam(ClientId: Target) && pController->Teams().GetDDRaceState(Player: pSelf->m_apPlayers[Target]) == DDRACE_STARTED) || (pChr && pController->Teams().IsPractice(Team: pChr->Team()))) |
799 | pSelf->m_apPlayers[Target]->KillCharacter(Weapon: WEAPON_GAME); |
800 | |
801 | pController->Teams().SetForceCharacterTeam(ClientId: Target, Team); |
802 | } |
803 | |
804 | void CGameContext::ConUninvite(IConsole::IResult *pResult, void *pUserData) |
805 | { |
806 | CGameContext *pSelf = (CGameContext *)pUserData; |
807 | auto *pController = pSelf->m_pController; |
808 | |
809 | pController->Teams().SetClientInvited(Team: pResult->GetInteger(Index: 1), ClientId: pResult->GetVictim(), Invited: false); |
810 | } |
811 | |
812 | void CGameContext::ConFreezeHammer(IConsole::IResult *pResult, void *pUserData) |
813 | { |
814 | CGameContext *pSelf = (CGameContext *)pUserData; |
815 | int Victim = pResult->GetVictim(); |
816 | |
817 | CCharacter *pChr = pSelf->GetPlayerChar(ClientId: Victim); |
818 | |
819 | if(!pChr) |
820 | return; |
821 | |
822 | char aBuf[128]; |
823 | str_format(buffer: aBuf, buffer_size: sizeof(aBuf), format: "'%s' got freeze hammer!" , |
824 | pSelf->Server()->ClientName(ClientId: Victim)); |
825 | pSelf->SendChat(ClientId: -1, Team: TEAM_ALL, pText: aBuf); |
826 | |
827 | pChr->m_FreezeHammer = true; |
828 | } |
829 | |
830 | void CGameContext::ConUnFreezeHammer(IConsole::IResult *pResult, void *pUserData) |
831 | { |
832 | CGameContext *pSelf = (CGameContext *)pUserData; |
833 | int Victim = pResult->GetVictim(); |
834 | |
835 | CCharacter *pChr = pSelf->GetPlayerChar(ClientId: Victim); |
836 | |
837 | if(!pChr) |
838 | return; |
839 | |
840 | char aBuf[128]; |
841 | str_format(buffer: aBuf, buffer_size: sizeof(aBuf), format: "'%s' lost freeze hammer!" , |
842 | pSelf->Server()->ClientName(ClientId: Victim)); |
843 | pSelf->SendChat(ClientId: -1, Team: TEAM_ALL, pText: aBuf); |
844 | |
845 | pChr->m_FreezeHammer = false; |
846 | } |
847 | void CGameContext::ConVoteNo(IConsole::IResult *pResult, void *pUserData) |
848 | { |
849 | CGameContext *pSelf = (CGameContext *)pUserData; |
850 | |
851 | pSelf->ForceVote(EnforcerId: pResult->m_ClientId, Success: false); |
852 | } |
853 | |
854 | void CGameContext::ConDrySave(IConsole::IResult *pResult, void *pUserData) |
855 | { |
856 | CGameContext *pSelf = (CGameContext *)pUserData; |
857 | |
858 | CPlayer *pPlayer = pSelf->m_apPlayers[pResult->m_ClientId]; |
859 | |
860 | if(!pPlayer || pSelf->Server()->GetAuthedState(ClientId: pResult->m_ClientId) != AUTHED_ADMIN) |
861 | return; |
862 | |
863 | CSaveTeam SavedTeam; |
864 | int Team = pSelf->GetDDRaceTeam(ClientId: pResult->m_ClientId); |
865 | int Result = SavedTeam.Save(pGameServer: pSelf, Team, Dry: true); |
866 | if(CSaveTeam::HandleSaveError(Result, ClientId: pResult->m_ClientId, pGameContext: pSelf)) |
867 | return; |
868 | |
869 | char aTimestamp[32]; |
870 | str_timestamp(buffer: aTimestamp, buffer_size: sizeof(aTimestamp)); |
871 | char aBuf[64]; |
872 | str_format(buffer: aBuf, buffer_size: sizeof(aBuf), format: "%s_%s_%s.save" , pSelf->Server()->GetMapName(), aTimestamp, pSelf->Server()->GetAuthName(ClientId: pResult->m_ClientId)); |
873 | IOHANDLE File = pSelf->Storage()->OpenFile(pFilename: aBuf, Flags: IOFLAG_WRITE, Type: IStorage::TYPE_ALL); |
874 | if(!File) |
875 | return; |
876 | |
877 | int Len = str_length(str: SavedTeam.GetString()); |
878 | io_write(io: File, buffer: SavedTeam.GetString(), size: Len); |
879 | io_close(io: File); |
880 | } |
881 | |
882 | void CGameContext::ConDumpAntibot(IConsole::IResult *pResult, void *pUserData) |
883 | { |
884 | CGameContext *pSelf = (CGameContext *)pUserData; |
885 | pSelf->Antibot()->ConsoleCommand(pCommand: "dump" ); |
886 | } |
887 | |
888 | void CGameContext::ConAntibot(IConsole::IResult *pResult, void *pUserData) |
889 | { |
890 | CGameContext *pSelf = (CGameContext *)pUserData; |
891 | pSelf->Antibot()->ConsoleCommand(pCommand: pResult->GetString(Index: 0)); |
892 | } |
893 | |
894 | void CGameContext::ConDumpLog(IConsole::IResult *pResult, void *pUserData) |
895 | { |
896 | CGameContext *pSelf = (CGameContext *)pUserData; |
897 | int LimitSecs = MAX_LOG_SECONDS; |
898 | if(pResult->NumArguments() > 0) |
899 | LimitSecs = pResult->GetInteger(Index: 0); |
900 | |
901 | if(LimitSecs < 0) |
902 | return; |
903 | |
904 | int Iterator = pSelf->m_LatestLog; |
905 | for(int i = 0; i < MAX_LOGS; i++) |
906 | { |
907 | CLog *pEntry = &pSelf->m_aLogs[Iterator]; |
908 | Iterator = (Iterator + 1) % MAX_LOGS; |
909 | |
910 | if(!pEntry->m_Timestamp) |
911 | continue; |
912 | |
913 | int Seconds = (time_get() - pEntry->m_Timestamp) / time_freq(); |
914 | if(Seconds > LimitSecs) |
915 | continue; |
916 | |
917 | char aBuf[256]; |
918 | if(pEntry->m_FromServer) |
919 | str_format(buffer: aBuf, buffer_size: sizeof(aBuf), format: "%s, %d seconds ago" , pEntry->m_aDescription, Seconds); |
920 | else |
921 | str_format(buffer: aBuf, buffer_size: sizeof(aBuf), format: "%s, %d seconds ago < addr=<{%s}> name='%s' client=%d" , |
922 | pEntry->m_aDescription, Seconds, pEntry->m_aClientAddrStr, pEntry->m_aClientName, pEntry->m_ClientVersion); |
923 | pSelf->Console()->Print(Level: IConsole::OUTPUT_LEVEL_STANDARD, pFrom: "log" , pStr: aBuf); |
924 | } |
925 | } |
926 | |
927 | void CGameContext::LogEvent(const char *Description, int ClientId) |
928 | { |
929 | CLog *pNewEntry = &m_aLogs[m_LatestLog]; |
930 | m_LatestLog = (m_LatestLog + 1) % MAX_LOGS; |
931 | |
932 | pNewEntry->m_Timestamp = time_get(); |
933 | str_copy(dst&: pNewEntry->m_aDescription, src: Description); |
934 | pNewEntry->m_FromServer = ClientId < 0; |
935 | if(!pNewEntry->m_FromServer) |
936 | { |
937 | pNewEntry->m_ClientVersion = Server()->GetClientVersion(ClientId); |
938 | Server()->GetClientAddr(ClientId, pAddrStr: pNewEntry->m_aClientAddrStr, Size: sizeof(pNewEntry->m_aClientAddrStr)); |
939 | str_copy(dst&: pNewEntry->m_aClientName, src: Server()->ClientName(ClientId)); |
940 | } |
941 | } |
942 | |