· 5 years ago · Feb 26, 2020, 12:12 AM
1#include "stdafx.h"
2
3#ifdef __ADMIN_MANAGER__
4#include "admin_manager.h"
5#include "char.h"
6#include "gm.h"
7#include "buffer_manager.h"
8#include "desc_manager.h"
9#include "config.h"
10#include "char_manager.h"
11#include "sectree_manager.h"
12#include "sectree.h"
13#include "map_location.h"
14#include "whisper_manager.h"
15#include "item.h"
16#include "db.h"
17#include "desc_client.h"
18#include "log.h"
19#include "p2p.h"
20#include "questmanager.h"
21
22/*******************************************************************\
23|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
24|||| CAdminManager - CLASS
25|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
26\*******************************************************************/
27
28#define ADMIN_MANAGER_DISCONNECT_ON_BAN_DELAY 5
29
30struct FMapViewerLoadPlayer
31{
32 FMapViewerLoadPlayer(TEMP_BUFFER& rkBuf) : m_rkBuf(rkBuf)
33 {
34 m_dwCount = 0;
35 }
36
37 void operator()(LPENTITY ent)
38 {
39 if (!ent->IsType(ENTITY_CHARACTER))
40 return;
41
42 LPCHARACTER pkChr = (LPCHARACTER) ent;
43
44 if (!pkChr->IsPC())
45 return;
46
47 m_dwCount++;
48 m_rkBuf.write(&CAdminManager::Instance().GetMapViewerPlayerInfo(pkChr), sizeof(TAdminManagerMapViewerPlayerInfo));
49 }
50
51 TEMP_BUFFER& m_rkBuf;
52 DWORD m_dwCount;
53};
54
55struct FMapViewerLoadMob
56{
57 FMapViewerLoadMob(TEMP_BUFFER& rkBuf, DWORD dwAllowFlag) : m_rkBuf(rkBuf), m_dwAllowFlag(dwAllowFlag)
58 {
59 m_dwCount = 0;
60 }
61
62 void operator()(LPENTITY ent)
63 {
64 if (!ent->IsType(ENTITY_CHARACTER))
65 return;
66
67 LPCHARACTER pkChr = (LPCHARACTER)ent;
68
69 if (!CAdminManager::instance().CheckMapViewerNPC(pkChr, m_dwAllowFlag))
70 return;
71
72 m_dwCount++;
73 m_rkBuf.write(&CAdminManager::Instance().GetMapViewerMonsterInfo(pkChr), sizeof(TAdminManagerMapViewerMobInfo));
74 }
75
76 TEMP_BUFFER& m_rkBuf;
77 DWORD m_dwCount;
78 DWORD m_dwAllowFlag;
79};
80
81/*******************************************************************\
82| [PUBLIC] (De-)Initialize Functions
83\*******************************************************************/
84
85CAdminManager::CAdminManager()
86{
87 memset(m_adwConfig, 0, sizeof(m_adwConfig));
88}
89
90CAdminManager::~CAdminManager()
91{
92 Destroy();
93}
94
95void CAdminManager::Initialize(DWORD* padwConfig, bool bReload)
96{
97 memcpy(m_adwConfig, padwConfig, sizeof(m_adwConfig));
98
99 if (!bReload)
100 InitializeBan();
101}
102
103void CAdminManager::Destroy()
104{
105
106}
107
108/*******************************************************************\
109| [PUBLIC] General Functions
110\*******************************************************************/
111
112TAdminManagerPlayerInfo& CAdminManager::GetPlayerInfo(LPCHARACTER pkChr)
113{
114 static TAdminManagerPlayerInfo kInfo;
115
116 kInfo.dwPID = pkChr->GetPlayerID();
117 strlcpy(kInfo.szName, pkChr->GetName(), sizeof(kInfo.szName));
118 kInfo.lMapIndex = pkChr->GetMapIndex();
119 kInfo.bChannel = g_bChannel;
120 kInfo.bEmpire = pkChr->GetEmpire();
121
122 return kInfo;
123}
124
125TAdminManagerPlayerInfo& CAdminManager::GetPlayerInfo(CCI* pCCI)
126{
127 static TAdminManagerPlayerInfo kInfo;
128
129 kInfo.dwPID = pCCI->dwPID;
130 strlcpy(kInfo.szName, pCCI->szName, sizeof(kInfo.szName));
131 kInfo.lMapIndex = pCCI->lMapIndex;
132 kInfo.bChannel = pCCI->bChannel;
133 kInfo.bEmpire = pCCI->bEmpire;
134
135 return kInfo;
136}
137
138DWORD CAdminManager::GetPlayerInfoList(std::vector<TAdminManagerPlayerInfo>& rvec_PlayerInfo)
139{
140 // get user by desc
141 const DESC_MANAGER::DESC_SET& rset_ClientDesc = DESC_MANAGER::instance().GetClientSet();
142 for (itertype(rset_ClientDesc) it = rset_ClientDesc.begin(); it != rset_ClientDesc.end(); ++it)
143 {
144 LPCHARACTER pkChr = (*it)->GetCharacter();
145 if (pkChr && !(*it)->IsPhase(PHASE_LOADING))
146 rvec_PlayerInfo.push_back(GetPlayerInfo(pkChr));
147 }
148
149 // get user by p2p manager
150 const P2P_MANAGER::TPIDCCIMap* pP2PMap = P2P_MANAGER::instance().GetP2PCCIMap();
151 for (itertype(*pP2PMap) it = pP2PMap->begin(); it != pP2PMap->end(); ++it)
152 {
153 CCI* pCCI = it->second;
154 rvec_PlayerInfo.push_back(GetPlayerInfo(pCCI));
155 }
156
157 return rvec_PlayerInfo.size();
158}
159
160/*******************************************************************\
161| [PUBLIC] Team Allow Functions
162\*******************************************************************/
163
164BYTE CAdminManager::GetTeamRankByPID(DWORD dwPID) const
165{
166 static DWORD s_dwOldPID = 0;
167 static BYTE s_bOldRank = GM_PLAYER;
168
169 if (s_dwOldPID == dwPID)
170 return s_bOldRank;
171
172 s_dwOldPID = dwPID;
173
174 // get rank by pid
175 if (LPCHARACTER pkChr = CHARACTER_MANAGER::instance().FindByPID(dwPID))
176 {
177 s_bOldRank = pkChr->GetGMLevel(true);
178 }
179 else
180 {
181 if (CCI* pkCCI = P2P_MANAGER::instance().FindByPID(dwPID))
182 s_bOldRank = GM::get_level(pkCCI->szName, NULL, true);
183 else
184 {
185 sys_err("cannot get team rank by pid %u", dwPID);
186 s_bOldRank = GM_PLAYER;
187 }
188 }
189
190 return s_bOldRank;
191}
192
193DWORD CAdminManager::GetAllow(BYTE bTeamRank) const
194{
195 return m_adwConfig[bTeamRank];
196}
197
198DWORD CAdminManager::GetAllow(LPCHARACTER pkChr) const
199{
200 return GetAllow(pkChr->GetGMLevel(true));
201}
202
203bool CAdminManager::HasAllow(BYTE bTeamRank, DWORD dwAllowFlag) const
204{
205 return (GetAllow(bTeamRank) & dwAllowFlag) != 0;
206}
207
208bool CAdminManager::HasAllow(LPCHARACTER pkChr, DWORD dwAllowFlag) const
209{
210 return (GetAllow(pkChr) & dwAllowFlag) != 0;
211}
212
213/*******************************************************************\
214| [PUBLIC] MapViewer Functions
215\*******************************************************************/
216
217TAdminManagerMapViewerPlayerInfo& CAdminManager::GetMapViewerPlayerInfo(LPCHARACTER pkChr)
218{
219 static TAdminManagerMapViewerPlayerInfo kInfo;
220
221 kInfo.dwPID = pkChr->GetPlayerID();
222 strlcpy(kInfo.szName, pkChr->GetName(), sizeof(kInfo.szName));
223 kInfo.bEmpire = pkChr->GetEmpire();
224 kInfo.is_alive = !pkChr->IsDead();
225 kInfo.x = pkChr->GetX();
226 kInfo.y = pkChr->GetY();
227
228 return kInfo;
229}
230
231TAdminManagerMapViewerMobInfo& CAdminManager::GetMapViewerMonsterInfo(LPCHARACTER pkChr)
232{
233 static TAdminManagerMapViewerMobInfo kInfo;
234
235 kInfo.dwVID = pkChr->GetVID();
236 kInfo.dwRaceNum = pkChr->GetRaceNum();
237 kInfo.is_alive = !pkChr->IsDead();
238 kInfo.x = pkChr->GetX();
239 kInfo.y = pkChr->GetY();
240 kInfo.stone_drop_vnum = pkChr->IsStone() ? pkChr->GetDropMetinStoneVnum() : 0;
241
242 return kInfo;
243}
244
245DWORD CAdminManager::GetMapViewerNPCAllowFlag(LPCHARACTER pkNPC) const
246{
247 if (pkNPC->IsStone())
248 return ALLOW_VIEW_MAPVIEWER_STONE;
249 if (pkNPC->IsMonster() && pkNPC->GetMobRank() >= MOB_RANK_BOSS)
250 return ALLOW_VIEW_MAPVIEWER_MONSTER;
251 if (pkNPC->GetCharType() == CHAR_TYPE_NPC)
252 return ALLOW_VIEW_MAPVIEWER_NPC;
253
254 return 0;
255}
256
257bool CAdminManager::CheckMapViewerNPC(LPCHARACTER pkChr, DWORD dwAllowFlag)
258{
259 return (pkChr->IsStone() && (dwAllowFlag & ALLOW_VIEW_MAPVIEWER_STONE) != 0) ||
260 (pkChr->IsMonster() && pkChr->GetMobRank() >= MOB_RANK_BOSS && (dwAllowFlag & ALLOW_VIEW_MAPVIEWER_MONSTER) != 0) ||
261 (pkChr->GetCharType() == CHAR_TYPE_NPC && (dwAllowFlag & ALLOW_VIEW_MAPVIEWER_NPC) != 0);
262}
263
264long CAdminManager::GetMapViewerMapIndex(DWORD dwPID)
265{
266 itertype(m_map_MapViewerByPID) it = m_map_MapViewerByPID.find(dwPID);
267 if (it == m_map_MapViewerByPID.end())
268 return 0;
269 return it->second;
270}
271
272bool CAdminManager::IsRunningMapViewer(DWORD dwPID)
273{
274 return m_map_MapViewerByPID.find(dwPID) != m_map_MapViewerByPID.end();
275}
276
277void CAdminManager::StartMapViewer(LPCHARACTER pkChr, long lMapIndex)
278{
279 DWORD dwPID = pkChr->GetPlayerID();
280
281 long lCurrentMapIndex = GetMapViewerMapIndex(dwPID);
282 if (lCurrentMapIndex != 0)
283 {
284 if (lCurrentMapIndex == lMapIndex)
285 {
286 sys_err("cannot start mapviewer for %u %s (already running)", dwPID, pkChr->GetName());
287 return;
288 }
289
290 StopMapViewer(dwPID);
291 }
292
293 if (!CMapLocation::instance().Exists(lMapIndex))
294 {
295 sys_err("cannot start mapviewer for %u %s (map %ld does not exist)", dwPID, pkChr->GetName(), lMapIndex);
296 return;
297 }
298
299 // check if the map is on other core
300 LPDESC pkP2PDesc = P2P_MANAGER::instance().GetP2PDescByMapIndex(lMapIndex);
301 if (pkP2PDesc)
302 {
303 StartMapViewer(dwPID, lMapIndex);
304
305 m_map_PlayerP2PConnections[dwPID].insert(pkP2PDesc);
306
307 TEMP_BUFFER buf;
308 buf.write(&dwPID, sizeof(DWORD));
309 buf.write(&lMapIndex, sizeof(long));
310 SendP2P(pkP2PDesc, P2P_SUBHEADER_START_MAPVIEWER, buf.read_peek(), buf.size());
311 }
312 else
313 {
314 pkChr->ChatPacket(CHAT_TYPE_INFO, LC_TEXT(pkChr, "The mapviewer was not able to start."));
315 }
316}
317
318void CAdminManager::StartMapViewer(DWORD dwPID, long lMapIndex)
319{
320 m_map_MapViewerByPID[dwPID] = lMapIndex;
321 m_map_MapViewerByMapIndex[lMapIndex].insert(dwPID);
322
323 LPDESC pkP2PDesc = P2P_MANAGER::instance().GetP2PDescByMapIndex(lMapIndex);
324 if (!pkP2PDesc)
325 SendMapViewerLoadPacket(dwPID, lMapIndex);
326}
327
328void CAdminManager::StopMapViewer(DWORD dwPID)
329{
330 if (!IsRunningMapViewer(dwPID))
331 {
332 sys_err("cannot stop mapviewer for pid %u (not running)", dwPID);
333 return;
334 }
335
336 long lMapIndex = m_map_MapViewerByPID[dwPID];
337
338 m_map_MapViewerByMapIndex[lMapIndex].erase(dwPID);
339 m_map_MapViewerByPID.erase(dwPID);
340
341 // check if the map is on other core
342 LPDESC pkP2PDesc = P2P_MANAGER::instance().GetP2PDescByMapIndex(lMapIndex);
343 if (pkP2PDesc)
344 SendP2P(pkP2PDesc, P2P_SUBHEADER_STOP_MAPVIEWER, &dwPID, sizeof(DWORD));
345}
346
347/*******************************************************************\
348| [PUBLIC] MapViewer Event Functions
349\*******************************************************************/
350
351void CAdminManager::MapViewer_OnPlayerLogin(LPCHARACTER pkChr)
352{
353 itertype(m_map_MapViewerByMapIndex) it = m_map_MapViewerByMapIndex.find(pkChr->GetMapIndex());
354 if (it == m_map_MapViewerByMapIndex.end() || it->second.size() == 0)
355 return;
356
357 for (itertype(it->second) set_it = it->second.begin(); set_it != it->second.end(); ++set_it)
358 {
359 if (HasAllow(GetTeamRankByPID(*set_it), ALLOW_VIEW_MAPVIEWER_PLAYER))
360 SendClientPacket(*set_it, GC_SUBHEADER_MAPVIEWER_PLAYER_APPEND, &GetMapViewerPlayerInfo(pkChr), sizeof(TAdminManagerMapViewerPlayerInfo));
361 }
362}
363
364void CAdminManager::MapViewer_OnPlayerLogout(LPCHARACTER pkChr)
365{
366 itertype(m_map_MapViewerByMapIndex) it = m_map_MapViewerByMapIndex.find(pkChr->GetMapIndex());
367 if (it == m_map_MapViewerByMapIndex.end() || it->second.size() == 0)
368 return;
369
370 DWORD dwPID = pkChr->GetPlayerID();
371
372 for (itertype(it->second) set_it = it->second.begin(); set_it != it->second.end(); ++set_it)
373 {
374 if (HasAllow(GetTeamRankByPID(*set_it), ALLOW_VIEW_MAPVIEWER_PLAYER))
375 SendClientPacket(*set_it, GC_SUBHEADER_MAPVIEWER_PLAYER_DESTROY, &dwPID, sizeof(DWORD));
376 }
377}
378
379void CAdminManager::MapViewer_OnPlayerMove(LPCHARACTER pkChr)
380{
381 itertype(m_map_MapViewerByMapIndex) it = m_map_MapViewerByMapIndex.find(pkChr->GetMapIndex());
382 if (it == m_map_MapViewerByMapIndex.end() || it->second.size() == 0)
383 return;
384
385 DWORD dwPID = pkChr->GetPlayerID();
386 const PIXEL_POSITION& rkPos = pkChr->GetXYZ();
387
388 TEMP_BUFFER buf;
389 buf.write(&dwPID, sizeof(DWORD));
390 buf.write(&rkPos.x, sizeof(rkPos.x));
391 buf.write(&rkPos.y, sizeof(rkPos.y));
392
393 for (itertype(it->second) set_it = it->second.begin(); set_it != it->second.end(); ++set_it)
394 {
395 if (HasAllow(GetTeamRankByPID(*set_it), ALLOW_VIEW_MAPVIEWER_PLAYER))
396 SendClientPacket(*set_it, GC_SUBHEADER_MAPVIEWER_PLAYER_MOVE, buf.read_peek(), buf.size());
397 }
398}
399
400void CAdminManager::MapViewer_OnPlayerStateChange(LPCHARACTER pkChr)
401{
402 itertype(m_map_MapViewerByMapIndex) it = m_map_MapViewerByMapIndex.find(pkChr->GetMapIndex());
403 if (it == m_map_MapViewerByMapIndex.end() || it->second.size() == 0)
404 return;
405
406 DWORD dwPID = pkChr->GetPlayerID();
407 bool is_alive = !pkChr->IsDead();
408
409 TEMP_BUFFER buf;
410 buf.write(&dwPID, sizeof(DWORD));
411 buf.write(&is_alive, sizeof(bool));
412
413 for (itertype(it->second) set_it = it->second.begin(); set_it != it->second.end(); ++set_it)
414 {
415 if (HasAllow(GetTeamRankByPID(*set_it), ALLOW_VIEW_MAPVIEWER_PLAYER))
416 SendClientPacket(*set_it, GC_SUBHEADER_MAPVIEWER_PLAYER_STATE, buf.read_peek(), buf.size());
417 }
418}
419
420void CAdminManager::MapViewer_OnMonsterCreate(LPCHARACTER pkChr)
421{
422 if (!CheckMapViewerNPC(pkChr))
423 return;
424
425 itertype(m_map_MapViewerByMapIndex) it = m_map_MapViewerByMapIndex.find(pkChr->GetMapIndex());
426 if (it == m_map_MapViewerByMapIndex.end() || it->second.size() == 0)
427 return;
428
429 DWORD dwAllowFlag = GetMapViewerNPCAllowFlag(pkChr);
430
431 for (itertype(it->second) set_it = it->second.begin(); set_it != it->second.end(); ++set_it)
432 {
433 if (HasAllow(GetTeamRankByPID(*set_it), dwAllowFlag))
434 SendClientPacket(*set_it, GC_SUBHEADER_MAPVIEWER_MONSTER_APPEND, &GetMapViewerMonsterInfo(pkChr), sizeof(TAdminManagerMapViewerMobInfo));
435 }
436}
437
438void CAdminManager::MapViewer_OnMonsterDestroy(LPCHARACTER pkChr)
439{
440 if (!CheckMapViewerNPC(pkChr))
441 return;
442
443 itertype(m_map_MapViewerByMapIndex) it = m_map_MapViewerByMapIndex.find(pkChr->GetMapIndex());
444 if (it == m_map_MapViewerByMapIndex.end() || it->second.size() == 0)
445 return;
446
447 DWORD dwAllowFlag = GetMapViewerNPCAllowFlag(pkChr);
448 DWORD dwVID = pkChr->GetVID();
449
450 for (itertype(it->second) set_it = it->second.begin(); set_it != it->second.end(); ++set_it)
451 {
452 if (HasAllow(GetTeamRankByPID(*set_it), dwAllowFlag))
453 SendClientPacket(*set_it, GC_SUBHEADER_MAPVIEWER_MONSTER_DESTROY, &dwVID, sizeof(DWORD));
454 }
455}
456
457void CAdminManager::MapViewer_OnMonsterMove(LPCHARACTER pkChr)
458{
459 if (!CheckMapViewerNPC(pkChr))
460 return;
461
462 itertype(m_map_MapViewerByMapIndex) it = m_map_MapViewerByMapIndex.find(pkChr->GetMapIndex());
463 if (it == m_map_MapViewerByMapIndex.end() || it->second.size() == 0)
464 return;
465
466 DWORD dwAllowFlag = GetMapViewerNPCAllowFlag(pkChr);
467 DWORD dwVID = pkChr->GetVID();
468 const PIXEL_POSITION& rkPos = pkChr->GetXYZ();
469
470 TEMP_BUFFER buf;
471 buf.write(&dwVID, sizeof(DWORD));
472 buf.write(&rkPos.x, sizeof(rkPos.x));
473 buf.write(&rkPos.y, sizeof(rkPos.y));
474
475 for (itertype(it->second) set_it = it->second.begin(); set_it != it->second.end(); ++set_it)
476 {
477 if (HasAllow(GetTeamRankByPID(*set_it), dwAllowFlag))
478 SendClientPacket(*set_it, GC_SUBHEADER_MAPVIEWER_MONSTER_MOVE, buf.read_peek(), buf.size());
479 }
480}
481
482void CAdminManager::MapViewer_OnMonsterStateChange(LPCHARACTER pkChr)
483{
484 if (!CheckMapViewerNPC(pkChr))
485 return;
486
487 itertype(m_map_MapViewerByMapIndex) it = m_map_MapViewerByMapIndex.find(pkChr->GetMapIndex());
488 if (it == m_map_MapViewerByMapIndex.end() || it->second.size() == 0)
489 return;
490
491 DWORD dwAllowFlag = GetMapViewerNPCAllowFlag(pkChr);
492 DWORD dwVID = pkChr->GetVID();
493 bool is_alive = !pkChr->IsDead();
494
495 TEMP_BUFFER buf;
496 buf.write(&dwVID, sizeof(DWORD));
497 buf.write(&is_alive, sizeof(bool));
498
499 for (itertype(it->second) set_it = it->second.begin(); set_it != it->second.end(); ++set_it)
500 {
501 if (HasAllow(GetTeamRankByPID(*set_it), dwAllowFlag))
502 SendClientPacket(*set_it, GC_SUBHEADER_MAPVIEWER_MONSTER_STATE, buf.read_peek(), buf.size());
503 }
504}
505
506/*******************************************************************\
507| [PUBLIC] Observer Functions
508\*******************************************************************/
509
510bool CAdminManager::IsObserverUpdatePoint(unsigned char bType) const
511{
512 static const unsigned char s_abPoints[] = { POINT_LEVEL, POINT_EXP, POINT_NEXT_EXP, POINT_HT, POINT_ST, POINT_DX, POINT_IQ,
513 POINT_HP, POINT_MAX_HP, POINT_SP, POINT_MAX_SP, POINT_GOLD };
514 static const unsigned char* s_pbPointLast = s_abPoints + sizeof(s_abPoints) / sizeof(unsigned char);
515 return std::find(s_abPoints, s_pbPointLast, bType) != s_pbPointLast;
516}
517
518DWORD CAdminManager::GetObserverPID(DWORD dwPID)
519{
520 itertype(m_map_ObserverByPID) it = m_map_ObserverByPID.find(dwPID);
521 if (it == m_map_ObserverByPID.end())
522 return 0;
523 return it->second;
524}
525
526bool CAdminManager::IsRunningObserver(DWORD dwPID)
527{
528 return m_map_ObserverByPID.find(dwPID) != m_map_ObserverByPID.end();
529}
530
531void CAdminManager::StartObserver(LPCHARACTER pkChr, const char* c_pszPlayerName, bool bSendFailMessage)
532{
533 DWORD dwPID = pkChr->GetPlayerID();
534
535 LPDESC pkPlayerP2PDesc = NULL;
536 DWORD dwPlayerPID;
537 if (LPCHARACTER pkPlayer = CHARACTER_MANAGER::instance().FindPC(c_pszPlayerName))
538 {
539 if (pkPlayer->GetDesc()->IsPhase(PHASE_GAME) || pkPlayer->GetDesc()->IsPhase(PHASE_DEAD))
540 dwPlayerPID = pkPlayer->GetPlayerID();
541 else
542 {
543 if (bSendFailMessage)
544 pkChr->ChatPacket(CHAT_TYPE_INFO, LC_TEXT(pkChr, "Cannot find player by name %s."), c_pszPlayerName);
545 return;
546 }
547 }
548 else
549 {
550 CCI* pkCCI = P2P_MANAGER::instance().Find(c_pszPlayerName);
551 if (pkCCI)
552 {
553 pkPlayerP2PDesc = pkCCI->pkDesc;
554 dwPlayerPID = pkCCI->dwPID;
555 }
556 else
557 {
558 if (bSendFailMessage)
559 pkChr->ChatPacket(CHAT_TYPE_INFO, LC_TEXT(pkChr, "Cannot find player by name %s."), c_pszPlayerName);
560 return;
561 }
562 }
563
564 if (GetTeamRankByPID(dwPlayerPID) >= pkChr->GetGMLevel(true) && pkChr->GetGMLevel(true) < GM_IMPLEMENTOR)
565 {
566 if (bSendFailMessage)
567 pkChr->ChatPacket(CHAT_TYPE_INFO, LC_TEXT(pkChr, "You cannot observe player %s."), c_pszPlayerName);
568 return;
569 }
570
571 DWORD dwCurrentPID = GetObserverPID(dwPID);
572 if (dwCurrentPID != 0)
573 {
574 if (dwCurrentPID == dwPID)
575 {
576 sys_err("cannot start observer for %u %s (already running)", dwPID, pkChr->GetName());
577 return;
578 }
579
580 StopObserver(dwPID);
581 }
582
583 StartObserver(dwPID, dwPlayerPID);
584
585 if (pkPlayerP2PDesc)
586 {
587 m_map_PlayerP2PConnections[dwPID].insert(pkPlayerP2PDesc);
588
589 TEMP_BUFFER buf;
590 buf.write(&dwPID, sizeof(DWORD));
591 buf.write(&dwPlayerPID, sizeof(DWORD));
592 SendP2P(pkPlayerP2PDesc, P2P_SUBHEADER_START_OBSERVER, buf.read_peek(), buf.size());
593 }
594}
595
596void CAdminManager::StartObserver(DWORD dwPID, DWORD dwPlayerPID)
597{
598 m_map_ObserverByPID[dwPID] = dwPlayerPID;
599 m_map_ObserverSetByPID[dwPlayerPID].insert(dwPID);
600
601 LPCHARACTER pkPlayer = CHARACTER_MANAGER::instance().FindByPID(dwPlayerPID);
602 if (pkPlayer)
603 SendObserverLoadPacket(dwPID, pkPlayer);
604}
605
606bool CAdminManager::StopObserver(DWORD dwPID, bool bIsForced)
607{
608 if (!IsRunningObserver(dwPID))
609 {
610 sys_err("cannot stop observer for pid %u (not running)", dwPID);
611 return false;
612 }
613
614 DWORD dwPlayerPID = m_map_ObserverByPID[dwPID];
615 m_map_ObserverByPID.erase(dwPID);
616
617 bool bRemovedSet = false;
618 std::set<DWORD>& rkPIDSet = m_map_ObserverSetByPID[dwPlayerPID];
619 if (rkPIDSet.size() == 1)
620 {
621 m_map_ObserverSetByPID.erase(dwPlayerPID);
622 bRemovedSet = true;
623 }
624 else
625 rkPIDSet.erase(dwPID);
626
627 if (bIsForced)
628 {
629 LPCHARACTER pkChr = CHARACTER_MANAGER::instance().FindByPID(dwPID);
630 if (pkChr)
631 {
632 SendClientPacket(pkChr->GetDesc(), GC_SUBHEADER_OBSERVER_STOP_FORCED, NULL, 0);
633 pkChr->ChatPacket(CHAT_TYPE_INFO, LC_TEXT(pkChr, "The observation of %s has been forced to stop."), pkChr->GetName());
634 pkChr->ChatPacket(CHAT_TYPE_INFO, LC_TEXT(pkChr, "The observation will continue when the player comes back online."));
635 }
636 }
637
638 CCI* pkP2PCCI;
639 // check if the observing player is on other core
640 pkP2PCCI = P2P_MANAGER::instance().FindByPID(dwPID);
641 if (pkP2PCCI)
642 SendP2P(pkP2PCCI->pkDesc, bIsForced ? P2P_SUBHEADER_STOP_OBSERVER_BY_FORCE : P2P_SUBHEADER_STOP_OBSERVER, &dwPID, sizeof(DWORD));
643 // check if the observed player is on other core
644 pkP2PCCI = P2P_MANAGER::instance().FindByPID(dwPlayerPID);
645 if (pkP2PCCI)
646 SendP2P(pkP2PCCI->pkDesc, bIsForced ? P2P_SUBHEADER_STOP_OBSERVER_BY_FORCE : P2P_SUBHEADER_STOP_OBSERVER, &dwPID, sizeof(DWORD));
647
648 return bRemovedSet;
649}
650
651/*******************************************************************\
652| [PUBLIC] Observer Event Functions
653\*******************************************************************/
654
655void CAdminManager::Observer_OnPlayerSkillGroupChange(LPCHARACTER pkChr)
656{
657 itertype(m_map_ObserverSetByPID) it = m_map_ObserverSetByPID.find(pkChr->GetPlayerID());
658 if (it == m_map_ObserverSetByPID.end() || it->second.size() == 0)
659 return;
660
661 unsigned char bSkillGroup = pkChr->GetSkillGroup();
662
663 SendObserverPacket(it->second, GC_SUBHEADER_OBSERVER_SKILLGROUP, &bSkillGroup, sizeof(unsigned char), ALLOW_VIEW_OBSERVER_SKILL);
664}
665
666void CAdminManager::Observer_OnPlayerSkillChange(LPCHARACTER pkChr, DWORD dwSkillVnum)
667{
668 itertype(m_map_ObserverSetByPID) it = m_map_ObserverSetByPID.find(pkChr->GetPlayerID());
669 if (it == m_map_ObserverSetByPID.end() || it->second.size() == 0)
670 return;
671
672 if (dwSkillVnum)
673 {
674 const TPlayerSkill* pkSkill = &(pkChr->GetPlayerSkills()[dwSkillVnum]);
675
676 TEMP_BUFFER buf;
677 buf.write(&dwSkillVnum, sizeof(DWORD));
678 buf.write(pkSkill, sizeof(TPlayerSkill));
679
680 SendObserverPacket(it->second, GC_SUBHEADER_OBSERVER_SKILL_UPDATE, buf.read_peek(), buf.size(), ALLOW_VIEW_OBSERVER_SKILL);
681 }
682 else
683 {
684 const TPlayerSkill* pkSkill = pkChr->GetPlayerSkills();
685
686 SendObserverPacket(it->second, GC_SUBHEADER_OBSERVER_SKILL_UPDATE_ALL, pkSkill, sizeof(TPlayerSkill) * SKILL_MAX_NUM, ALLOW_VIEW_OBSERVER_SKILL);
687 }
688}
689
690void CAdminManager::Observer_OnPlayerSkillCooldown(LPCHARACTER pkChr, DWORD dwSkillVnum, DWORD dwCoolTime)
691{
692 itertype(m_map_ObserverSetByPID) it = m_map_ObserverSetByPID.find(pkChr->GetPlayerID());
693 if (it == m_map_ObserverSetByPID.end() || it->second.size() == 0)
694 return;
695
696 TEMP_BUFFER buf;
697 buf.write(&dwSkillVnum, sizeof(DWORD));
698 buf.write(&dwCoolTime, sizeof(DWORD));
699 SendObserverPacket(it->second, GC_SUBHEADER_OBSERVER_SKILL_COOLDOWN, buf.read_peek(), buf.size(), ALLOW_VIEW_OBSERVER_SKILL);
700}
701
702void CAdminManager::Observer_OnPlayerPointChange(LPCHARACTER pkChr, unsigned char bType, long long llValue)
703{
704 if (!IsObserverUpdatePoint(bType))
705 return;
706
707 itertype(m_map_ObserverSetByPID) it = m_map_ObserverSetByPID.find(pkChr->GetPlayerID());
708 if (it == m_map_ObserverSetByPID.end() || it->second.size() == 0)
709 return;
710
711 TEMP_BUFFER buf;
712 buf.write(&bType, sizeof(unsigned char));
713 buf.write(&llValue, sizeof(long long));
714 SendObserverPacket(it->second, GC_SUBHEADER_OBSERVER_POINT_UPDATE, buf.read_peek(), buf.size(), bType == POINT_GOLD ? ALLOW_VIEW_OBSERVER_GOLD : 0);
715}
716
717void CAdminManager::Observer_OnPlayerItemSet(LPCHARACTER pkChr, WORD wCell)
718{
719 itertype(m_map_ObserverSetByPID) it = m_map_ObserverSetByPID.find(pkChr->GetPlayerID());
720 if (it == m_map_ObserverSetByPID.end() || it->second.size() == 0)
721 return;
722
723 bool bIsInventory = wCell < INVENTORY_MAX_NUM2 || wCell >= INVENTORY_MAX_NUM2 + WEAR_MAX_NUM;
724 DWORD dwAllowFlag = bIsInventory ? ALLOW_VIEW_OBSERVER_INVENTORY : ALLOW_VIEW_OBSERVER_EQUIPMENT;
725
726 LPITEM pkItem = pkChr->GetInventoryItem(wCell);
727 if (pkItem)
728 {
729 TAdminManagerObserverItemInfo kInfo;
730 EncodeObserverItemPacket(kInfo, pkItem);
731 SendObserverPacket(it->second, GC_SUBHEADER_OBSERVER_ITEM_SET, &kInfo, sizeof(kInfo), dwAllowFlag);
732 }
733 else
734 {
735 SendObserverPacket(it->second, GC_SUBHEADER_OBSERVER_ITEM_DEL, &wCell, sizeof(WORD), dwAllowFlag);
736 }
737}
738
739void CAdminManager::Observer_OnPlayerWhisper(LPCHARACTER pkChr, DWORD dwReceiverPID, const char* c_pszMessage)
740{
741 TEMP_BUFFER buf;
742 itertype(m_map_ObserverSetByPID) it;
743
744 it = m_map_ObserverSetByPID.find(pkChr->GetPlayerID());
745 if (it != m_map_ObserverSetByPID.end() && it->second.size() > 0)
746 {
747 buf.reset();
748 EncodeObserverWhisperPacket(buf, GC_SUBHEADER_NONE, dwReceiverPID, 0, c_pszMessage);
749 SendObserverPacket(it->second, GC_SUBHEADER_OBSERVER_WHISPER_SEND, buf.read_peek(), buf.size(), ALLOW_VIEW_OBSERVER_WHISPER);
750 }
751
752 it = m_map_ObserverSetByPID.find(dwReceiverPID);
753 if (it != m_map_ObserverSetByPID.end() && it->second.size() > 0)
754 {
755 buf.reset();
756 EncodeObserverWhisperPacket(buf, GC_SUBHEADER_NONE, pkChr->GetPlayerID(), 0, c_pszMessage);
757 SendObserverPacket(it->second, GC_SUBHEADER_OBSERVER_WHISPER_RECV, buf.read_peek(), buf.size(), ALLOW_VIEW_OBSERVER_WHISPER);
758 }
759}
760
761void CAdminManager::Observer_OnPlayerChatban(LPCHARACTER pkChr, DWORD dwTimeLeft)
762{
763 itertype(m_map_ObserverSetByPID) it = m_map_ObserverSetByPID.find(pkChr->GetPlayerID());
764 if (it == m_map_ObserverSetByPID.end() || it->second.size() == 0)
765 return;
766
767 SendObserverPacket(it->second, GC_SUBHEADER_OBSERVER_CHATBAN_STATE, &dwTimeLeft, sizeof(DWORD));
768}
769
770void CAdminManager::Observer_OnPlayerAccountban(DWORD dwPID, DWORD dwTimeLeft)
771{
772 itertype(m_map_ObserverSetByPID) it = m_map_ObserverSetByPID.find(dwPID);
773 if (it == m_map_ObserverSetByPID.end() || it->second.size() == 0)
774 return;
775
776 SendObserverPacket(it->second, GC_SUBHEADER_OBSERVER_ACCOUNTBAN_STATE, &dwTimeLeft, sizeof(DWORD));
777}
778
779/*******************************************************************\
780| [PUBLIC] Ban Functions
781\*******************************************************************/
782
783CAdminManager::TBanClientPlayerInfo& CAdminManager::GetBanClientPlayerInfo(LPCHARACTER pkChr, DWORD dwDuration)
784{
785 static TBanClientPlayerInfo kPlayerInfo;
786
787 if (!pkChr)
788 return kPlayerInfo;
789
790 kPlayerInfo.dwPID = pkChr->GetPlayerID();
791 strlcpy(kPlayerInfo.szName, pkChr->GetName(), sizeof(kPlayerInfo.szName));
792 kPlayerInfo.bRace = pkChr->GetRealRaceNum();
793 kPlayerInfo.bLevel = pkChr->GetLevel();
794 kPlayerInfo.wChatbanCount = pkChr->GetChatBanCount();
795 kPlayerInfo.wAccountbanCount = pkChr->GetAccountBanCount();
796 kPlayerInfo.dwDuration = dwDuration;
797 kPlayerInfo.bIsOnline = true;
798
799 return kPlayerInfo;
800}
801
802CAdminManager::TBanClientPlayerInfo& CAdminManager::GetBanClientPlayerInfo(DWORD dwPID, TChatBanPlayerInfo* pPlayerInfo)
803{
804 static TBanClientPlayerInfo kPlayerInfo;
805 kPlayerInfo.dwPID = dwPID;
806 strlcpy(kPlayerInfo.szName, pPlayerInfo->szName, sizeof(kPlayerInfo.szName));
807 kPlayerInfo.bRace = pPlayerInfo->bRace;
808 kPlayerInfo.bLevel = pPlayerInfo->bLevel;
809 kPlayerInfo.wChatbanCount = pPlayerInfo->wChatbanCount;
810 kPlayerInfo.wAccountbanCount = pPlayerInfo->wAccountbanCount;
811 kPlayerInfo.dwDuration = pPlayerInfo->GetDuration();
812 kPlayerInfo.bIsOnline = pPlayerInfo->IsOnline();
813
814 return kPlayerInfo;
815}
816
817CAdminManager::TBanClientAccountInfo& CAdminManager::GetBanClientAccountInfo(DWORD dwAID, TAccountBanPlayerInfo* pAccountInfo)
818{
819 static TBanClientAccountInfo kAccountInfo;
820 kAccountInfo.dwAID = dwAID;
821 strlcpy(kAccountInfo.szLoginName, pAccountInfo->szLoginName, sizeof(kAccountInfo.szLoginName));
822 for (int i = 0; i < PLAYER_PER_ACCOUNT; ++i)
823 {
824 kAccountInfo.dwPID[i] = pAccountInfo->dwPID[i];
825 strlcpy(kAccountInfo.szName[i], pAccountInfo->szName[i], sizeof(kAccountInfo.szName[i]));
826 kAccountInfo.bRace[i] = pAccountInfo->bRace[i];
827 kAccountInfo.bLevel[i] = pAccountInfo->bLevel[i];
828 kAccountInfo.wChatbanCount[i] = pAccountInfo->wChatbanCount[i];
829 }
830 kAccountInfo.wAccountbanCount = pAccountInfo->wAccountbanCount;
831 kAccountInfo.dwDuration = pAccountInfo->GetDuration();
832
833 for (int i = 0; i < PLAYER_PER_ACCOUNT; ++i)
834 {
835 kAccountInfo.bIsOnline[i] = false;
836
837 if (!pAccountInfo->dwPID[i])
838 continue;
839
840 if (CHARACTER_MANAGER::instance().FindByPID(pAccountInfo->dwPID[i]) != NULL ||
841 P2P_MANAGER::instance().FindByPID(pAccountInfo->dwPID[i]) != NULL)
842 kAccountInfo.bIsOnline[i] = true;
843 }
844
845 return kAccountInfo;
846}
847
848void CAdminManager::InitializeBan()
849{
850 m_map_BanChatList.clear();
851 m_map_BanChatListByName.clear();
852 m_map_BanAccountList.clear();
853 m_map_BanAccountListByName.clear();
854 m_map_BanAccountListByPlayerName.clear();
855 m_map_BanAccountListByPlayerID.clear();
856
857 // load ban chat list
858 {
859 std::auto_ptr<SQLMsg> pMsg(DBManager::instance().DirectQuery("SELECT affect.dwPID, player.name, player.job, player.level, player.chatban_count, "
860 "account.ban_count, affect.lDuration FROM player.affect "
861 "INNER JOIN player ON player.id = affect.dwPID "
862 "INNER JOIN %s.account ON account.id = player.account_id "
863 "WHERE affect.bType = %u", g_strAccountDatabaseName.c_str(), AFFECT_BLOCK_CHAT));
864 while (MYSQL_ROW row = mysql_fetch_row(pMsg->Get()->pSQLResult))
865 {
866 int col = 0;
867
868 DWORD dwPID;
869 str_to_number(dwPID, row[col++]);
870
871 TChatBanPlayerInfo& rkPlayerInfo = m_map_BanChatList[dwPID];
872
873 strlcpy(rkPlayerInfo.szName, row[col++], sizeof(rkPlayerInfo.szName));
874 str_to_number(rkPlayerInfo.bRace, row[col++]);
875 str_to_number(rkPlayerInfo.bLevel, row[col++]);
876 str_to_number(rkPlayerInfo.wChatbanCount, row[col++]);
877 str_to_number(rkPlayerInfo.wAccountbanCount, row[col++]);
878 str_to_number(rkPlayerInfo.dwDuration, row[col++]);
879
880 m_map_BanChatListByName[rkPlayerInfo.szName] = dwPID;
881 }
882 }
883
884 // load ban account list
885 {
886 std::auto_ptr<SQLMsg> pMsg(DBManager::instance().DirectQuery("SELECT account.id, account.login, player.id, player.name, player.job, "
887 "player.level, player.chatban_count, account.ban_count, account.status, TIME_TO_SEC(TIMEDIFF(account.availDt, NOW())) "
888 "FROM player.player "
889 "RIGHT JOIN %s.account ON account.id = player.account_id "
890 "WHERE account.`status` = 'BLOCK' OR account.availDt > NOW() "
891 "ORDER BY account.id", g_strAccountDatabaseName.c_str()));
892
893 DWORD dwCurAID = 0;
894 DWORD dwCurPlayerIndex = 0;
895 TAccountBanPlayerInfo* pAccountInfo = NULL;
896 while (MYSQL_ROW row = mysql_fetch_row(pMsg->Get()->pSQLResult))
897 {
898 int col = 0;
899
900 DWORD dwAID;
901 str_to_number(dwAID, row[col++]);
902 char szAccountLogin[LOGIN_MAX_LEN + 1];
903 strlcpy(szAccountLogin, row[col++], sizeof(szAccountLogin));
904
905 if (dwAID != dwCurAID)
906 {
907 dwCurAID = dwAID;
908 dwCurPlayerIndex = 0;
909
910 pAccountInfo = &m_map_BanAccountList[dwAID];
911 memset(pAccountInfo, 0, sizeof(TAccountBanPlayerInfo));
912 strlcpy(pAccountInfo->szLoginName, szAccountLogin, sizeof(pAccountInfo->szLoginName));
913
914 m_map_BanAccountListByName[szAccountLogin] = dwAID;
915 }
916
917 if (row[col])
918 str_to_number(pAccountInfo->dwPID[dwCurPlayerIndex], row[col]);
919 ++col;
920 if (row[col])
921 strlcpy(pAccountInfo->szName[dwCurPlayerIndex], row[col], sizeof(pAccountInfo->szName[dwCurPlayerIndex]));
922 ++col;
923 if (row[col])
924 str_to_number(pAccountInfo->bRace[dwCurPlayerIndex], row[col]);
925 ++col;
926 if (row[col])
927 str_to_number(pAccountInfo->bLevel[dwCurPlayerIndex], row[col]);
928 ++col;
929 if (row[col])
930 str_to_number(pAccountInfo->wChatbanCount[dwCurPlayerIndex], row[col]);
931 ++col;
932
933 str_to_number(pAccountInfo->wAccountbanCount, row[col++]);
934
935 char szStatus[ACCOUNT_STATUS_MAX_LEN + 1];
936 strlcpy(szStatus, row[col++], sizeof(szStatus));
937 if (!strcasecmp(szStatus, "BLOCK"))
938 {
939 pAccountInfo->dwDuration = INT_MAX;
940 }
941 else
942 {
943 DWORD dwDuration;
944 str_to_number(dwDuration, row[col++]);
945
946 pAccountInfo->SetDuration(dwDuration);
947 }
948
949 m_map_BanAccountListByPlayerName[pAccountInfo->szName[dwCurPlayerIndex]] = dwAID;
950 m_map_BanAccountListByPlayerID[pAccountInfo->dwPID[dwCurPlayerIndex]] = dwAID;
951 ++dwCurPlayerIndex;
952 }
953 }
954}
955
956void CAdminManager::SearchBanChatPlayer(LPCHARACTER pkChr, const char* c_pszName)
957{
958 SearchBanChatPlayer(pkChr->GetPlayerID(), c_pszName);
959}
960
961void CAdminManager::SearchBanChatPlayer(DWORD dwGMPid, const char* c_pszName)
962{
963 TBanClientPlayerInfo* pPlayerInfo = NULL;
964
965 LPCHARACTER pkFind = CHARACTER_MANAGER::instance().FindPC(c_pszName);
966 if (pkFind)
967 {
968 pPlayerInfo = &GetBanClientPlayerInfo(pkFind);
969
970 if (CAffect* pkAff = pkFind->FindAffect(AFFECT_BLOCK_CHAT))
971 pPlayerInfo->dwDuration = pkAff->lDuration;
972
973 P2P_SearchBanChatPlayer(dwGMPid, true, pPlayerInfo);
974 }
975 else
976 {
977 TEMP_BUFFER buf;
978 buf.write(&dwGMPid, sizeof(DWORD));
979 int iLen = strlen(c_pszName);
980 buf.write(&iLen, sizeof(int));
981 buf.write(c_pszName, iLen);
982
983 if (CCI* pkCCI = P2P_MANAGER::instance().Find(c_pszName))
984 {
985 SendP2P(pkCCI->pkDesc, P2P_SUBHEADER_BAN_CHAT_SEARCH_PLAYER, buf.read_peek(), buf.size());
986 }
987 else
988 {
989 db_clientdesc->DBPacket(HEADER_GD_ADMIN_MANAGER_CHAT_SEARCH_PLAYER, 0, buf.read_peek(), buf.size());
990 }
991 }
992}
993
994void CAdminManager::P2P_SearchBanChatPlayer(DWORD dwGMPid, bool bSuccess, TBanClientPlayerInfo* pPlayerInfo)
995{
996 if (bSuccess && !pPlayerInfo)
997 {
998 sys_err("invalid call P2P_SearchBanChatPlayer: bSuccess = TRUE pPlayerInfo = NULL");
999 return;
1000 }
1001
1002 TEMP_BUFFER buf;
1003 buf.write(&bSuccess, sizeof(bool));
1004 if (bSuccess)
1005 buf.write(pPlayerInfo, sizeof(TBanClientPlayerInfo));
1006 SendClientPacket(dwGMPid, GC_SUBHEADER_BAN_CHAT_SEARCH_PLAYER, buf.read_peek(), buf.size());
1007}
1008
1009void CAdminManager::SendBanPlayerLog(LPCHARACTER pkChr, DWORD dwPlayerID)
1010{
1011 char szExtraOption[256];
1012 int iExtraOptionLen = snprintf(szExtraOption, sizeof(szExtraOption), "");
1013
1014 if (HasAllow(pkChr, ALLOW_VIEW_BAN_CHAT_LOG))
1015 iExtraOptionLen += snprintf(szExtraOption + iExtraOptionLen, sizeof(szExtraOption) - iExtraOptionLen, " OR `type`=%u",
1016 BAN_TYPE_CHAT);
1017 if (HasAllow(pkChr, ALLOW_VIEW_BAN_ACCOUNT_LOG))
1018 iExtraOptionLen += snprintf(szExtraOption + iExtraOptionLen, sizeof(szExtraOption) - iExtraOptionLen, " OR `type`=%u",
1019 BAN_TYPE_ACCOUNT);
1020
1021 DBManager::instance().ReturnQuery(QID_ADMIN_MANAGER_BAN_LOG, pkChr->GetPlayerID(), new DWORD(dwPlayerID),
1022 "SELECT pid, name, gm_pid, gm_name, `type`+0, new_duration, reason, proof, date FROM log.ban_log WHERE pid = %u "
1023 "AND (FALSE%s) "
1024 "ORDER BY date DESC", dwPlayerID, szExtraOption);
1025}
1026
1027void CAdminManager::CreateAccountBanInfo(TAccountBanPlayerInfo* pInfo, LPCHARACTER pkChr, DWORD dwAID)
1028{
1029 if (!dwAID)
1030 {
1031 if (!pkChr)
1032 {
1033 sys_err("invalid call of CreateAccountBanInfo (no pkChr and no dwAID given)");
1034 return;
1035 }
1036
1037 dwAID = pkChr->GetAID();
1038 }
1039
1040 memset(pInfo, 0, sizeof(TAccountBanPlayerInfo));
1041
1042 std::auto_ptr<SQLMsg> pMsg(DBManager::instance().DirectQuery("SELECT account.login, player.id, player.name, player.job, "
1043 "player.level, player.chatban_count, account.ban_count, account.status, TIME_TO_SEC(TIMEDIFF(account.availDt, NOW())) "
1044 "FROM player.player "
1045 "RIGHT JOIN %s.account ON account.id = player.account_id "
1046 "WHERE player.account_id = %u", g_strAccountDatabaseName.c_str(), dwAID));
1047
1048 DWORD dwCurPlayerIndex = 0;
1049 if (pkChr)
1050 {
1051 pInfo->dwPID[dwCurPlayerIndex] = pkChr->GetPlayerID();
1052 strlcpy(pInfo->szName[dwCurPlayerIndex], pkChr->GetName(), sizeof(pInfo->szName[dwCurPlayerIndex]));
1053 pInfo->bRace[dwCurPlayerIndex] = pkChr->GetRealRaceNum();
1054 pInfo->bLevel[dwCurPlayerIndex] = pkChr->GetLevel();
1055 pInfo->wChatbanCount[dwCurPlayerIndex] = pkChr->GetChatBanCount();
1056 ++dwCurPlayerIndex;
1057 }
1058
1059 while (MYSQL_ROW row = mysql_fetch_row(pMsg->Get()->pSQLResult))
1060 {
1061 int col = 0;
1062
1063 strlcpy(pInfo->szLoginName, row[col++], sizeof(pInfo->szLoginName));
1064
1065 DWORD dwPID = 0;
1066 if (row[col])
1067 str_to_number(dwPID, row[col]);
1068 ++col;
1069
1070 if (dwPID && (!pkChr || dwPID != pkChr->GetPlayerID()))
1071 {
1072 pInfo->dwPID[dwCurPlayerIndex] = dwPID;
1073 if (row[col])
1074 strlcpy(pInfo->szName[dwCurPlayerIndex], row[col], sizeof(pInfo->szName[dwCurPlayerIndex]));
1075 ++col;
1076 if (row[col])
1077 str_to_number(pInfo->bRace[dwCurPlayerIndex], row[col]);
1078 ++col;
1079 if (row[col])
1080 str_to_number(pInfo->bLevel[dwCurPlayerIndex], row[col]);
1081 ++col;
1082 if (row[col])
1083 str_to_number(pInfo->wChatbanCount[dwCurPlayerIndex], row[col]);
1084 ++col;
1085
1086 ++dwCurPlayerIndex;
1087 }
1088 else
1089 {
1090 ++col; // player name
1091 ++col; // player race
1092 ++col; // player level
1093 ++col; // player chatban count
1094 }
1095
1096 str_to_number(pInfo->wAccountbanCount, row[col++]);
1097
1098 char szStatus[ACCOUNT_STATUS_MAX_LEN + 1];
1099 strlcpy(szStatus, row[col++], sizeof(szStatus));
1100 if (!strcasecmp(szStatus, "BLOCK"))
1101 {
1102 pInfo->dwDuration = INT_MAX;
1103 }
1104 else
1105 {
1106 int iDuration;
1107 str_to_number(iDuration, row[col++]);
1108
1109 if (iDuration < 0)
1110 iDuration = 0;
1111
1112 pInfo->SetDuration(iDuration);
1113 }
1114 }
1115}
1116
1117void CAdminManager::DoAccountBan(LPCHARACTER pkChrGM, DWORD dwAID, DWORD dwPlayerID, DWORD dwTimeLeft, const char* c_pszReason, const char* c_pszProof, bool bIncreaseBanCounter)
1118{
1119 LPCHARACTER pkChrTarget = dwPlayerID ? CHARACTER_MANAGER::instance().FindByPID(dwPlayerID) : NULL;
1120 TAccountBanPlayerInfo* pAccountInfo = NULL;
1121 bool bIsLog = false;
1122
1123 int iTimeChange = dwTimeLeft;
1124
1125 // get handle on player info
1126 itertype(m_map_BanAccountList) it = m_map_BanAccountList.find(dwAID);
1127 if (it != m_map_BanAccountList.end())
1128 {
1129 pAccountInfo = &m_map_BanAccountList[dwAID];
1130
1131 iTimeChange = (int)dwTimeLeft - (int)pAccountInfo->GetDuration();
1132 }
1133 else
1134 {
1135 if (!dwTimeLeft)
1136 return;
1137
1138 // create account info
1139 if (pkChrTarget)
1140 {
1141 if (dwAID != pkChrTarget->GetAID())
1142 {
1143 sys_err("invalid aid %u != real aid %u of player %u", dwAID, it->second, dwPlayerID);
1144 return;
1145 }
1146 pAccountInfo = &m_map_BanAccountList[dwAID];
1147 CreateAccountBanInfo(pAccountInfo, pkChrTarget);
1148
1149 if (!*pAccountInfo->szLoginName)
1150 {
1151 m_map_BanAccountList.erase(dwAID);
1152 return;
1153 }
1154 }
1155 else
1156 {
1157 // log
1158 char szTargetName[CHARACTER_NAME_MAX_LEN + 1];
1159 char szLoginName[LOGIN_MAX_LEN + 1];
1160
1161 {
1162 if (dwPlayerID)
1163 {
1164 DWORD dwCompareAID = 0;
1165
1166 std::auto_ptr<SQLMsg> pMsg(DBManager::instance().DirectQuery("SELECT player.name, account.login, account.id FROM player.player "
1167 "INNER JOIN %s.account ON account.id = player.account_id "
1168 "WHERE player.id = %u", g_strAccountDatabaseName.c_str(), dwPlayerID));
1169 if (pMsg->Get()->uiNumRows == 0)
1170 {
1171 if (pkChrGM)
1172 pkChrGM->ChatPacket(CHAT_TYPE_INFO, "The player [%u] could not be found.", dwPlayerID);
1173 return;
1174 }
1175
1176 MYSQL_ROW row = mysql_fetch_row(pMsg->Get()->pSQLResult);
1177 strlcpy(szTargetName, row[0], sizeof(szTargetName));
1178 strlcpy(szLoginName, row[1], sizeof(szLoginName));
1179 str_to_number(dwCompareAID, row[2]);
1180
1181 if (dwAID != dwCompareAID)
1182 {
1183 sys_err("invalid aid %u != real aid %u of player %u", dwAID, dwCompareAID, dwPlayerID);
1184 return;
1185 }
1186 }
1187 else
1188 {
1189 std::auto_ptr<SQLMsg> pMsg(DBManager::instance().DirectQuery("SELECT account.login FROM %s.account WHERE id = %u",
1190 g_strAccountDatabaseName.c_str(), dwAID));
1191 if (pMsg->Get()->uiNumRows == 0)
1192 {
1193 if (pkChrGM)
1194 pkChrGM->ChatPacket(CHAT_TYPE_INFO, "The account [%u] could not be found.", dwAID);
1195 return;
1196 }
1197
1198 MYSQL_ROW row = mysql_fetch_row(pMsg->Get()->pSQLResult);
1199 szTargetName[0] = '\0';
1200 strlcpy(szLoginName, row[0], sizeof(szLoginName));
1201 }
1202
1203 LogManager::instance().AccountBanLog(dwPlayerID, dwAID, szTargetName, pkChrGM, iTimeChange, dwTimeLeft, c_pszReason, c_pszProof, bIncreaseBanCounter);
1204 bIsLog = true;
1205 }
1206
1207 LPDESC pkDesc = DESC_MANAGER::instance().FindByLoginName(szLoginName);
1208 CCI* pkCCI;
1209 if (pkDesc || (!(pkCCI = P2P_MANAGER::instance().FindByPID(dwPlayerID))))
1210 {
1211 pAccountInfo = &m_map_BanAccountList[dwAID];
1212 CreateAccountBanInfo(pAccountInfo, pkDesc ? pkDesc->GetCharacter() : NULL, dwAID);
1213 }
1214 else
1215 {
1216 DWORD dwGMPid = pkChrGM->GetPlayerID();
1217 BYTE bRequestorGMLevel = pkChrGM->GetGMLevel(true);
1218
1219 TEMP_BUFFER buf;
1220 buf.write(&dwGMPid, sizeof(DWORD));
1221 buf.write(&bRequestorGMLevel, sizeof(BYTE));
1222 buf.write(&dwAID, sizeof(DWORD));
1223 int iLen = strlen(szLoginName);
1224 buf.write(&iLen, sizeof(int));
1225 buf.write(szLoginName, iLen);
1226 buf.write(&dwTimeLeft, sizeof(DWORD));
1227 buf.write(&bIncreaseBanCounter, sizeof(bool));
1228 SendP2P(pkCCI->pkDesc, P2P_SUBHEADER_BAN_ACCOUNT_REQUEST, buf.read_peek(), buf.size());
1229
1230 pkChrGM->ChatPacket(CHAT_TYPE_INFO, LC_TEXT(pkChrGM, "A ban request for %s (account %s) to channel %u (port %u) has been sent."),
1231 szTargetName, szLoginName, pkCCI->pkDesc->GetP2PChannel(), pkCCI->pkDesc->GetP2PPort());
1232
1233 return;
1234 }
1235 }
1236 }
1237
1238 // set new duration
1239 DWORD dwOldDuration = pAccountInfo->dwDuration;
1240 pAccountInfo->SetDuration(dwTimeLeft);
1241
1242 // increase ban counter
1243 if (bIncreaseBanCounter)
1244 pAccountInfo->wAccountbanCount++;
1245
1246 // exec ban
1247 if (!__DoAccountBan(dwAID, pAccountInfo, pkChrGM->GetPlayerID(), pkChrGM->GetGMLevel()))
1248 {
1249 pAccountInfo->dwDuration = dwOldDuration;
1250 pAccountInfo->wAccountbanCount--;
1251 return;
1252 }
1253
1254 // log
1255 if (!bIsLog)
1256 LogManager::Instance().AccountBanLog(dwPlayerID, dwAID, pAccountInfo->szName[0], pkChrGM, iTimeChange, dwTimeLeft, c_pszReason, c_pszProof, bIncreaseBanCounter);
1257}
1258
1259void CAdminManager::P2P_DoAccountBan(DWORD dwGMPid, BYTE bRequestorGMLevel, DWORD dwAID, const char* c_pszLoginName, DWORD dwTimeLeft, bool bIncreaseBanCounter)
1260{
1261 TAccountBanPlayerInfo* pAccountInfo = NULL;
1262 itertype(m_map_BanAccountList) it = m_map_BanAccountList.find(dwAID);
1263 if (it != m_map_BanAccountList.end())
1264 {
1265 pAccountInfo = &it->second;
1266 }
1267 else
1268 {
1269 pAccountInfo = &m_map_BanAccountList[dwAID];
1270
1271 LPDESC pkDesc = DESC_MANAGER::instance().FindByLoginName(c_pszLoginName);
1272 CreateAccountBanInfo(pAccountInfo, pkDesc ? pkDesc->GetCharacter() : NULL, dwAID);
1273 if (!*pAccountInfo->szLoginName)
1274 {
1275 m_map_BanAccountList.erase(dwAID);
1276 return;
1277 }
1278 }
1279
1280 // set new duration
1281 DWORD dwOldDuration = pAccountInfo->dwDuration;
1282 pAccountInfo->SetDuration(dwTimeLeft);
1283
1284 // increase ban counter
1285 if (bIncreaseBanCounter)
1286 pAccountInfo->wAccountbanCount++;
1287
1288 // exec ban
1289 if (!__DoAccountBan(dwAID, pAccountInfo, dwGMPid, bRequestorGMLevel))
1290 {
1291 pAccountInfo->dwDuration = dwOldDuration;
1292 pAccountInfo->wAccountbanCount--;
1293 return;
1294 }
1295}
1296
1297#ifndef __WIN32__
1298#define SendGMChatPacket(text, args...) if (pkChrGM) \
1299 pkChrGM->ChatPacket(CHAT_TYPE_INFO, LC_TEXT(pkChrGM, text), ##args);\
1300 else\
1301 P2P_MANAGER::instance().SendChatPacket(dwGMPid, CHAT_TYPE_INFO, text, ##args);
1302#else
1303#define SendGMChatPacket(text, ...) if (pkChrGM) \
1304 pkChrGM->ChatPacket(CHAT_TYPE_INFO, LC_TEXT(pkChrGM, text), __VA_ARGS__);\
1305 else\
1306 P2P_MANAGER::instance().SendChatPacket(dwGMPid, CHAT_TYPE_INFO, text, __VA_ARGS__);
1307#endif // __WIN32__
1308bool CAdminManager::__DoAccountBan(DWORD dwAID, TAccountBanPlayerInfo* pAccountInfo, DWORD dwGMPid, BYTE bRequestorGMLevel)
1309{
1310 // get gm char
1311 LPCHARACTER pkChrGM = CHARACTER_MANAGER::instance().FindByPID(dwGMPid);
1312
1313 // check gm levels
1314 BYTE bTargetGMLevel = GM_PLAYER;
1315 for (int i = 0; i < PLAYER_PER_ACCOUNT; ++i)
1316 {
1317 if (!pAccountInfo->dwPID[i])
1318 continue;
1319
1320 BYTE bGMLevel = GM::get_level(pAccountInfo->szName[i], NULL, true);
1321 if (bGMLevel > bTargetGMLevel)
1322 bTargetGMLevel = bGMLevel;
1323 }
1324 if (bTargetGMLevel > GM_PLAYER)
1325 {
1326 if (bTargetGMLevel == GM_IMPLEMENTOR || bRequestorGMLevel < GM_IMPLEMENTOR)
1327 {
1328 SendGMChatPacket("You cannot ban accounts of the team.");
1329 return false;
1330 }
1331 }
1332
1333 // disconnect account
1334 if (pAccountInfo->GetDuration())
1335 {
1336 LPDESC pkDesc = DESC_MANAGER::instance().FindByLoginName(pAccountInfo->szLoginName);
1337 if (pkDesc)
1338 {
1339 if (ADMIN_MANAGER_DISCONNECT_ON_BAN_DELAY)
1340 {
1341 if (pkDesc->GetCharacter())
1342 pkDesc->GetCharacter()->ChatPacket(CHAT_TYPE_INFO,
1343 LC_TEXT(pkDesc->GetCharacter(), "Your account has been blocked. You will be disconnected within %d seconds."),
1344 ADMIN_MANAGER_DISCONNECT_ON_BAN_DELAY);
1345 pkDesc->DelayedDisconnect(ADMIN_MANAGER_DISCONNECT_ON_BAN_DELAY);
1346 }
1347 else
1348 {
1349 pkDesc->SetPhase(PHASE_CLOSE);
1350 }
1351
1352 if (pkDesc->GetCharacter())
1353 {
1354 SendGMChatPacket("The player [%s] of account [%s] has been disconnected.",
1355 pkDesc->GetCharacter()->GetName(), pAccountInfo->szLoginName);
1356 }
1357 else
1358 {
1359 SendGMChatPacket("The account [%s] has been disconnected.", pAccountInfo->szLoginName);
1360 }
1361 }
1362 else
1363 {
1364 int iLen = strlen(pAccountInfo->szLoginName);
1365
1366 TEMP_BUFFER buf;
1367 buf.write(&iLen, sizeof(int));
1368 buf.write(pAccountInfo->szLoginName, iLen);
1369 SendP2P(NULL, P2P_SUBHEADER_BAN_ACCOUNT_DISCONNECT, buf.read_peek(), buf.size());
1370
1371 SendGMChatPacket("A disconnect request for all cores of account [%s] has been sent.", pAccountInfo->szLoginName);
1372 }
1373 }
1374
1375 // update account table
1376 SQLMsg* pMsg = NULL;
1377 if (pAccountInfo->GetDuration() < INT_MAX)
1378 {
1379 pMsg = DBManager::instance().DirectQuery("UPDATE %s.account SET "
1380 "account.status = 'OK', account.availDt = DATE_ADD(NOW(), INTERVAL %u SECOND), ban_count = %u "
1381 "WHERE account.id = %u", g_strAccountDatabaseName.c_str(), pAccountInfo->GetDuration(), pAccountInfo->wAccountbanCount, dwAID);
1382 }
1383 else
1384 {
1385 pMsg = DBManager::instance().DirectQuery("UPDATE %s.account SET "
1386 "account.status = 'BLOCK', account.availDt = NOW(), ban_count = %u "
1387 "WHERE account.id = %u", g_strAccountDatabaseName.c_str(), pAccountInfo->wAccountbanCount, dwAID);
1388 }
1389
1390 if (pMsg->Get()->uiAffectedRows == 0)
1391 {
1392 SendGMChatPacket("The ban request failed somehow. If the problem happens again report it.");
1393 delete pMsg;
1394 return false;
1395 }
1396 delete pMsg;
1397
1398 // get client info table
1399 TBanClientAccountInfo& rkClientInfo = GetBanClientAccountInfo(dwAID, pAccountInfo);
1400
1401 // p2p
1402 SendP2P(NULL, P2P_SUBHEADER_BAN_ACCOUNTBAN, &rkClientInfo, sizeof(TBanClientAccountInfo));
1403
1404 // event
1405 OnPlayerAccountban(&rkClientInfo);
1406
1407 return true;
1408}
1409#undef SendGMChatPacket
1410
1411void CAdminManager::P2P_DoAccountBanDisconnect(const char* c_pszLoginName)
1412{
1413 LPDESC pkDesc = DESC_MANAGER::instance().FindByLoginName(c_pszLoginName);
1414 if (pkDesc)
1415 {
1416 if (ADMIN_MANAGER_DISCONNECT_ON_BAN_DELAY)
1417 {
1418 if (pkDesc->GetCharacter())
1419 pkDesc->GetCharacter()->ChatPacket(CHAT_TYPE_INFO,
1420 LC_TEXT(pkDesc->GetCharacter(), "Your account has been blocked. You will be disconnected within %d seconds."),
1421 ADMIN_MANAGER_DISCONNECT_ON_BAN_DELAY);
1422 pkDesc->DelayedDisconnect(ADMIN_MANAGER_DISCONNECT_ON_BAN_DELAY);
1423 }
1424 else
1425 {
1426 pkDesc->SetPhase(PHASE_CLOSE);
1427 }
1428 }
1429}
1430
1431void CAdminManager::SearchBanAccount(LPCHARACTER pkChr, const char* c_pszName, BYTE bSearchType)
1432{
1433 SearchBanAccount(pkChr->GetPlayerID(), c_pszName, bSearchType);
1434}
1435
1436void CAdminManager::SearchBanAccount(DWORD dwGMPid, const char* c_pszName, BYTE bSearchType)
1437{
1438 static TAccountBanPlayerInfo skAccountInfo;
1439 DWORD dwAID = 0;
1440 TAccountBanPlayerInfo* pAccountInfo = NULL;
1441
1442 if (bSearchType == BAN_ACCOUNT_SEARCH_ACCOUNT)
1443 {
1444 itertype(m_map_BanAccountListByName) it = m_map_BanAccountListByName.find(c_pszName);
1445 if (it != m_map_BanAccountListByName.end())
1446 {
1447 dwAID = it->second;
1448 pAccountInfo = &m_map_BanAccountList[dwAID];
1449 }
1450 else
1451 {
1452 pAccountInfo = &skAccountInfo;
1453
1454 LPDESC pkDesc = DESC_MANAGER::instance().FindByLoginName(c_pszName);
1455 if (pkDesc)
1456 dwAID = pkDesc->GetAccountTable().id;
1457 else
1458 {
1459 char szEscapedLogin[LOGIN_MAX_LEN * 2 + 1];
1460 DBManager::instance().EscapeString(szEscapedLogin, sizeof(szEscapedLogin), c_pszName, strlen(c_pszName));
1461 std::auto_ptr<SQLMsg> pMsg(DBManager::instance().DirectQuery("SELECT id FROM %s.account WHERE login = '%s'",
1462 g_strAccountDatabaseName.c_str(), szEscapedLogin));
1463 if (pMsg->Get()->uiNumRows == 0)
1464 {
1465 P2P_SearchBanAccount(dwGMPid, false, NULL);
1466 return;
1467 }
1468 str_to_number(dwAID, mysql_fetch_row(pMsg->Get()->pSQLResult)[0]);
1469 }
1470
1471 CreateAccountBanInfo(pAccountInfo, pkDesc ? pkDesc->GetCharacter() : NULL, dwAID);
1472 }
1473 }
1474 else if (bSearchType == BAN_ACCOUNT_SEARCH_PLAYER)
1475 {
1476 itertype(m_map_BanAccountListByPlayerName) it = m_map_BanAccountListByPlayerName.find(c_pszName);
1477 if (it != m_map_BanAccountListByPlayerName.end())
1478 {
1479 dwAID = it->second;
1480 pAccountInfo = &m_map_BanAccountList[dwAID];
1481 }
1482 else
1483 {
1484 pAccountInfo = &skAccountInfo;
1485
1486 LPCHARACTER pkChr = CHARACTER_MANAGER::instance().FindPC(c_pszName);
1487 if (pkChr)
1488 {
1489 dwAID = pkChr->GetAID();
1490 CreateAccountBanInfo(pAccountInfo, pkChr);
1491 }
1492 else
1493 {
1494 CCI* pkCCI = P2P_MANAGER::instance().Find(c_pszName);
1495 if (pkCCI)
1496 {
1497 TEMP_BUFFER buf;
1498 buf.write(&dwGMPid, sizeof(DWORD));
1499 int iLen = strlen(c_pszName);
1500 buf.write(&iLen, sizeof(int));
1501 buf.write(c_pszName, iLen);
1502 buf.write(&bSearchType, sizeof(BYTE));
1503
1504 SendP2P(pkCCI->pkDesc, P2P_SUBHEADER_BAN_ACCOUNT_SEARCH, buf.read_peek(), buf.size());
1505 return;
1506 }
1507 else
1508 {
1509 char szEscapedName[CHARACTER_NAME_MAX_LEN * 2 + 1];
1510 DBManager::instance().EscapeString(szEscapedName, sizeof(szEscapedName), c_pszName, strlen(c_pszName));
1511 std::auto_ptr<SQLMsg> pMsg(DBManager::instance().DirectQuery("SELECT account_id FROM player WHERE name = '%s'", szEscapedName));
1512 if (pMsg->Get()->uiNumRows == 0)
1513 {
1514 P2P_SearchBanAccount(dwGMPid, false, NULL);
1515 return;
1516 }
1517 str_to_number(dwAID, mysql_fetch_row(pMsg->Get()->pSQLResult)[0]);
1518
1519 CreateAccountBanInfo(pAccountInfo, NULL, dwAID);
1520 }
1521 }
1522 }
1523 }
1524
1525 P2P_SearchBanAccount(dwGMPid, dwAID != 0, &GetBanClientAccountInfo(dwAID, pAccountInfo));
1526}
1527
1528void CAdminManager::P2P_SearchBanAccount(DWORD dwGMPid, bool bSuccess, TBanClientAccountInfo* pAccountInfo)
1529{
1530 if (bSuccess && !pAccountInfo)
1531 {
1532 sys_err("invalid call P2P_SearchBanAccount: bSuccess = TRUE pAccountInfo = NULL");
1533 return;
1534 }
1535
1536 TEMP_BUFFER buf;
1537 buf.write(&bSuccess, sizeof(bool));
1538 if (bSuccess)
1539 buf.write(pAccountInfo, sizeof(TBanClientAccountInfo));
1540 SendClientPacket(dwGMPid, GC_SUBHEADER_BAN_ACCOUNT_SEARCH, buf.read_peek(), buf.size());
1541}
1542
1543void CAdminManager::SendBanAccountLog(LPCHARACTER pkChr, DWORD dwAccountID)
1544{
1545 char szExtraOption[256];
1546 int iExtraOptionLen = snprintf(szExtraOption, sizeof(szExtraOption), "");
1547
1548 if (HasAllow(pkChr, ALLOW_VIEW_BAN_CHAT_LOG))
1549 iExtraOptionLen += snprintf(szExtraOption + iExtraOptionLen, sizeof(szExtraOption) - iExtraOptionLen, " OR `type`=%u",
1550 BAN_TYPE_CHAT);
1551 if (HasAllow(pkChr, ALLOW_VIEW_BAN_ACCOUNT_LOG))
1552 iExtraOptionLen += snprintf(szExtraOption + iExtraOptionLen, sizeof(szExtraOption) - iExtraOptionLen, " OR `type`=%u",
1553 BAN_TYPE_ACCOUNT);
1554
1555 DBManager::instance().ReturnQuery(QID_ADMIN_MANAGER_BAN_LOG, pkChr->GetPlayerID(), new DWORD(dwAccountID),
1556 "SELECT pid, name, gm_pid, gm_name, `type`+0, new_duration, reason, proof, date FROM log.ban_log WHERE aid = %u "
1557 "AND (FALSE%s) "
1558 "ORDER BY date DESC", dwAccountID, szExtraOption);
1559}
1560
1561/*******************************************************************\
1562| [PUBLIC] Ban Event Functions
1563\*******************************************************************/
1564
1565void CAdminManager::Ban_OnPlayerLogin(DWORD dwPID)
1566{
1567 itertype(m_map_BanChatList) it = m_map_BanChatList.find(dwPID);
1568 if (it == m_map_BanChatList.end())
1569 return;
1570 it->second.SetOnline();
1571}
1572
1573void CAdminManager::Ban_OnPlayerLogout(DWORD dwPID)
1574{
1575 itertype(m_map_BanChatList) it = m_map_BanChatList.find(dwPID);
1576 if (it == m_map_BanChatList.end())
1577 return;
1578 it->second.SetOffline();
1579}
1580
1581void CAdminManager::Ban_OnPlayerChatban(LPCHARACTER pkChr, DWORD dwTimeLeft)
1582{
1583 TBanClientPlayerInfo& rkPlayerInfo = GetBanClientPlayerInfo(pkChr, dwTimeLeft);
1584
1585 SendP2P(NULL, P2P_SUBHEADER_BAN_PLAYER_CHATBAN, &rkPlayerInfo, sizeof(TBanClientPlayerInfo));
1586 Ban_OnPlayerChatban(&rkPlayerInfo);
1587}
1588
1589void CAdminManager::Ban_OnPlayerChatban(const char* c_pszName, DWORD dwTimeLeft, bool bIncreaseBanCounter)
1590{
1591 TBanClientPlayerInfo* pPlayerInfo = NULL;
1592
1593 itertype(m_map_BanChatListByName) it = m_map_BanChatListByName.find(c_pszName);
1594 if (it != m_map_BanChatListByName.end())
1595 {
1596 itertype(m_map_BanChatList) it2 = m_map_BanChatList.find(it->second);
1597 if (it2 != m_map_BanChatList.end())
1598 pPlayerInfo = &GetBanClientPlayerInfo(it2->first, &it2->second);
1599 }
1600
1601 if (!pPlayerInfo)
1602 {
1603 if (!dwTimeLeft)
1604 return;
1605
1606 LPCHARACTER pkChr = CHARACTER_MANAGER::instance().FindPC(c_pszName);
1607 if (pkChr)
1608 pPlayerInfo = &GetBanClientPlayerInfo(pkChr, dwTimeLeft);
1609 else
1610 {
1611 char szEscapeName[CHARACTER_NAME_MAX_LEN * 2 + 1];
1612 DBManager::instance().EscapeString(szEscapeName, sizeof(szEscapeName), c_pszName, strlen(c_pszName));
1613
1614 std::auto_ptr<SQLMsg> pMsg(DBManager::instance().DirectQuery("SELECT player.id, player.name, player.job, player.level, "
1615 "player.chatban_count, account.ban_count "
1616 "FROM player INNER JOIN %s.account ON account.id = player.account_id WHERE name = '%s'",
1617 g_strAccountDatabaseName.c_str(), szEscapeName));
1618 if (!pMsg->Get()->uiNumRows)
1619 {
1620 sys_err("cannot get player by name %s [%s] - cannot add to chat ban list", c_pszName, szEscapeName);
1621 return;
1622 }
1623
1624 MYSQL_ROW row = mysql_fetch_row(pMsg->Get()->pSQLResult);
1625 int col = 0;
1626 pPlayerInfo = &GetBanClientPlayerInfo(NULL);
1627
1628 str_to_number(pPlayerInfo->dwPID, row[col++]);
1629 strlcpy(pPlayerInfo->szName, row[col++], sizeof(pPlayerInfo->szName));
1630 str_to_number(pPlayerInfo->bRace, row[col++]);
1631 str_to_number(pPlayerInfo->bLevel, row[col++]);
1632 str_to_number(pPlayerInfo->wChatbanCount, row[col++]);
1633 str_to_number(pPlayerInfo->wAccountbanCount, row[col++]);
1634 pPlayerInfo->dwDuration = dwTimeLeft;
1635 }
1636 }
1637 else
1638 {
1639 pPlayerInfo->dwDuration = dwTimeLeft;
1640
1641 if (bIncreaseBanCounter)
1642 pPlayerInfo->wChatbanCount++;
1643 }
1644
1645 SendP2P(NULL, P2P_SUBHEADER_BAN_PLAYER_CHATBAN, pPlayerInfo, sizeof(TBanClientPlayerInfo));
1646 Ban_OnPlayerChatban(pPlayerInfo);
1647}
1648
1649void CAdminManager::Ban_OnPlayerChatban(const TBanClientPlayerInfo* pPlayerInfo)
1650{
1651 if (!pPlayerInfo->dwDuration)
1652 {
1653 if (m_map_BanChatList.find(pPlayerInfo->dwPID) == m_map_BanChatList.end())
1654 return;
1655
1656 m_map_BanChatListByName.erase(pPlayerInfo->szName);
1657 m_map_BanChatList.erase(pPlayerInfo->dwPID);
1658 }
1659 else
1660 {
1661 TChatBanPlayerInfo& rkPlayerInfo = m_map_BanChatList[pPlayerInfo->dwPID];
1662 strlcpy(rkPlayerInfo.szName, pPlayerInfo->szName, sizeof(rkPlayerInfo.szName));
1663 rkPlayerInfo.bRace = pPlayerInfo->bRace;
1664 rkPlayerInfo.bLevel = pPlayerInfo->bLevel;
1665 rkPlayerInfo.wChatbanCount = pPlayerInfo->wChatbanCount;
1666 rkPlayerInfo.wAccountbanCount = pPlayerInfo->wAccountbanCount;
1667
1668 if (CHARACTER_MANAGER::instance().FindByPID(pPlayerInfo->dwPID) || P2P_MANAGER::instance().FindByPID(pPlayerInfo->dwPID))
1669 rkPlayerInfo.SetOnline();
1670 else if (rkPlayerInfo.IsOnline())
1671 rkPlayerInfo.SetOffline();
1672 rkPlayerInfo.SetDuration(pPlayerInfo->dwDuration);
1673
1674 m_map_BanChatListByName[rkPlayerInfo.szName] = pPlayerInfo->dwPID;
1675 }
1676
1677 for (itertype(m_set_ActivePIDs) it = m_set_ActivePIDs.begin(); it != m_set_ActivePIDs.end(); ++it)
1678 {
1679 if (HasAllow(GetTeamRankByPID(*it), ALLOW_VIEW_BAN_CHAT))
1680 SendClientPacket(*it, GC_SUBHEADER_BAN_CHAT_STATE, pPlayerInfo, sizeof(TBanClientPlayerInfo));
1681 }
1682}
1683
1684void CAdminManager::Ban_OnPlayerAccountban(const TBanClientAccountInfo* pAccountInfo)
1685{
1686 if (!pAccountInfo->dwDuration)
1687 {
1688 if (m_map_BanAccountList.find(pAccountInfo->dwAID) == m_map_BanAccountList.end())
1689 return;
1690
1691 for (int i = 0; i < PLAYER_PER_ACCOUNT; ++i)
1692 {
1693 if (pAccountInfo->dwPID[i])
1694 {
1695 m_map_BanAccountListByPlayerName.erase(pAccountInfo->szName[i]);
1696 m_map_BanAccountListByPlayerID.erase(pAccountInfo->dwPID[i]);
1697 }
1698 }
1699 m_map_BanAccountListByName.erase(pAccountInfo->szLoginName);
1700 m_map_BanAccountList.erase(pAccountInfo->dwAID);
1701 }
1702 else
1703 {
1704 if (LPDESC pkDesc = DESC_MANAGER::instance().FindByLoginName(pAccountInfo->szLoginName))
1705 pkDesc->GetAccountTable().accban_count = pAccountInfo->wAccountbanCount;
1706
1707 TAccountBanPlayerInfo& rkAccountInfo = m_map_BanAccountList[pAccountInfo->dwAID];
1708 strlcpy(rkAccountInfo.szLoginName, pAccountInfo->szLoginName, sizeof(rkAccountInfo.szLoginName));
1709 for (int i = 0; i < PLAYER_PER_ACCOUNT; ++i)
1710 {
1711 rkAccountInfo.dwPID[i] = pAccountInfo->dwPID[i];
1712 strlcpy(rkAccountInfo.szName[i], pAccountInfo->szName[i], sizeof(rkAccountInfo.szName));
1713 rkAccountInfo.bRace[i] = pAccountInfo->bRace[i];
1714 rkAccountInfo.bLevel[i] = pAccountInfo->bLevel[i];
1715 rkAccountInfo.wChatbanCount[i] = pAccountInfo->wChatbanCount[i];
1716
1717 if (rkAccountInfo.dwPID[i])
1718 {
1719 m_map_BanAccountListByPlayerName[rkAccountInfo.szName[i]] = pAccountInfo->dwAID;
1720 m_map_BanAccountListByPlayerID[rkAccountInfo.dwPID[i]] = pAccountInfo->dwAID;
1721 }
1722 }
1723 rkAccountInfo.wAccountbanCount = pAccountInfo->wAccountbanCount;
1724 rkAccountInfo.SetDuration(pAccountInfo->dwDuration);
1725
1726 m_map_BanAccountListByName[rkAccountInfo.szLoginName] = pAccountInfo->dwAID;
1727 }
1728
1729 for (itertype(m_set_ActivePIDs) it = m_set_ActivePIDs.begin(); it != m_set_ActivePIDs.end(); ++it)
1730 {
1731 if (HasAllow(GetTeamRankByPID(*it), ALLOW_VIEW_BAN_ACCOUNT))
1732 SendClientPacket(*it, GC_SUBHEADER_BAN_ACCOUNT_STATE, pAccountInfo, sizeof(TBanClientAccountInfo));
1733 }
1734}
1735
1736/*******************************************************************\
1737| [PUBLIC] Item Functions
1738\*******************************************************************/
1739
1740void CAdminManager::SearchItem(LPCHARACTER pkChr, BYTE bSearchType, const char* c_pszData)
1741{
1742 char szQuery[2048];
1743 int iQueryLen = snprintf(szQuery, sizeof(szQuery), "SELECT player.id, player.name, account.id, account.login, "
1744 "item.id, item.window+0, item.pos, item.vnum, item.count, item.is_gm_owner, ");
1745 for (int i = 0; i < ITEM_SOCKET_MAX_NUM; ++i)
1746 iQueryLen += snprintf(szQuery + iQueryLen, sizeof(szQuery) - iQueryLen, "item.socket%d, ", i);
1747 for (int i = 0; i < ITEM_ATTRIBUTE_MAX_NUM; ++i)
1748 iQueryLen += snprintf(szQuery + iQueryLen, sizeof(szQuery) - iQueryLen, "item.attrtype%d, item.attrvalue%d, ", i, i);
1749 iQueryLen += snprintf(szQuery + iQueryLen - 2, sizeof(szQuery) - iQueryLen + 2, " "
1750 "FROM item LEFT JOIN player ON player.id = item.owner_id LEFT JOIN %s.account ON account.id = item.owner_id "
1751 "LEFT JOIN item_proto ON item_proto.vnum = item.vnum WHERE ", g_strAccountDatabaseName.c_str());
1752
1753 char szEscapedData[100];
1754 if (c_pszData)
1755 DBManager::instance().EscapeString(szEscapedData, sizeof(szEscapedData), c_pszData, strlen(c_pszData));
1756
1757 switch (bSearchType)
1758 {
1759 case ITEM_SEARCH_IID:
1760 snprintf(szQuery + iQueryLen, sizeof(szQuery) - iQueryLen, "item.id = '%s'", szEscapedData);
1761 break;
1762
1763 case ITEM_SEARCH_INAME:
1764 snprintf(szQuery + iQueryLen, sizeof(szQuery) - iQueryLen, "item_proto.locale_name_%s LIKE '%%%s%%'", CLocaleManager::instance().GetLanguageName(pkChr->GetLanguageID()), szEscapedData);
1765 break;
1766
1767 case ITEM_SEARCH_PID:
1768 snprintf(szQuery + iQueryLen, sizeof(szQuery) - iQueryLen, "item.owner_id = '%s' AND item.window != %u AND item.window != %u",
1769 szEscapedData, SAFEBOX, MALL);
1770 break;
1771
1772 case ITEM_SEARCH_PNAME:
1773 snprintf(szQuery + iQueryLen, sizeof(szQuery) - iQueryLen, "player.name = '%s'", szEscapedData);
1774 break;
1775
1776 case ITEM_SEARCH_GM_ITEM:
1777 snprintf(szQuery + iQueryLen, sizeof(szQuery) - iQueryLen, "item.is_gm_owner = 1");
1778 break;
1779
1780 default:
1781 sys_err("invalid search type %u", bSearchType);
1782 return;
1783 }
1784
1785 DBManager::instance().ReturnQuery(QID_ADMIN_MANAGER_ITEM_SEARCH, pkChr->GetPlayerID(), NULL, "%s", szQuery);
1786}
1787
1788/*******************************************************************\
1789| [PUBLIC] Client Packet Functions
1790\*******************************************************************/
1791
1792void CAdminManager::SendLoadPacket(LPCHARACTER pkChr)
1793{
1794 TPacketGCAdminManagerLoad packet;
1795 packet.header = HEADER_GC_ADMIN_MANAGER_LOAD;
1796
1797 // send allow flag
1798 packet.dwAllowFlag = GetAllow(pkChr);
1799
1800 // get online player
1801 std::vector<TAdminManagerPlayerInfo> vec_PlayerInfo;
1802 vec_PlayerInfo.push_back(GetPlayerInfo(pkChr));
1803 packet.dwPlayerCount = GetPlayerInfoList(vec_PlayerInfo);
1804 packet.bIsGMItemTradeBlock = HasAllow(pkChr, ALLOW_GM_TRADE_BLOCK_OPTION) ? quest::CQuestManager::instance().GetEventFlag(EVENT_FLAG_GM_ITEM_TRADE_BLOCK) != 0 : false;
1805 packet.dwBanChatCount = m_map_BanChatList.size();
1806 packet.dwBanAccountCount = m_map_BanAccountList.size();
1807 // check right
1808 if (!HasAllow(pkChr, ALLOW_VIEW_ONLINE_COUNT))
1809 packet.dwPlayerCount = 0;
1810 if (!HasAllow(pkChr, ALLOW_VIEW_BAN_CHAT))
1811 packet.dwBanChatCount = 0;
1812 if (!HasAllow(pkChr, ALLOW_VIEW_BAN_ACCOUNT))
1813 packet.dwBanAccountCount = 0;
1814
1815 // set packet size
1816 packet.size = sizeof(TPacketGCAdminManagerLoad) +
1817 sizeof(TAdminManagerPlayerInfo) * packet.dwPlayerCount +
1818 sizeof(TBanClientPlayerInfo) * packet.dwBanChatCount +
1819 sizeof(TBanClientAccountInfo) * packet.dwBanAccountCount;
1820
1821 // create buffer with entire packet
1822 TEMP_BUFFER buf;
1823 buf.write(&packet, sizeof(packet));
1824 if (HasAllow(pkChr, ALLOW_VIEW_ONLINE_LIST))
1825 buf.write(&vec_PlayerInfo[0], sizeof(TAdminManagerPlayerInfo) * packet.dwPlayerCount);
1826 if (HasAllow(pkChr, ALLOW_VIEW_BAN_CHAT))
1827 {
1828 for (itertype(m_map_BanChatList) it = m_map_BanChatList.begin(); it != m_map_BanChatList.end(); ++it)
1829 {
1830 buf.write(&GetBanClientPlayerInfo(it->first, &it->second), sizeof(TBanClientPlayerInfo));
1831 }
1832 }
1833 if (HasAllow(pkChr, ALLOW_VIEW_BAN_ACCOUNT))
1834 {
1835 for (itertype(m_map_BanAccountList) it = m_map_BanAccountList.begin(); it != m_map_BanAccountList.end(); ++it)
1836 {
1837 buf.write(&GetBanClientAccountInfo(it->first, &it->second), sizeof(TBanClientAccountInfo));
1838 }
1839 }
1840
1841 // send
1842 pkChr->GetDesc()->Packet(buf.read_peek(), buf.size());
1843}
1844
1845void CAdminManager::SendMapViewerLoadPacket(DWORD dwPID, long lMapIndex)
1846{
1847 LPSECTREE_MAP pkMap = SECTREE_MANAGER::instance().GetMap(lMapIndex);
1848 if (!pkMap)
1849 {
1850 sys_err("cannot send load packet pid %u [map %ld does not exists]", dwPID, lMapIndex);
1851 return;
1852 }
1853
1854 DWORD dwTempCount = 0;
1855
1856 TEMP_BUFFER buf;
1857 PIXEL_POSITION kBasePos;
1858 char* szWritePoint;
1859
1860 // write base coord
1861 if (!SECTREE_MANAGER::instance().GetMapBasePositionByMapIndex(lMapIndex, kBasePos))
1862 {
1863 sys_err("cannot get base position of map %ld (request pid %u)", lMapIndex, dwPID);
1864 return;
1865 }
1866 buf.write(&kBasePos.x, sizeof(kBasePos.x));
1867 buf.write(&kBasePos.y, sizeof(kBasePos.y));
1868
1869 if (HasAllow(GetTeamRankByPID(dwPID), ALLOW_VIEW_MAPVIEWER_PLAYER))
1870 {
1871 // write player
1872 buf.write(&dwTempCount, sizeof(DWORD));
1873 FMapViewerLoadPlayer fLoadPlayer(buf);
1874 pkMap->for_each(fLoadPlayer);
1875 // update count
1876 szWritePoint = buf.getptr()->write_point - sizeof(TAdminManagerMapViewerPlayerInfo)* fLoadPlayer.m_dwCount - sizeof(DWORD);
1877 memcpy(szWritePoint, &fLoadPlayer.m_dwCount, sizeof(DWORD));
1878 }
1879
1880 if (HasAllow(GetTeamRankByPID(dwPID), ALLOW_VIEW_MAPVIEWER_MONSTER | ALLOW_VIEW_MAPVIEWER_NPC | ALLOW_VIEW_MAPVIEWER_STONE))
1881 {
1882 // write mobs
1883 buf.write(&dwTempCount, sizeof(DWORD));
1884 FMapViewerLoadMob fLoadMob(buf, GetAllow(GetTeamRankByPID(dwPID)));
1885 pkMap->for_each(fLoadMob);
1886 // update count
1887 szWritePoint = buf.getptr()->write_point - sizeof(TAdminManagerMapViewerMobInfo) * fLoadMob.m_dwCount - sizeof(DWORD);
1888 memcpy(szWritePoint, &fLoadMob.m_dwCount, sizeof(DWORD));
1889 }
1890
1891 // send packet
1892 SendClientPacket(dwPID, GC_SUBHEADER_MAPVIEWER_LOAD, buf.read_peek(), buf.size());
1893}
1894
1895void CAdminManager::EncodeObserverItemPacket(TAdminManagerObserverItemInfo& rkItemInfo, LPITEM pkItem)
1896{
1897 rkItemInfo.id = pkItem->GetID();
1898 rkItemInfo.vnum = pkItem->GetVnum();
1899 rkItemInfo.count = pkItem->GetCount();
1900 rkItemInfo.cell = pkItem->GetCell();
1901 memcpy(rkItemInfo.alSockets, pkItem->GetSockets(), sizeof(rkItemInfo.alSockets));
1902 memcpy(rkItemInfo.aAttr, pkItem->GetAttributes(), sizeof(rkItemInfo.aAttr));
1903 rkItemInfo.is_gm_item = pkItem->IsGMOwner();
1904}
1905
1906int CAdminManager::EncodeObserverWhisperPacket(TEMP_BUFFER& rBuf, unsigned char bSubHeader, DWORD dwOtherPID, DWORD dwElapsedTime, const char* szMessage)
1907{
1908 int iTextLen = strlen(szMessage);
1909
1910 if (bSubHeader)
1911 rBuf.write(&bSubHeader, sizeof(unsigned char));
1912 rBuf.write(&dwOtherPID, sizeof(DWORD));
1913 rBuf.write(&dwElapsedTime, sizeof(DWORD));
1914 rBuf.write(&iTextLen, sizeof(int));
1915 rBuf.write(szMessage, iTextLen);
1916
1917 return (bSubHeader ? sizeof(unsigned char) : 0) + sizeof(DWORD) + sizeof(DWORD) + sizeof(int) + iTextLen;
1918}
1919
1920void CAdminManager::SendObserverLoadPacket(DWORD dwPID, LPCHARACTER pkPlayer)
1921{
1922 DWORD dwTempCount = 0;
1923
1924 TEMP_BUFFER buf;
1925 char* szWritePoint;
1926
1927 // main information
1928 DWORD dwPlayerPID = pkPlayer->GetPlayerID(); // pid
1929 buf.write(&dwPlayerPID, sizeof(DWORD));
1930 DWORD dwAccountID = pkPlayer->GetAID();
1931 buf.write(&dwAccountID, sizeof(DWORD));
1932 unsigned char bRaceNum = pkPlayer->GetRealRaceNum();
1933 buf.write(&bRaceNum, sizeof(unsigned char));
1934 int iAccountNameLen = strlen(pkPlayer->GetDesc()->GetAccountTable().login);
1935 buf.write(&iAccountNameLen, sizeof(int));
1936 buf.write(pkPlayer->GetDesc()->GetAccountTable().login, iAccountNameLen);
1937 const PIXEL_POSITION& kPos = pkPlayer->GetXYZ();
1938 buf.write(&kPos.x, sizeof(kPos.x)); // x-position
1939 buf.write(&kPos.y, sizeof(kPos.y)); // y-position
1940
1941 // skills
1942 if (HasAllow(GetTeamRankByPID(dwPID), ALLOW_VIEW_OBSERVER_SKILL))
1943 {
1944 unsigned char bSkillGroup = pkPlayer->GetSkillGroup();
1945 buf.write(&bSkillGroup, sizeof(unsigned char));
1946 buf.write(pkPlayer->GetPlayerSkills(), sizeof(TPlayerSkill) * SKILL_MAX_NUM);
1947 }
1948
1949 // points
1950 buf.write(&dwTempCount, sizeof(DWORD));
1951 int iPointCount = 0;
1952 for (int i = 0; i < POINT_MAX_NUM; ++i)
1953 {
1954 if (IsObserverUpdatePoint(i) && (i != POINT_GOLD || HasAllow(GetTeamRankByPID(dwPID), ALLOW_VIEW_OBSERVER_GOLD)))
1955 {
1956 unsigned char bType = i;
1957 buf.write(&bType, sizeof(unsigned char));
1958 int iValue = pkPlayer->GetConvPoint(bType);
1959 buf.write(&iValue, sizeof(int));
1960 ++iPointCount;
1961 }
1962 }
1963 szWritePoint = buf.getptr()->write_point - (sizeof(unsigned char) + sizeof(int)) * iPointCount - sizeof(DWORD);
1964 memcpy(szWritePoint, &iPointCount, sizeof(DWORD));
1965
1966 // inventory
1967 if (HasAllow(GetTeamRankByPID(dwPID), ALLOW_VIEW_OBSERVER_INVENTORY | ALLOW_VIEW_OBSERVER_EQUIPMENT))
1968 {
1969 buf.write(&dwTempCount, sizeof(DWORD));
1970 int iItemCount = 0;
1971 for (int i = 0; i < INVENTORY_AND_EQUIP_SLOT_MAX; ++i)
1972 {
1973 bool bIsInventory = i < INVENTORY_MAX_NUM2 || i >= INVENTORY_MAX_NUM2 + WEAR_MAX_NUM;
1974 if ((bIsInventory && !HasAllow(GetTeamRankByPID(dwPID), ALLOW_VIEW_OBSERVER_INVENTORY)) ||
1975 (!bIsInventory && !HasAllow(GetTeamRankByPID(dwPID), ALLOW_VIEW_OBSERVER_EQUIPMENT)))
1976 continue;
1977
1978 LPITEM pkItem = pkPlayer->GetInventoryItem(i);
1979 if (pkItem)
1980 {
1981 TAdminManagerObserverItemInfo kInfo;
1982 EncodeObserverItemPacket(kInfo, pkItem);
1983 buf.write(&kInfo, sizeof(kInfo));
1984 iItemCount++;
1985 }
1986 }
1987 szWritePoint = buf.getptr()->write_point - sizeof(TAdminManagerObserverItemInfo)* iItemCount - sizeof(DWORD);
1988 memcpy(szWritePoint, &iItemCount, sizeof(DWORD));
1989 }
1990
1991 // whisper
1992 if (HasAllow(GetTeamRankByPID(dwPID), ALLOW_VIEW_OBSERVER_WHISPER))
1993 {
1994 buf.write(&dwTempCount, sizeof(DWORD));
1995 int iWhisperCount = 0;
1996 int iWhisperLen = 0;
1997 TPlayerWhisper* pkPlayerWhisper = CWhisperManager::instance().GetWhisper(pkPlayer->GetName());
1998 if (pkPlayerWhisper)
1999 {
2000 TPlayerWhisper::iterator it;
2001 for (it = pkPlayerWhisper->begin(); it != pkPlayerWhisper->end(); ++it)
2002 {
2003 CWhisper* pkWhisper = it->second;
2004
2005 const CWhisper::TMessageQueue& kQueue1 = pkWhisper->GetMessageQueue(0);
2006 const std::deque<CWhisper::TMessage*>& kQueueContainer1 = kQueue1.GetContainer();
2007 int iContainerIndex1 = 0;
2008 int iContainerSize1 = kQueueContainer1.size();
2009
2010 const CWhisper::TMessageQueue& kQueue2 = pkWhisper->GetMessageQueue(1);
2011 const std::deque<CWhisper::TMessage*>& kQueueContainer2 = kQueue2.GetContainer();
2012 int iContainerIndex2 = 0;
2013 int iContainerSize2 = kQueueContainer2.size();
2014
2015 unsigned char bTargetContainer = pkWhisper->GetIndexByName(pkPlayer->GetName());
2016
2017 while (iContainerIndex1 < iContainerSize1 || iContainerIndex2 < iContainerSize2)
2018 {
2019 CWhisper::TMessage* pkMessage1 = NULL;
2020 if (iContainerIndex1 < iContainerSize1)
2021 pkMessage1 = kQueueContainer1[iContainerIndex1];
2022 CWhisper::TMessage* pkMessage2 = NULL;
2023 if (iContainerIndex2 < iContainerSize2)
2024 pkMessage2 = kQueueContainer2[iContainerIndex2];
2025
2026 CWhisper::TMessage* pkMessage = NULL;
2027 unsigned char bContainerIndex = 0;
2028
2029 if (pkMessage1 && pkMessage2)
2030 {
2031 if (pkMessage1->m_dwSentTime < pkMessage2->m_dwSentTime)
2032 {
2033 pkMessage = pkMessage1;
2034 bContainerIndex = 0;
2035 }
2036 else
2037 {
2038 pkMessage = pkMessage2;
2039 bContainerIndex = 1;
2040 }
2041 }
2042 else
2043 {
2044 if (pkMessage1)
2045 {
2046 pkMessage = pkMessage1;
2047 bContainerIndex = 0;
2048 }
2049 else
2050 {
2051 pkMessage = pkMessage2;
2052 bContainerIndex = 1;
2053 }
2054 }
2055
2056 if (bContainerIndex == 0)
2057 iContainerIndex1++;
2058 else
2059 iContainerIndex2++;
2060
2061 if (bContainerIndex == bTargetContainer)
2062 {
2063 iWhisperLen += EncodeObserverWhisperPacket(buf, GC_SUBHEADER_OBSERVER_WHISPER_SEND,
2064 pkWhisper->GetPlayerIDByIndex(bTargetContainer == 0 ? 1 : 0),
2065 (get_dword_time() - pkMessage->m_dwSentTime) / 1000,
2066 pkMessage->m_stText.c_str());
2067 }
2068 else
2069 {
2070 iWhisperLen += EncodeObserverWhisperPacket(buf, GC_SUBHEADER_OBSERVER_WHISPER_RECV,
2071 pkWhisper->GetPlayerIDByIndex(bTargetContainer == 0 ? 1 : 0),
2072 (get_dword_time() - pkMessage->m_dwSentTime) / 1000,
2073 pkMessage->m_stText.c_str());
2074 }
2075 // append name
2076 const char* szName = pkWhisper->GetRealNameByIndex(bTargetContainer == 0 ? 1 : 0);
2077 int iNameLen = strlen(szName);
2078 buf.write(&iNameLen, sizeof(int));
2079 buf.write(szName, iNameLen);
2080 iWhisperLen += sizeof(int) + iNameLen;
2081
2082 ++iWhisperCount;
2083 }
2084 }
2085 }
2086 szWritePoint = buf.getptr()->write_point - iWhisperLen - sizeof(DWORD);
2087 memcpy(szWritePoint, &iWhisperCount, sizeof(DWORD));
2088 }
2089
2090 // ban
2091 CAffect* pAffBlockChat = pkPlayer->FindAffect(AFFECT_BLOCK_CHAT);
2092 DWORD dwChatBanTimeout = pAffBlockChat ? pAffBlockChat->lDuration : 0;
2093 buf.write(&dwChatBanTimeout, sizeof(DWORD));
2094
2095 // send packet
2096 SendClientPacket(dwPID, GC_SUBHEADER_OBSERVER_LOAD, buf.read_peek(), buf.size());
2097}
2098
2099void CAdminManager::SendObserverPacket(const std::set<DWORD>& rset_ObserverPIDs, unsigned char bSubHeader, const void* c_pvData, int iSize, DWORD dwCheckAllow)
2100{
2101 for (itertype(rset_ObserverPIDs) it = rset_ObserverPIDs.begin(); it != rset_ObserverPIDs.end(); ++it)
2102 {
2103 if (!dwCheckAllow || HasAllow(GetTeamRankByPID(*it), dwCheckAllow))
2104 SendClientPacket(*it, bSubHeader, c_pvData, iSize);
2105 }
2106}
2107
2108void CAdminManager::SendClientPacket(LPDESC pkDesc, unsigned char bSubHeader, const void* c_pvData, int iSize)
2109{
2110 TPacketGCAdminManager packet;
2111 packet.header = HEADER_GC_ADMIN_MANAGER;
2112 packet.size = sizeof(packet) + iSize;
2113 packet.sub_header = bSubHeader;
2114
2115 TEMP_BUFFER buf;
2116 buf.write(&packet, sizeof(packet));
2117 if (iSize)
2118 buf.write(c_pvData, iSize);
2119
2120 pkDesc->Packet(buf.read_peek(), buf.size());
2121}
2122
2123void CAdminManager::SendClientPacket(DWORD dwPID, unsigned char bSubHeader, const void* c_pvData, int iSize)
2124{
2125 LPCHARACTER pkChr = CHARACTER_MANAGER::instance().FindByPID(dwPID);
2126 if (pkChr)
2127 {
2128 SendClientPacket(pkChr->GetDesc(), bSubHeader, c_pvData, iSize);
2129 }
2130 else
2131 {
2132 CCI* pkCCI = P2P_MANAGER::instance().FindByPID(dwPID);
2133 if (pkCCI)
2134 {
2135 pkCCI->pkDesc->SetRelay(pkCCI->szName);
2136 SendClientPacket(pkCCI->pkDesc, bSubHeader, c_pvData, iSize);
2137 }
2138 else
2139 sys_err("cannot send client packet to pid %u subheader %hu [cannot find player]", dwPID, bSubHeader);
2140 }
2141}
2142
2143void CAdminManager::SendClientPacket(unsigned char bSubHeader, const void* c_pvData, int iSize, DWORD dwCheckAllow)
2144{
2145 for (itertype(m_set_ActivePlayers) it = m_set_ActivePlayers.begin(); it != m_set_ActivePlayers.end(); ++it)
2146 {
2147 if (!dwCheckAllow || HasAllow(*it, dwCheckAllow))
2148 SendClientPacket((*it)->GetDesc(), bSubHeader, c_pvData, iSize);
2149 }
2150}
2151
2152int CAdminManager::RecvClientPacket(LPCHARACTER pkChr, unsigned char bSubHeader, const char* c_pData, size_t uiBytes)
2153{
2154 if (m_set_ActivePlayers.find(pkChr) == m_set_ActivePlayers.end())
2155 {
2156 sys_err("cannot process admin packet by non-active-player %u %s (subheader %hu)", pkChr->GetPlayerID(), pkChr->GetName(), bSubHeader);
2157 return -1;
2158 }
2159
2160 switch (bSubHeader)
2161 {
2162 case CG_SUBHEADER_MAPVIEWER_START:
2163 {
2164 if (uiBytes < sizeof(DWORD) + sizeof(DWORD))
2165 return -1;
2166
2167 DWORD dwBaseX = *(DWORD*) c_pData;
2168 c_pData += sizeof(DWORD);
2169 DWORD dwBaseY = *(DWORD*) c_pData;
2170 long lMapIndex = SECTREE_MANAGER::instance().GetMapIndex(dwBaseX, dwBaseY);
2171
2172 if (HasAllow(pkChr, ALLOW_MAPVIEWER))
2173 {
2174 if (lMapIndex == 0)
2175 {
2176 pkChr->ChatPacket(CHAT_TYPE_INFO, "Invalid map.");
2177 sys_err("cannot find map by base coords (%u, %u)", dwBaseX, dwBaseY);
2178 }
2179 else
2180 {
2181 StartMapViewer(pkChr, lMapIndex);
2182 }
2183 }
2184 else
2185 sys_err("%s is not allowed to start the mapviewer", pkChr->GetName());
2186
2187 return sizeof(DWORD) + sizeof(DWORD);
2188 }
2189
2190 case CG_SUBHEADER_MAPVIEWER_STOP:
2191 StopMapViewer(pkChr->GetPlayerID());
2192 return 0;
2193
2194 case CG_SUBHEADER_OBSERVER_START:
2195 {
2196 if (uiBytes < sizeof(bool) + sizeof(int))
2197 return -1;
2198
2199 bool bSendFailMessage = *(bool*) c_pData;
2200 uiBytes -= sizeof(bool);
2201 c_pData += sizeof(bool);
2202
2203 int iLen = *(int*) c_pData;
2204 uiBytes -= sizeof(int);
2205 c_pData += sizeof(int);
2206
2207 if (uiBytes < iLen)
2208 return -1;
2209
2210 if (HasAllow(pkChr, ALLOW_OBSERVER))
2211 {
2212 char szPlayerName[CHARACTER_NAME_MAX_LEN + 1];
2213 strlcpy(szPlayerName, c_pData, MIN(iLen, CHARACTER_NAME_MAX_LEN) + 1);
2214
2215 StartObserver(pkChr, szPlayerName, bSendFailMessage);
2216 }
2217
2218 return sizeof(bool) + sizeof(int) + iLen;
2219 }
2220
2221 case CG_SUBHEADER_OBSERVER_STOP:
2222 StopObserver(pkChr->GetPlayerID());
2223 return 0;
2224
2225 case CG_SUBHEADER_BAN_CHAT_SEARCH:
2226 {
2227 if (uiBytes < sizeof(int))
2228 return -1;
2229
2230 int iNameLen = *(int*) c_pData;
2231 c_pData += sizeof(int);
2232 uiBytes -= sizeof(int);
2233
2234 if (iNameLen > CHARACTER_NAME_MAX_LEN)
2235 return -1;
2236
2237 if (uiBytes < iNameLen)
2238 return -1;
2239
2240 char* szName = new char[iNameLen + 1];
2241 thecore_memcpy(szName, c_pData, iNameLen);
2242 szName[iNameLen] = '\0';
2243
2244 if (HasAllow(pkChr, ALLOW_VIEW_BAN_CHAT))
2245 SearchBanChatPlayer(pkChr, szName);
2246
2247 delete[] szName;
2248
2249 return sizeof(int) + iNameLen;
2250 }
2251
2252 case CG_SUBHEADER_BAN_REQUEST_LOG:
2253 {
2254 ;
2255 if (uiBytes < sizeof(BYTE))
2256 return -1;
2257
2258 BYTE bType = *(BYTE*) c_pData;
2259 c_pData += sizeof(BYTE);
2260 uiBytes -= sizeof(BYTE);
2261
2262 if (uiBytes < sizeof(DWORD))
2263 return -1;
2264
2265 DWORD dwID = *(DWORD*) c_pData;
2266
2267 if (bType == BAN_TYPE_CHAT && HasAllow(pkChr, ALLOW_VIEW_BAN_CHAT_LOG))
2268 SendBanPlayerLog(pkChr, dwID);
2269 else if (bType == BAN_TYPE_ACCOUNT && HasAllow(pkChr, ALLOW_VIEW_BAN_ACCOUNT_LOG))
2270 SendBanAccountLog(pkChr, dwID);
2271
2272 return sizeof(BYTE) + sizeof(DWORD);
2273 }
2274 break;
2275
2276 case CG_SUBHEADER_BAN_ACCOUNT_SEARCH:
2277 {
2278 if (uiBytes < sizeof(BYTE) + sizeof(int))
2279 return -1;
2280
2281 BYTE bSearchType = *(BYTE*) c_pData;
2282 c_pData += sizeof(BYTE);
2283 uiBytes -= sizeof(BYTE);
2284
2285 int iNameLen = *(int*) c_pData;
2286 c_pData += sizeof(int);
2287 uiBytes -= sizeof(int);
2288
2289 if (iNameLen > (CHARACTER_NAME_MAX_LEN > LOGIN_MAX_LEN ? CHARACTER_NAME_MAX_LEN : LOGIN_MAX_LEN))
2290 return -1;
2291
2292 if (uiBytes < iNameLen)
2293 return -1;
2294
2295 char* szName = new char[iNameLen + 1];
2296 thecore_memcpy(szName, c_pData, iNameLen);
2297 szName[iNameLen] = '\0';
2298
2299 if (HasAllow(pkChr, ALLOW_VIEW_BAN_ACCOUNT))
2300 SearchBanAccount(pkChr, szName, bSearchType);
2301
2302 delete[] szName;
2303
2304 return sizeof(BYTE) + sizeof(int) + iNameLen;
2305 }
2306 break;
2307
2308 case CG_SUBHEADER_BAN_ACCOUNT:
2309 {
2310 if (uiBytes < sizeof(DWORD) + sizeof(DWORD) + sizeof(DWORD) + sizeof(BYTE) + sizeof(int))
2311 return -1;
2312
2313 DWORD dwAID = *(DWORD*) c_pData;
2314 c_pData += sizeof(DWORD);
2315 uiBytes -= sizeof(DWORD);
2316
2317 DWORD dwPlayerID = *(DWORD*) c_pData;
2318 c_pData += sizeof(DWORD);
2319 uiBytes -= sizeof(DWORD);
2320
2321 DWORD dwTimeLeft = *(DWORD*) c_pData;
2322 c_pData += sizeof(DWORD);
2323 uiBytes -= sizeof(DWORD);
2324
2325 bool bIncreaseBanCounter = *(bool*) c_pData;
2326 c_pData += sizeof(bool);
2327 uiBytes -= sizeof(bool);
2328
2329 int iLen1 = *(int*) c_pData;
2330 c_pData += sizeof(int);
2331 uiBytes -= sizeof(int);
2332
2333 if (uiBytes < iLen1 || iLen1 > 512)
2334 return -1;
2335
2336 char* szReason = new char[iLen1 + 1];
2337 thecore_memcpy(szReason, c_pData, iLen1);
2338 szReason[iLen1] = '\0';
2339 c_pData += iLen1;
2340 uiBytes -= iLen1;
2341
2342 if (uiBytes < sizeof(int))
2343 return -1;
2344
2345 int iLen2 = *(int*) c_pData;
2346 c_pData += sizeof(int);
2347 uiBytes -= sizeof(int);
2348
2349 if (uiBytes < iLen2 || iLen2 > 512)
2350 return -1;
2351
2352 char* szProof = new char[iLen2 + 1];
2353 thecore_memcpy(szProof, c_pData, iLen2);
2354 szProof[iLen2] = '\0';
2355
2356 if (HasAllow(pkChr, ALLOW_BAN_ACCOUNT))
2357 DoAccountBan(pkChr, dwAID, dwPlayerID, dwTimeLeft, szReason, szProof, bIncreaseBanCounter);
2358
2359 delete[] szReason;
2360 delete[] szProof;
2361
2362 return sizeof(DWORD) + sizeof(DWORD) + sizeof(DWORD) + sizeof(bool) + sizeof(int) + iLen1 + sizeof(int) + iLen2;
2363 }
2364 break;
2365
2366 case CG_SUBHEADER_ITEM_SEARCH:
2367 {
2368 if (uiBytes < sizeof(BYTE) + sizeof(int))
2369 return -1;
2370
2371 BYTE bSearchType = *(BYTE*) c_pData;
2372 c_pData += sizeof(BYTE);
2373 uiBytes -= sizeof(BYTE);
2374
2375 int iDataLen = *(int*) c_pData;
2376 c_pData += sizeof(int);
2377 uiBytes -= sizeof(int);
2378
2379 if (iDataLen > (CHARACTER_NAME_MAX_LEN > LOGIN_MAX_LEN ? CHARACTER_NAME_MAX_LEN : LOGIN_MAX_LEN))
2380 return -1;
2381
2382 if (iDataLen < 0 || (iDataLen == 0 && bSearchType != ITEM_SEARCH_GM_ITEM))
2383 return -1;
2384
2385 if (uiBytes < iDataLen)
2386 return -1;
2387
2388 char* szData = NULL;
2389 if (iDataLen)
2390 {
2391 szData = new char[iDataLen + 1];
2392 thecore_memcpy(szData, c_pData, iDataLen);
2393 szData[iDataLen] = '\0';
2394 }
2395
2396 if (HasAllow(pkChr, ALLOW_VIEW_ITEM))
2397 SearchItem(pkChr, bSearchType, szData);
2398
2399 if (szData)
2400 delete[] szData;
2401
2402 return sizeof(BYTE) + sizeof(int) + iDataLen;
2403 }
2404 break;
2405 }
2406
2407 sys_err("cannot process client packet subheader %hu (player %u %s)", bSubHeader, pkChr->GetPlayerID(), pkChr->GetName());
2408 return -1;
2409}
2410
2411/*******************************************************************\
2412| [PUBLIC] P2P Functions
2413\*******************************************************************/
2414
2415void CAdminManager::SendP2P(LPDESC pkDesc, unsigned char bSubHeader, const void* c_pvData, int iSize)
2416{
2417 TPacketGGAdminManager packet;
2418 packet.header = HEADER_GG_ADMIN_MANAGER;
2419 packet.sub_header = bSubHeader;
2420
2421 TEMP_BUFFER buf;
2422 buf.write(&packet, sizeof(packet));
2423 if (iSize)
2424 buf.write(c_pvData, iSize);
2425
2426 if (pkDesc)
2427 pkDesc->Packet(buf.read_peek(), buf.size());
2428 else
2429 P2P_MANAGER::instance().Send(buf.read_peek(), buf.size());
2430}
2431
2432int CAdminManager::RecvP2P(unsigned char bSubHeader, const char* c_pData)
2433{
2434 if (test_server)
2435 sys_log(0, "CAdminManager::RecvP2P %u", bSubHeader);
2436
2437 switch (bSubHeader)
2438 {
2439 case P2P_SUBHEADER_LOGOUT_PID:
2440 {
2441 OnLogoutPlayer(*(DWORD*) c_pData);
2442 return sizeof(DWORD);
2443 }
2444 break;
2445
2446 case P2P_SUBHEADER_START_MAPVIEWER:
2447 {
2448 DWORD dwPID = *(DWORD*) c_pData;
2449 c_pData += sizeof(DWORD);
2450 long lMapIndex = *(long*) c_pData;
2451
2452 StartMapViewer(dwPID, lMapIndex);
2453
2454 return sizeof(DWORD) + sizeof(long);
2455 }
2456 break;
2457
2458 case P2P_SUBHEADER_STOP_MAPVIEWER:
2459 {
2460 StopMapViewer(*(DWORD*) c_pData);
2461 return sizeof(DWORD);
2462 }
2463 break;
2464
2465 case P2P_SUBHEADER_START_OBSERVER:
2466 {
2467 DWORD dwPID = *(DWORD*) c_pData;
2468 c_pData += sizeof(DWORD);
2469 DWORD dwPlayerPID = *(DWORD*) c_pData;
2470
2471 StartObserver(dwPID, dwPlayerPID);
2472
2473 return sizeof(DWORD) + sizeof(DWORD);
2474 }
2475 break;
2476
2477 case P2P_SUBHEADER_STOP_OBSERVER:
2478 {
2479 StopObserver(*(DWORD*) c_pData);
2480 return sizeof(DWORD);
2481 }
2482 break;
2483
2484 case P2P_SUBHEADER_STOP_OBSERVER_BY_FORCE:
2485 {
2486 StopObserver(*(DWORD*) c_pData, true);
2487 return sizeof(DWORD);
2488 }
2489 break;
2490
2491 case P2P_SUBHEADER_BAN_PLAYER_CHATBAN:
2492 {
2493 TBanClientPlayerInfo* pPlayerInfo = (TBanClientPlayerInfo *) c_pData;
2494
2495 Ban_OnPlayerChatban(pPlayerInfo);
2496 return sizeof(TBanClientPlayerInfo);
2497 }
2498 break;
2499
2500 case P2P_SUBHEADER_BAN_CHAT_SEARCH_PLAYER:
2501 {
2502 DWORD dwGMPID = *(DWORD*) c_pData;
2503 c_pData += sizeof(DWORD);
2504 int iNameLen = *(int*) c_pData;
2505 c_pData += sizeof(int);
2506 char* szName = new char[iNameLen + 1];
2507 thecore_memcpy(szName, c_pData, iNameLen);
2508 szName[iNameLen] = '\0';
2509
2510 SearchBanChatPlayer(dwGMPID, szName);
2511 delete[] szName;
2512
2513 return sizeof(DWORD) + sizeof(int) + iNameLen;
2514 }
2515 break;
2516
2517 case P2P_SUBHEADER_BAN_ACCOUNT_REQUEST:
2518 {
2519 DWORD dwGMPid = *(DWORD*) c_pData;
2520 c_pData += sizeof(DWORD);
2521 BYTE bRequestorGMLevel = *(BYTE*) c_pData;
2522 c_pData += sizeof(BYTE);
2523 DWORD dwAID = *(DWORD*) c_pData;
2524 c_pData += sizeof(DWORD);
2525 int iLoginNameLen = *(int*) c_pData;
2526 c_pData += sizeof(int);
2527 char* szLoginName = new char[iLoginNameLen + 1];
2528 thecore_memcpy(szLoginName, c_pData, iLoginNameLen);
2529 szLoginName[iLoginNameLen] = '\0';
2530 c_pData += iLoginNameLen;
2531 DWORD dwTimeLeft = *(DWORD*) c_pData;
2532 c_pData += sizeof(DWORD);
2533 bool bIncreaseBanCounter = *(bool*) c_pData;
2534
2535 P2P_DoAccountBan(dwGMPid, bRequestorGMLevel, dwAID, szLoginName, dwTimeLeft, bIncreaseBanCounter);
2536 delete[] szLoginName;
2537
2538 return sizeof(DWORD) + sizeof(BYTE) + sizeof(DWORD) + sizeof(int) + iLoginNameLen + sizeof(DWORD) + sizeof(bool);
2539 }
2540 break;
2541
2542 case P2P_SUBHEADER_BAN_ACCOUNT_DISCONNECT:
2543 {
2544 ;
2545 int iLoginNameLen = *(int*) c_pData;
2546 c_pData += sizeof(int);
2547 char* szLoginName = new char[iLoginNameLen + 1];
2548 thecore_memcpy(szLoginName, c_pData, iLoginNameLen);
2549 szLoginName[iLoginNameLen] = '\0';
2550
2551 P2P_DoAccountBanDisconnect(szLoginName);
2552 delete[] szLoginName;
2553
2554 return sizeof(int) + iLoginNameLen;
2555 }
2556 break;
2557
2558 case P2P_SUBHEADER_BAN_ACCOUNTBAN:
2559 {
2560 TBanClientAccountInfo* pData = (TBanClientAccountInfo*) c_pData;
2561
2562 OnPlayerAccountban(pData);
2563 return sizeof(TBanClientAccountInfo);
2564 }
2565 break;
2566
2567 case P2P_SUBHEADER_BAN_ACCOUNT_SEARCH:
2568 {
2569 DWORD dwGMPid = *(DWORD*) c_pData;
2570 c_pData += sizeof(DWORD);
2571 int iLen = *(int*) c_pData;
2572 c_pData += sizeof(int);
2573 char* szName = new char[iLen + 1];
2574 thecore_memcpy(szName, c_pData, iLen);
2575 szName[iLen] = '\0';
2576 c_pData += iLen;
2577 BYTE bSearchType = *(BYTE*) c_pData;
2578
2579 SearchBanAccount(dwGMPid, szName, bSearchType);
2580 delete[] szName;
2581
2582 return sizeof(DWORD) + sizeof(int) + iLen + sizeof(BYTE);
2583 }
2584 break;
2585 }
2586
2587 sys_err("cannot process subheader %u", bSubHeader);
2588 return -1;
2589}
2590
2591/*******************************************************************\
2592| [PUBLIC] Event Functions
2593\*******************************************************************/
2594
2595void CAdminManager::OnLoginPlayer(LPCHARACTER pkChr)
2596{
2597 // update online player list
2598 SendClientPacket(GC_SUBHEADER_PLAYER_ONLINE, &GetPlayerInfo(pkChr), sizeof(TAdminManagerPlayerInfo), ALLOW_VIEW_ONLINE_LIST | ALLOW_VIEW_ONLINE_COUNT);
2599
2600 // events
2601 MapViewer_OnPlayerLogin(pkChr);
2602 Ban_OnPlayerLogin(pkChr->GetPlayerID());
2603
2604 // only allow the admin manager for gms - also on test_server !
2605 if (!GM::check_allow(pkChr->GetGMLevel(true), GM_ALLOW_ADMIN_MANAGER))
2606 return;
2607
2608 m_set_ActivePlayers.insert(pkChr);
2609 m_set_ActivePIDs.insert(pkChr->GetPlayerID());
2610
2611 // load packet
2612 SendLoadPacket(pkChr);
2613}
2614
2615void CAdminManager::OnP2PLoginPlayer(DWORD dwPID)
2616{
2617 // event
2618 Ban_OnPlayerLogin(dwPID);
2619
2620 // get player
2621 CCI* pkCCI = P2P_MANAGER::instance().FindByPID(dwPID);
2622 if (!pkCCI)
2623 {
2624 sys_err("cannot get cci by pid %u", dwPID);
2625 return;
2626 }
2627
2628 SendClientPacket(GC_SUBHEADER_PLAYER_ONLINE, &GetPlayerInfo(pkCCI), sizeof(TAdminManagerPlayerInfo), ALLOW_VIEW_ONLINE_LIST | ALLOW_VIEW_ONLINE_COUNT);
2629}
2630
2631void CAdminManager::OnLogoutPlayer(LPCHARACTER pkChr)
2632{
2633 // events
2634 MapViewer_OnPlayerLogout(pkChr);
2635
2636 // normal handling
2637 OnLogoutPlayer(pkChr->GetPlayerID());
2638}
2639
2640void CAdminManager::OnLogoutPlayer(DWORD dwPID)
2641{
2642 Ban_OnPlayerLogout(dwPID);
2643
2644 {
2645 itertype(m_map_ObserverSetByPID) it = m_map_ObserverSetByPID.find(dwPID);
2646 if (it != m_map_ObserverSetByPID.end() && it->second.size() > 0)
2647 {
2648 do
2649 {
2650 DWORD dwPID = *(it->second.begin());
2651 if (StopObserver(dwPID, true))
2652 break;
2653 } while (it->second.size() > 0);
2654 }
2655 }
2656
2657 {
2658 itertype(m_set_ActivePIDs) it = m_set_ActivePIDs.find(dwPID);
2659 if (it != m_set_ActivePIDs.end())
2660 {
2661 // stop mapviewer
2662 if (IsRunningMapViewer(dwPID))
2663 StopMapViewer(dwPID);
2664
2665 // stop observer
2666 if (IsRunningObserver(dwPID))
2667 StopObserver(dwPID);
2668
2669 // remove pid for all p2p connections which are connected to the player somehow
2670 itertype(m_map_PlayerP2PConnections) p2p_it = m_map_PlayerP2PConnections.find(dwPID);
2671 if (p2p_it != m_map_PlayerP2PConnections.end())
2672 {
2673 for (itertype(p2p_it->second) desc_it = p2p_it->second.begin(); desc_it != p2p_it->second.end(); ++desc_it)
2674 SendP2P(*desc_it, P2P_SUBHEADER_LOGOUT_PID, &dwPID, sizeof(DWORD));
2675
2676 m_map_PlayerP2PConnections.erase(p2p_it);
2677 }
2678
2679 // remove player if exists
2680 LPCHARACTER pkChr = CHARACTER_MANAGER::instance().FindByPID(dwPID);
2681 if (pkChr)
2682 m_set_ActivePlayers.erase(pkChr);
2683
2684 m_set_ActivePIDs.erase(it);
2685 }
2686 }
2687
2688 SendClientPacket(GC_SUBHEADER_PLAYER_OFFLINE, &dwPID, sizeof(DWORD), ALLOW_VIEW_ONLINE_LIST | ALLOW_VIEW_ONLINE_COUNT);
2689}
2690
2691void CAdminManager::OnP2PLogoutPlayer(DWORD dwPID)
2692{
2693 // event
2694 Ban_OnPlayerLogout(dwPID);
2695
2696 SendClientPacket(GC_SUBHEADER_PLAYER_OFFLINE, &dwPID, sizeof(DWORD), ALLOW_VIEW_ONLINE_LIST | ALLOW_VIEW_ONLINE_COUNT);
2697}
2698
2699void CAdminManager::OnP2PDisconnect(LPDESC pkDesc)
2700{
2701 // remove each p2p peer pointer that refers to the disconnected peer from the list
2702 for (itertype(m_map_PlayerP2PConnections) it = m_map_PlayerP2PConnections.begin(); it != m_map_PlayerP2PConnections.end(); ++it)
2703 {
2704 itertype(it->second) desc_it = it->second.find(pkDesc);
2705 if (desc_it != it->second.end())
2706 it->second.erase(desc_it);
2707 }
2708}
2709
2710void CAdminManager::OnPlayerMove(LPCHARACTER pkChr)
2711{
2712 // mapviewer
2713 MapViewer_OnPlayerMove(pkChr);
2714}
2715
2716void CAdminManager::OnPlayerStateChange(LPCHARACTER pkChr)
2717{
2718 // mapviewer
2719 MapViewer_OnPlayerStateChange(pkChr);
2720}
2721
2722void CAdminManager::OnMonsterCreate(LPCHARACTER pkChr)
2723{
2724 // mapviewer
2725 MapViewer_OnMonsterCreate(pkChr);
2726}
2727
2728void CAdminManager::OnMonsterDestroy(LPCHARACTER pkChr)
2729{
2730 // mapviewer
2731 MapViewer_OnMonsterDestroy(pkChr);
2732}
2733
2734void CAdminManager::OnMonsterMove(LPCHARACTER pkChr)
2735{
2736 // mapviewer
2737 MapViewer_OnMonsterMove(pkChr);
2738}
2739
2740void CAdminManager::OnMonsterStateChange(LPCHARACTER pkChr)
2741{
2742 // mapviewer
2743 MapViewer_OnMonsterStateChange(pkChr);
2744}
2745
2746void CAdminManager::OnPlayerSkillGroupChange(LPCHARACTER pkChr)
2747{
2748 // observer
2749 Observer_OnPlayerSkillGroupChange(pkChr);
2750}
2751
2752void CAdminManager::OnPlayerSkillChange(LPCHARACTER pkChr, DWORD dwSkillVnum)
2753{
2754 // observer
2755 Observer_OnPlayerSkillChange(pkChr, dwSkillVnum);
2756}
2757
2758void CAdminManager::OnPlayerSkillCooldown(LPCHARACTER pkChr, DWORD dwSkillVnum, DWORD dwCoolTime)
2759{
2760 // observer
2761 Observer_OnPlayerSkillCooldown(pkChr, dwSkillVnum, dwCoolTime);
2762}
2763
2764void CAdminManager::OnPlayerPointChange(LPCHARACTER pkChr, unsigned char bType, long long llValue)
2765{
2766 // observer
2767 Observer_OnPlayerPointChange(pkChr, bType, llValue);
2768}
2769
2770void CAdminManager::OnPlayerItemSet(LPCHARACTER pkChr, WORD wCell)
2771{
2772 // observer
2773 Observer_OnPlayerItemSet(pkChr, wCell);
2774}
2775
2776void CAdminManager::OnPlayerWhisper(LPCHARACTER pkChr, DWORD dwReceiverPID, const char* c_pszMessage)
2777{
2778 // observer
2779 Observer_OnPlayerWhisper(pkChr, dwReceiverPID, c_pszMessage);
2780}
2781
2782void CAdminManager::OnPlayerChatban(LPCHARACTER pkChr, DWORD dwTimeLeft)
2783{
2784 // observer
2785 Observer_OnPlayerChatban(pkChr, dwTimeLeft);
2786 // ban
2787 Ban_OnPlayerChatban(pkChr, dwTimeLeft);
2788}
2789
2790void CAdminManager::OnPlayerChatban(const char* c_pszName, DWORD dwTimeLeft, bool bIncreaseBanCounter)
2791{
2792 // ban
2793 Ban_OnPlayerChatban(c_pszName, dwTimeLeft, bIncreaseBanCounter);
2794}
2795
2796void CAdminManager::OnPlayerAccountban(const TBanClientAccountInfo* pAccountInfo)
2797{
2798 // observer
2799 for (int i = 0; i < PLAYER_PER_ACCOUNT; ++i)
2800 {
2801 if (pAccountInfo->dwPID[i])
2802 Observer_OnPlayerAccountban(pAccountInfo->dwPID[i], pAccountInfo->dwDuration);
2803 }
2804 // ban
2805 Ban_OnPlayerAccountban(pAccountInfo);
2806}
2807
2808void CAdminManager::OnEventFlagChange(const std::string& c_rstFlagName, int iNewValue)
2809{
2810 if (c_rstFlagName == EVENT_FLAG_GM_ITEM_TRADE_BLOCK)
2811 {
2812 bool bIsActive = iNewValue != 0;
2813 SendClientPacket(GC_SUBHEADER_GM_ITEM_TRADE_BLOCK, &bIsActive, sizeof(bool), ALLOW_GM_TRADE_BLOCK_OPTION);
2814 }
2815}
2816
2817#endif