EvEmu  0.8.4
11 September 2021
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
Client.cpp
Go to the documentation of this file.
1 /*
2  ------------------------------------------------------------------------------------
3  LICENSE:
4  ------------------------------------------------------------------------------------
5  This file is part of EVEmu: EVE Online Server Emulator
6  Copyright 2006 - 2021 The EVEmu Team
7  For the latest information visit https://evemu.dev
8  ------------------------------------------------------------------------------------
9  This program is free software; you can redistribute it and/or modify it under
10  the terms of the GNU Lesser General Public License as published by the Free Software
11  Foundation; either version 2 of the License, or (at your option) any later
12  version.
13 
14  This program is distributed in the hope that it will be useful, but WITHOUT
15  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16  FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
17 
18  You should have received a copy of the GNU Lesser General Public License along with
19  this program; if not, write to the Free Software Foundation, Inc., 59 Temple
20  Place - Suite 330, Boston, MA 02111-1307, USA, or go to
21  http://www.gnu.org/copyleft/lesser.txt.
22  ------------------------------------------------------------------------------------
23  Author: Zhur
24  Updates: Allan (rewrite), AlTahir(DaVinci)
25 */
26 
27 #include "eve-server.h"
28 #include "../eve-common/EVEVersion.h"
29 #include "../eve-common/EVE_Character.h"
30 
31 #include "Client.h"
32 #include "ConsoleCommands.h"
33 #include "EVEServerConfig.h"
34 #include "LiveUpdateDB.h"
35 #include "PyBoundObject.h"
36 #include "StaticDataMgr.h"
37 #include "chat/LSCService.h"
40 #include "fleet/FleetService.h"
43 #include "npc/NPC.h"
44 //#include "npc/Drone.h"
45 //#include "npc/DroneAI.h"
46 #include "station/StationDataMgr.h"
47 #include "station/StationOffice.h"
48 #include "system/DestinyManager.h"
49 #include "system/SystemManager.h"
50 #include "system/SystemBubble.h"
52 #include "exploration/Scan.h"
53 #include "station/Station.h"
54 #include "station/TradeService.h"
55 #include "pos/Tower.h"
56 
57 static const uint32 PING_INTERVAL_MS = 600000; //10m
58 
60 : EVEClientSession(con),
61  m_TS(nullptr),
62  m_char(CharacterRef(nullptr)),
63  m_scan(nullptr),
64  pShipSE(nullptr),
65  pSession(new ClientSession()),
66  m_system(nullptr),
67  m_services(services),
68  m_movePoint(NULL_ORIGIN),
69  m_clientState(Player::State::Idle),
70  m_stateTimer(0),
71  m_ballparkTimer(0),
72  m_pingTimer(PING_INTERVAL_MS),
73  m_scanTimer(0),
74  m_cloakTimer(0),
75  m_fleetTimer(0),
76  m_invulTimer(0),
77  m_clientTimer(0),
78  m_logoutTimer(0),
79  m_jetcanTimer(0),
80  m_sessionTimer(0),
81  m_uncloakTimer(0),
82  m_destinyEventQueue(new PyList()),
83  m_destinyUpdateQueue(new PyList()),
84  m_nextNotifySequence(0)
85 {
86  m_pod = ShipItemRef(nullptr);
87  m_ship = ShipItemRef(nullptr);
88 
91 
92  m_afk = false;
93  m_login = true;
94  m_invul = true;
95  m_wing = false;
96  m_fleet = false;
97  m_squad = false;
98  m_loaded = false;
99  m_undock = false;
100  m_showall = false;
101  m_uncloak = false;
102  m_beyonce = false;
103  m_autoStop = false;
104  m_canThrow = false;
105  m_packaged = false;
106  m_portrait = false;
107  m_autoPilot = false;
108  m_bubbleWait = false; // allow client processing of subsquent destiny msgs
109  m_charCreation = false;
110  m_setStateSent = false;
111  m_validSession = false;
112  m_sessionChangeActive = false;
113 
114  //m_toGate = 0;
115  m_locationID = 0;
116  m_moveSystemID = 0;
117  m_skillTimer = 0;
118  m_dockStationID = 0;
119 
120  m_lpMap.clear();
121  m_channels.clear();
122  m_hangarLoaded.clear();
123 
124  // Start handshake
125  Reset();
126 }
127 
227  if (!m_loaded)
228  return;
229 
230  m_loaded = false;
231 
232  if (pShipSE != nullptr)
233  WarpOut(); // need to make tests for this...it will segfault if m_char is invalid
234 
235  // LSC logout
236  for (auto cur : m_channels)
237  cur->LeaveChannel(this);
238 
239  if (m_char.get() != nullptr) { // we have valid character
249  sLog.Green(" Client::Logout()","%s (Acct:%u) logging out.", m_char->name(), GetUserID());
250 
251  if (!sConsole.IsDbError()) {
254  }
255 
256  if (!sConsole.IsShutdown()) {
257  if (IsDocked()) {
258  if (GetTradeSession()) {
259  TradeService* mts = (TradeService*)(m_services.LookupService("trademgr"));
260  mts->CancelTrade(this);
261  }
263  // remove char from station
264  sEntityList.GetStationByID(m_locationID)->RemoveItem(m_char);
265  }
266 
267  }
268  // remove fleet data, remove char from ItemFactory cache, save SP and set logout time
269  m_char->LogOut();
270  }
271 
272  // save shipstate and remove from ItemFactory
273  m_ship->LogOut();
274 
275  m_system->RemoveClient(this, true);
276  // remove char from entitylist
277  sEntityList.RemovePlayer(this);
278 
279  for (auto cur : m_bindSet)
281 
282  m_system = nullptr; // DO NOT delete m_system here
283 
284  SafeDelete(m_TS);
290 }
291 
293 {
295  return false;
296 
297  PyPacket *p(nullptr);
298  while ((p = PopPacket())) {
299  try {
300  if (!DispatchPacket(p))
301  sLog.Error("Client", "%s: Failed to dispatch packet of type %s (%d).", m_char->name(), MACHONETMSG_TYPE_NAMES[ p->type ], (int)p->type);
302  }
303  catch(PyException& e) {
305  }
306 
307  SafeDelete(p);
308  }
309 
310  // send queue
312 
313  return true;
314 }
315 
317 {
318  if (sEntityList.IsOnline(charID)) {
319  sLog.Error("Client::SelectCharacter()", "Char %u already online.", charID);
320  SendErrorMsg("That Character is already online. Selection Failed.");
322  return false;
323  }
324 
325  InitSession(charID);
326  if (!m_validSession){
327  sLog.Error("Client::SelectCharacter()", "Failed to init session for char %u.", charID);
328  SendErrorMsg("Unable to Initalize Character session. Selection Failed.");
330  return false;
331  }
332 
333  sEntityList.AddPlayer(this);
334  sItemFactory.SetUsingClient(this);
335 
336  m_system = sEntityList.FindOrBootSystem(m_SystemData.systemID);
337  if (m_system == nullptr) {
338  sLog.Error("Client::SelectCharacter()", "Failed to boot system %u for char %u.", m_SystemData.systemID, charID);
339  SendErrorMsg("SolarSystem %s(%u) - Boot Failure.", m_SystemData.name.c_str(), m_SystemData.systemID);
341  return false;
342  }
343 
344  m_char = sItemFactory.GetCharacter(charID);
345  if (m_char.get() == nullptr) {
346  sLog.Error("Client::SelectCharacter()", "GetChar for %u = nullptr", charID);
347  SendErrorMsg("Unable to locate Character. Selection Failed.");
348  sItemFactory.UnsetUsingClient();
350  return false;
351  }
352 
353  m_char->SetClient(this);
354 
355  // register with our system manager AFTER character is constructed and initialized
356  m_system->AddClient(this, true);
357 
358  // this will eventually check for d/c timer and rejoin existing fleet if applicable
359  // fleet data is zeroed when char item is created
360 
361  SetPodItem();
362 
363  m_ship = sItemFactory.GetShip(m_shipId);
364  if (m_ship.get() == nullptr) {
365  sLog.Error("Client::SelectCharacter()", "shipID %u invalid for %u. Selecting new ship...", m_shipId, charID);
366  PickAlternateShip(); // incase shipID wasnt set correctly in db (seen on 'bad' Damage::Killed())
367  m_ship = sItemFactory.GetShip(m_shipId);
368  if (m_ship.get() == nullptr) {
369  sLog.Error("Client::SelectCharacter()", "shipID %u for %u also invalid. Loading Pod.", m_shipId, charID);
370  m_ship = m_pod;
371  }
372  SetShip(m_ship);
373  }
374 
375  m_ship->SetPlayer(this);
376 
377  GPoint pos(NULL_ORIGIN);
378  if (sDataMgr.IsSolarSystem(m_locationID))
379  pos = m_ship->position();
380 
382 
383  if (sDataMgr.IsSolarSystem(m_locationID)) {
384  WarpIn();
385  } else {
386  if (m_ship->typeID() == itemTypeCapsule) {
387  if (sConfig.server.NoobShipCheck) {
389  if (sRef.get() == nullptr) {
390  // error here...
391  } else if (!sRef->HasShip(this)) {
393  }
394  } else {
396  }
397  }
398  }
399 
400  //create corp and ally chat channels (if not already created)
402 
403  // load char LPs
404  //m_lpMap
405 
406  // update account online status, increase login count, set last login timestamp
409 
410  //johnsus - characterOnline mod
412  sItemFactory.UnsetUsingClient();
413 
414 
417  //SetCloakTimer(Player::Timer::LoginCloak);
418 
419  m_char->VerifySP();
420  m_char->SkillQueueLoop(false);
421  m_char->SetLoginTime();
422 
423  // set ship cap and shields to full
424  m_ship->SetShipShield(1.0);
426 
427  // send MOTD and server data to 'local' chat channel
429 
430  return (m_loaded = true);
431 }
432 
434  if (m_charCreation)
435  return;
436 
437  double profileStartTime = GetTimeUSeconds();
438 
439  // wtf is this for?
440  if (m_pingTimer.Check()) {
441  _SendPingRequest(); //10m
443  }
444 
445  if (m_skillTimer > 0)
448 
449  if (m_sessionTimer.Check(false)) {
450  _log(CLIENT__TIMER, "Client::ProcessClient(): SetSessionChange to false for %s(%u)", m_char->name(), m_char->itemID());
452  m_sessionChangeActive = false;
453  }
454 
455  /* Check Character Save Timer Expiry: (not currently used -allan 17May16)
456  if (m_char->CheckSaveTimer()) {
457  _log(CLIENT__TIMER, "Client::ProcessClient(): SaveTimer for %s(%u)", m_char->name(), m_char->itemID());
458  m_char->SaveCharacter();
459  m_ship->SaveShip();
460  }
461  */
462  if (sDataMgr.IsStation(m_locationID)) {
463  if (m_stateTimer.Enabled())
464  if (m_stateTimer.Check(false)) {
466  switch (m_clientState) {
467  case Player::State::Login: {
468  _log(CLIENT__TIMER, "ProcessClient()::IsDocked()::CheckState(): case: Login");
469  m_login = false;
470  } break;
471  case Player::State::Idle: {
472  _log(CLIENT__TIMER, "ProcessClient()::IsDocked()::CheckState(): case: Idle");
473  } break;
474  case Player::State::Logout: {
475  _log(CLIENT__TIMER, "ProcessClient()::IsDocked()::CheckState(): case: Logout");
476  } break;
477  case Player::State::Killed: {
478  _log(CLIENT__TIMER, "ProcessClient()::IsDocked()::CheckState(): case: Killed");
479  } break;
480  }
482  _log(AUTOPILOT__TRACE, "ProcessClient()::IsDocked() - m_clientState set to Idle");
483  }
484  if (sConfig.debug.UseProfiling)
485  sProfiler.AddTime(Profile::client, GetTimeUSeconds() - profileStartTime);
486  return;
487  }
488 
489  if (pShipSE == nullptr) {
490  sLog.Error("ProcessClient()","%s: InSpace with no shipSE. LocationID %u", m_char->name(), m_locationID);
491  return;
492  }
493 
494  if (m_invulTimer.Enabled()/*m_invul*/)
495  if (m_invulTimer.Check(false)) {
496  _log(CLIENT__TIMER, "ProcessClient(): SetInvul to false for %s(%u)", m_char->name(), m_char->itemID());
498  m_invul = false;
499  m_undock = false;
500  }
501 
502  if (m_scanTimer.Enabled())
503  if (m_scanTimer.Check(false)) {
504  _log(CLIENT__TIMER, "ProcessClient(): Scan Timer hit for %s(%u).", m_char->name(), m_char->itemID());
507  }
508 
509  if (m_ballparkTimer.Enabled())
510  if (m_ballparkTimer.Check(false)) {
511  _log(CLIENT__TIMER, "ProcessClient(): Ballpark Timer hit for %s(%u).", m_char->name(), m_char->itemID());
513  SetBallPark();
514  }
515 
516  if (pShipSE->DestinyMgr()->IsCloaked())
517  if (m_cloakTimer.Check(false)) {
518  _log(CLIENT__TIMER, "ProcessClient(): SetCloak to false for %s(%u)", m_char->name(), m_char->itemID());
520  pShipSE->DestinyMgr()->UnCloak();
521  //m_clientState = Player::State::Idle;
522  //_log(AUTOPILOT__TRACE, "ProcessClient() - Cloaked - m_clientState set to Idle");
523  }
524 
525  if (m_uncloak)
526  if (m_uncloakTimer.Check(false)) {
527  _log(CLIENT__TIMER, "ProcessClient(): SetUncloak to false for %s(%u)", m_char->name(), m_char->itemID());
529  m_uncloak = false;
530  }
531 
532  if (m_stateTimer.Enabled())
533  if (m_stateTimer.Check(false)) {
534  _log(CLIENT__TIMER, "ProcessClient(): state timer hit. current state time is %ums", m_stateTimer.GetCurrentTime());
536  switch (m_clientState) {
537  case Player::State::Idle: {
538  _log(CLIENT__TIMER, "ProcessClient()::CheckState(): case: Idle");
539  // this shouldnt hit...error
540  } break;
541  case Player::State::Dock: {
542  _log(CLIENT__TIMER, "ProcessClient()::CheckState(): case: Dock");
543  DockToStation();
544  } break;
545  case Player::State::Undock: {
546  _log(CLIENT__TIMER, "ProcessClient()::CheckState(): case: Undock");
548  SetBallPark();
550  } break;
551  case Player::State::Killed: {
552  _log(CLIENT__TIMER, "ProcessClient()::CheckState(): case: Killed");
553  // live does NOT resend destiny state when killed. see csBoard notes.
556  } break;
557  case Player::State::Board: {
558  _log(CLIENT__TIMER, "ProcessClient()::CheckState(): case: Board");
559  // calling OnSessionChanged() in client with shipid in change will update ego with new ship.
560  // NOTE: all items must be in same bubble.
563  } break;
564  case Player::State::Login: {
565  _log(CLIENT__TIMER, "ProcessClient()::CheckState(): case: Login");
566  m_login = false;
567  SetBallPark();
569  m_ship->GetModuleManager()->UpdateChargeQty(); // <<<< huge hack here....cant find another way to do it yet.
570  } break;
571  case Player::State::Jump: {
572  _log(CLIENT__TIMER, "ProcessClient()::CheckState(): case: Jump");
573  ExecuteJump();
574  } break;
576  _log(CLIENT__TIMER, "ProcessClient()::CheckState(): case: DriveJump");
578  } break;
579  case Player::State::Logout: {
580  _log(CLIENT__TIMER, "ProcessClient()::CheckState(): case: Logout");
581  // can we use this to allow WarpOut?
582  } break;
583  default: {
584  sLog.Error("ProcessClient()","%s: State timer expired with invalid state: %s.", m_char->name(), GetStateName(m_clientState).c_str());
585  //SendErrorMsg("Server Error - Move not initalized properly. You may need to relog. Ref: ServerError 10928");
586  } break;
587  }
588  }
589 
590  // only set for location change
591  if (m_fleetTimer.Enabled())
592  if (m_fleetTimer.Check(false)) {
594  BoostData bData = BoostData();
595  if (IsSquadID(m_squad)) {
596  SquadData sData = SquadData();
597  sFltSvc.GetSquadData(m_squad, sData);
598  if ((sData.leader != nullptr) and (sData.booster != nullptr))
599  if ((sData.leader->IsInSpace()) and (sData.booster->IsInSpace()))
600  bData = sData.boost;
601  } else if (IsWingID(m_wing)) {
602  WingData wData = WingData();
603  sFltSvc.GetWingData(m_wing, wData);
604  if ((wData.leader != nullptr) and (wData.booster != nullptr))
605  if ((wData.leader->IsInSpace()) and (wData.booster->IsInSpace()))
606  bData = wData.boost;
607  } else if (IsFleetID(m_fleet)) {
608  FleetData fData = FleetData();
609  sFltSvc.GetFleetData(m_fleet, fData);
610  if ((fData.leader != nullptr) and (fData.booster != nullptr))
611  if ((fData.leader->IsInSpace()) and (fData.booster->IsInSpace())) {
612  CharacterRef bRef = fData.booster->GetChar();
619  }
620  }
621  pShipSE->ApplyBoost(bData);
622  }
623 
624  if (sConfig.debug.UseProfiling)
625  sProfiler.AddTime(Profile::client, GetTimeUSeconds() - profileStartTime);
626 }
627 
629  sLog.Blue("Client::WarpIn()", "%s(%u) called WarpIn(). Finish code here.", GetName(), m_char->itemID());
630  char ci[45];
631  snprintf(ci, sizeof(ci), "InSpace: %s(%u)", GetName(), m_char->itemID());
632  m_ship->SetCustomInfo(ci);
633  if (!InPod())
635  return;
636  /*
637  // We are just logging in, so we need to warp to our last position from our WarpOut spot.
638  // when implemented, make sure we move the ship item, if needed....check this
639  GPoint warpToPoint(m_ship->position());
640  GPoint warpFromPoint(m_ship->position());
641  warpFromPoint.MakeRandomPointOnSphere(0.5*ONE_AU_IN_METERS);
642  pShipSE->DestinyMgr()->SetPosition(warpFromPoint);
643  pShipSE->DestinyMgr()->WarpTo(warpToPoint); // Warp ship from the random login point to the position saved on last disconnect
644  */
645 }
646 
648  sLog.Blue("Client::WarpOut()", "Client Destructor for %s(%u) called WarpOut(). Finish code here.", GetName(), m_char->itemID());
649  char ci[45];
650  snprintf(ci, sizeof(ci), "Logout: %s(%u)", GetName(), m_char->itemID());
651  m_ship->SetCustomInfo(ci);
652  if (!InPod())
655  DestroyShipSE();
656  return;
657  /*
658  SetInvulTimer(Player::Timer::WarpOutInvul);
659  // We are logging out, so we need to warp to a random spot 1Mm away:
660  GPoint warpToPoint(m_ship->position());
661  warpToPoint.MakeRandomPointOnSphere(0.5*ONE_AU_IN_METERS);
662  if (sConsole.IsShutdown()) // if server is being shutdown, set ship to WarpOut point, as if they warped there.
663  pShipSE->SetPosition(warpToPoint);
664  else
665  pShipSE->DestinyMgr()->WarpTo(warpToPoint);
666  */
667 }
668 
669 void Client::SetAutoPilot(bool set/*false*/)
670 {
671  // itemID=10644 flag=*module* not published - not in client data
672  if (m_autoPilot == set)
673  return;
674 
675  m_autoPilot = set;
676  _log(AUTOPILOT__MESSAGE, "%s called SetAutoPilot to %s", GetName(), (set ? "true" : "false"));
677 }
678 
680 {
681  MoveToLocation(systemID, m_ship->position());
682 }
683 
684 void Client::MoveToLocation(uint32 locationID, const GPoint& pt) {
685  // process ALL location changes here.
686  if (!sDataMgr.IsStation(locationID) and !sDataMgr.IsSolarSystem(locationID)) {
687  SendErrorMsg("Move requested to unsupported location %u", locationID);
688  return;
689  }
690 
691  _log(AUTOPILOT__TRACE, "MoveToLocation() - m_autoPilot = %s", (m_autoPilot ? "true" : "false"));
692 
693  if (!m_login and (m_locationID == locationID) and !sDataMgr.IsStation(locationID)) {
694  _log(PLAYER__WARNING, "MoveToLocation() - m_locationID == location");
695  // This is a simple movement
696  SetDestiny(pt, true);
697  return;
698  }
699 
700  bool count(m_login);
701  bool wasDocked(sDataMgr.IsStation(m_locationID));
702  m_locationID = locationID;
703  // get data for new system. this checks for stationID sent as locationID, so is safe here.
704  sDataMgr.GetSystemData(m_locationID, m_SystemData);
705 
706  m_bubbleWait = false; // allow client processing of subsequent destiny msgs
707 
708  // location changed...verify current system and set session data for current system.
709  if (IsJump() or ((m_system != nullptr) and (m_system->GetID() != m_SystemData.systemID))) {
710  //we have different m_system
711  _log(PLAYER__WARNING, "MoveToLocation() - current m_system is %s, systemData is for %s, m_system->GetID(%u) != locationID(%u)", \
713  // if docked, update guestlist
714  if (wasDocked) {
716  wasDocked = false; // dont update station again on this call (redundant check later in this method)
717  }
718  if (pShipSE != nullptr)
719  if (IsJump() and !m_autoPilot)
720  pShipSE->DestinyMgr()->Halt();
721 
722  // remove from current system before resetting system vars
724  m_system->RemoveClient(this, (count = true), IsJump());
725  m_system = nullptr;
726  }
727 
728  if (m_system == nullptr) {
729  _log(PLAYER__WARNING, "MoveToLocation() - m_system == NULL, m_locationID = %u", m_locationID);
730  // find our new system's manager
731  sItemFactory.SetUsingClient(this);
732  m_system = sEntityList.FindOrBootSystem(m_SystemData.systemID);
733  sItemFactory.UnsetUsingClient();
734  if (m_system == nullptr) {
735  sLog.Error("Client", "Failed to boot system %u for char %s (%u)", m_SystemData.systemID, m_char->name(), m_char->itemID());
736  SendErrorMsg("Unable to boot system. Relog and try again.");
737  return;
738  }
739 
740  m_beyonce = false;
741  m_setStateSent = false;
742 
743  // register ourselves with new system manager (this wont hit on login)
744  m_system->AddClient(this, count, IsJump());
745  }
746 
747  if (InPod()) {
748  m_ship->Move(m_locationID, flagCapsule, true);
749  } else {
751  m_ship->Move(m_locationID, flagNone, true);
752  }
753 
754  // once systemData.radius implemented, remove this in favor of below check
755  m_ship->SetPosition(pt);
756  /* comment this block for later use...
757  * m_SystemData.radius is not populated yet, and this does weird things with ships
758  // verify 'pt' is within system boundaries
759  if (pt.length() < m_SystemData.radius) {
760  m_ship->SetPosition(pt);
761  } else {
762  ; // oob
763  }
764  */
765 
766  char ci[45];
767  if (sDataMgr.IsStation(m_locationID)) {
768  _log(PLAYER__WARNING, "MoveToLocation() - Character %s (%u) Docked in %u.", m_char->name(), m_char->itemID(), m_locationID);
769  stDataMgr.GetStationData(m_locationID, m_StationData);
770  snprintf(ci, sizeof(ci), "Docked: %s(%u)", GetName(), m_char->itemID());
771  m_char->Move(m_locationID, flagNone, true);
772  m_ship->Move(m_locationID, flagHangar, true);
773 
774  if (IsFleetID(m_fleet)) {
776  if (IsFleetBooster()) {
777  std::list<int32> wing, squad;
778  wing.clear();
779  squad.clear();
780  if (IsSquadID(m_squad)) {
781  squad.emplace(squad.end(), m_squad);
782  } else if (IsWingID(m_wing)) {
783  wing.emplace(wing.end(), m_wing);
784  }
785  sFltSvc.UpdateBoost(m_fleet, IsFleetBoss(), wing, squad);
786  }
787  }
788 
789  if (!IsHangarLoaded(m_locationID))
790  LoadStationHangar(m_locationID);
792  DestroyShipSE();
793  StationItemRef sRef = sEntityList.GetStationByID(m_locationID);
794  if (sRef.get() != nullptr) {
796  sRef->AddGuest(this);
797  }
798  m_bubbleWait = true; // deny client processing of subsquent destiny msgs
799  } else {
800  _log(PLAYER__WARNING, "MoveToLocation() - Character %s(%u) InSpace in %u. (setState %s, beyonce %s)", \
801  m_char->name(), m_char->itemID(), m_locationID, m_setStateSent ? "true" : "false", m_beyonce ? "true" : "false");
802  snprintf(ci, sizeof(ci), "InSpace: %s(%u)", GetName(), m_char->itemID());
803 
804  // if docked, update guestlist
805  if (wasDocked and m_undock)
807 
808  if (IsFleetID(m_fleet)) {
810  if (IsFleetBooster()) {
811  std::list<int32> wing, squad;
812  wing.clear();
813  squad.clear();
814  if (IsSquadID(m_squad)) {
815  squad.emplace(squad.end(), m_squad);
816  } else if (IsWingID(m_wing)) {
817  wing.emplace(wing.end(), m_wing);
818  }
819  sFltSvc.UpdateBoost(m_fleet, IsFleetBoss(), wing, squad);
820  }
821  }
822 
823  if (m_char->flag() != flagPilot)
824  m_char->Move(m_shipId, flagPilot, true);
825 
826  if (pShipSE != nullptr)
828 
829  SetDestiny(pt);
830 
831  if (IsJump() and !m_autoPilot)
832  pShipSE->DestinyMgr()->Stop();
833  }
834 
835  m_ship->SetCustomInfo(ci);
836 
837  if (!m_login)
838  m_ship->SaveShip(); // this saves everything on ship
839 
840  uint32 stationID(sDataMgr.IsStation(m_locationID) ? m_locationID : 0);
841  m_char->SetLocation(stationID, m_SystemData);
842 
843  UpdateSession();
845 }
846 
847 void Client::SetDestiny(const GPoint& pt, bool update/*false*/) {
848  if (!sDataMgr.IsSolarSystem(m_locationID)) {
849  _log(CLIENT__ERROR, "%s(%u) - Calling SetDestiny() when not in space.", GetName(), m_char->itemID());
850  return;
851  }
852  m_bubbleWait = false; // allow client processing of subsquent destiny msgs
853  m_setStateSent = false;
854 
855  bool updateShip = false;
856  if (pShipSE == nullptr) {
857  updateShip = true;
858  CreateShipSE();
859  }
860 
861  if (pShipSE->SystemMgr()->GetID() != m_system->GetID())
862  _log(CLIENT__ERROR, "%s(%u) - Ship SysID of %u != Client SysID of %u.", GetName(), m_char->itemID(), pShipSE->SystemMgr()->GetID(), m_system->GetID());
863 
864  _log(PLAYER__AP_TRACE, "Client::SetDestiny(): shipSystemID: %u, SystemID: %u, update: %s, updateShip: %s, jump: %s, cloak: %s", \
865  pShipSE->SystemMgr()->GetID(), m_system->GetID(), update?"true":"false", \
866  updateShip?"true":"false", IsJump()?"true":"false", pShipSE->DestinyMgr()->IsCloaked()?"true":"false");
867 
868  if (pt.isZero()) {
869  if (pShipSE->GetPosition().isZero()) {
871  } else {
873  }
874  } else {
875  pShipSE->DestinyMgr()->SetPosition(pt, update);
876  }
877 
878  //if (m_login)
879  // pShipSE->DestinyMgr()->SetCloak(true);
880 
882 
883  if (updateShip)
884  UpdateNewShip();
885 }
886 
888  _log(PLAYER__AP_TRACE, "Client::SetBallPark(): State: %s, SetState: %s, Beyonce: %s", \
889  GetStateName(m_clientState).c_str(), m_setStateSent?"true":"false", m_beyonce?"true":"false");
890  m_bubbleWait = false; // allow client processing of subsequent destiny msgs
891  if (pShipSE->SysBubble() == nullptr)
893  if (!m_beyonce and !m_login and !m_undock) {
894  m_bubbleWait = true; // wait on proc destiny msgs
896  SetBallParkTimer(Player::Timer::Default); // set timer 1s to wait for beyonce
897  return;
898  }
899  if (!m_setStateSent and m_beyonce) { // MUST have beyonce before sending state data.
902  if (IsJump()) {
904  // dont use timer method here...(jumping ship will flash at destination)
907  }
908  }
909  if (m_undock)
911 }
912 
914  if (!m_ballparkTimer.Enabled()) {
915  sLog.Error("CheckBallparkTimer()", "BallPark Timer is disabled.");
916  } else {
917  sLog.Warning("CheckBallparkTimer()", "BallPark Time remaining %ums", m_ballparkTimer.GetRemainingTime());
918  }
919 
920  _log(CLIENT__TIMER, "CheckBallparkTimer(): State: %s, SetState: %s, Beyonce: %s, Login: %s", \
921  GetStateName(m_clientState).c_str(), m_setStateSent?"true":"false", \
922  m_beyonce?"true":"false", m_login?"true":"false");
923  _log(CLIENT__TIMER, "CheckBallparkTimer(): invul: %s, cloak: %s, bubblewait: %s", m_invul?"true":"false", \
924  pShipSE == nullptr? "ship null": pShipSE->DestinyMgr() == nullptr? "destiny null": pShipSE->DestinyMgr()->IsCloaked()?"true":"false", \
925  m_bubbleWait?"true":"false");
926 }
927 
929  if ((pShipSE == nullptr) or (pShipSE->DestinyMgr() == nullptr)) {
930  CreateShipSE();
931  pShipSE->SetPilot(this);
933  UpdateNewShip();
934  }
935  pShipSE->DestinyMgr()->SetPosition(pt, true);
936  if (m_undock)
937  return;
938  if (pShipSE->DestinyMgr()->IsMoving())
939  pShipSE->DestinyMgr()->Halt();
940 }
941 
943  pShipSE->Dock();
944  // ap cleared on client side when docking.
945  m_autoPilot = false;
946  m_setStateSent = false;
948  _log(AUTOPILOT__TRACE, "DockToStation()() - m_clientState set to Idle");
950  m_bubbleWait = true; // deny client processing of subsquent destiny msgs
951 
952  //Check if player is in pod and have no ships in hangar, in which case they get a rookie ship for free
953  // on live, SCC sends mail about the loss of the players ship, and offers a shiny, new, fully-fitted ship as replacement. we dont....yet
954  // this needs to be done before player is docked
955  if (m_ship->typeID() == itemTypeCapsule) {
956  if (sConfig.server.NoobShipCheck) {
958  if (sRef.get() == nullptr) {
959  _log(CLIENT__ERROR, "%s(%u): DockToStation() - Station %u not found in inventory of %s(%u).", \
961  } else if (!sRef->HasShip(this)) { // need to get hangar items (flagHangar) by owner
963  }
964  } else {
966  }
967  }
968 
970 
971  SetSessionTimer();
972  m_ship->SetDocked();
973 }
974 
976  if (m_TS != nullptr) {
977  TradeService* mts = (TradeService*)(m_services.LookupService("trademgr"));
978  mts->CancelTrade(this);
979  }
980 
981  m_invul = true;
982  m_undock = true;
983  //set position and direction of docking ramp for later use
986 
987  m_ship->Undock();
988 
999  SetSessionTimer();
1000 
1001  m_ship->SetUndocking(false);
1002 }
1003 
1005  FactionData data = FactionData();
1006  data.allianceID = GetAllianceID();
1008  data.factionID = GetWarFactionID();
1009  data.ownerID = GetCharacterID();
1010  pShipSE = new ShipSE(m_ship, *(m_system->GetServiceMgr()), m_system, data);
1011  _log(PLAYER__MESSAGE, "CreateShipSE() - pShipSE %p created for %s(%u)", pShipSE, m_char->name(), m_char->itemID());
1012 }
1013 
1015  if (pShipSE != nullptr) {
1016  _log(PLAYER__MESSAGE, "DestroyShipSE() - pShipSE %p (%s) destroyed for %s(%u)", pShipSE, m_ship->name(), m_char->name(), m_char->itemID());
1019  } else {
1020  _log(PLAYER__WARNING, "DestroyShipSE() - pShipSE = null for %s(%u)", m_char->name(), m_char->itemID());
1021  }
1022  pShipSE = nullptr;
1023 }
1024 
1026 {
1027  sItemFactory.SetUsingClient(this);
1028  pShipSE->SetPilot(this);
1030  sItemFactory.UnsetUsingClient();
1031 
1032  char ci[45];
1033  snprintf(ci, sizeof(ci), "InSpace: %s(%u)", GetName(), m_char->itemID());
1034  m_ship->SetCustomInfo(ci);
1035  SetSessionTimer();
1036 }
1037 
1039  if (!IsPlayerItem(m_char->capsuleID())) {
1040  CreateNewPod();
1041  } else {
1042  m_pod = sItemFactory.GetShip(m_char->capsuleID());
1043  }
1044  if (m_pod.get() == nullptr)
1045  CreateNewPod();
1046 }
1047 
1048 // can throw
1050 {
1051  if (newShipRef.get() == nullptr) {
1052  _log(PLAYER__ERROR, "CheckShipRef() - %s: newShipRef == NULL.", m_char->name());
1053  throw CustomError ("Could not find ship's ItemRef. Cannot Board. Ref: ServerError 12321.");
1054  } else if (!newShipRef->isSingleton()) {
1055  _log(PLAYER__MESSAGE, "%s tried to board ship %u, which is not assembled.", m_char->name(), newShipRef->itemID());
1056  throw CustomError ("You cannot board a ship which is not assembled!");
1057  } else if ((m_ship == newShipRef) and !m_login) {
1058  // if char is loging in, this will hit. unknown about any other time.
1059  _log(PLAYER__MESSAGE, "%s tried to board active ship %u.", m_char->name(), newShipRef->itemID());
1060  throw CustomError ("You are already aboard this ship.");
1061  }
1062 }
1063 
1065 {
1066  CheckShipRef(newShipRef);
1067 
1068  if (m_login) {
1069  _log(PLAYER__MESSAGE, "%s boarding active ship %u on login.", m_char->name(), newShipRef->itemID());
1070  } else if (m_ship->typeID() == itemTypeCapsule) {
1072  m_ship->Move(m_system->GetID(), flagCapsule, true);
1073  m_ship->SetCustomInfo(nullptr);
1074  } else {
1075  char ci[45];
1076  snprintf(ci, sizeof(ci), "Inactive: %s(%u)", GetName(), m_char->itemID());
1077  m_ship->SetCustomInfo(ci);
1079  m_ship->SaveShip();
1080  }
1081 
1082  SetShip(newShipRef);
1083  SetSessionTimer();
1084 }
1085 
1086 void Client::Board(ShipSE* newShipSE)
1087 {
1088  CheckShipRef(newShipSE->GetShipItemRef());
1089 
1090  if (m_ship->typeID() == itemTypeCapsule) {
1092  m_ship->Move(m_system->GetID(), flagCapsule, true);
1093  // cannot use DestroyShipSE() for this. it removes current shipSE, with pilot, like pilot is leaving bubble.
1094  ShipSE* oldShipSE = pShipSE;
1095  // set vars to new ship
1096  SetShip(newShipSE->GetShipItemRef());
1097  pShipSE = newShipSE;
1098  // remove pod entity
1099  m_system->RemoveEntity(oldShipSE);
1100  SafeDelete(oldShipSE);
1101  } else { // you can xfer direct from one ship from another.
1102  // check for POS/FF in bubble. check for ship in FF. if so, then not abandoned.
1103  bool abandoned = true;
1104  if (pShipSE->SysBubble()->HasTower()) {
1105  TowerSE* ptSE = pShipSE->SysBubble()->GetTowerSE();
1106  if (ptSE->HasForceField())
1107  if (pShipSE->GetPosition().distance(ptSE->GetPosition()) < ptSE->GetSOI())
1108  abandoned = false;
1109  }
1110 
1111  char ci[45];
1112  if (abandoned) {
1113  pShipSE->Abandon();
1114  snprintf(ci, sizeof(ci), "Abandoned: %s(%u)", GetName(), m_char->itemID());
1115  } else
1116  snprintf(ci, sizeof(ci), "Ejected: %s(%u)", GetName(), m_char->itemID());
1117 
1118  m_ship->SetCustomInfo(ci);
1120  m_ship->Eject();
1121 
1122  pShipSE->DestinyMgr()->Eject();
1123 
1124  SetShip(newShipSE->GetShipItemRef());
1125  pShipSE = newShipSE;
1126  }
1127 
1128  UpdateNewShip();
1129  //SetStateTimer(Player::State::Board, Player::Timer::Board);
1131 }
1132 
1134 {
1135  if (m_pod.get() == nullptr)
1136  CreateNewPod();
1137 
1138  if (m_pod.get() == nullptr) {
1139  _log(SHIP__ERROR, "Handle_Eject() - Failed to get podItem for %s.", GetName());
1140  if (m_canThrow) {
1141  throw CustomError ("Something bad happened as you prepared to eject. Ref: ServerError 25107.");
1142  } else {
1143  return;
1144  }
1145  }
1146  // this should NEVER happen...
1147  if (pShipSE->SysBubble() == nullptr) {
1148  _log(SHIP__ERROR, "Handle_Eject() - Bubble is null for %s.", GetName());
1149  if (m_canThrow) {
1150  throw CustomError ("Something bad happened as you prepared to eject. Ref: ServerError 25107+1.");
1151  } else {
1152  return;
1153  }
1154  }
1155 
1156  // check for POS/FF in bubble. check for ship in FF. if so, then not abandoned.
1157  bool abandoned = true;
1158  if (pShipSE->SysBubble()->HasTower()) {
1159  TowerSE* ptSE = pShipSE->SysBubble()->GetTowerSE();
1160  if (ptSE->HasForceField())
1161  if (pShipSE->GetPosition().distance(ptSE->GetPosition()) < ptSE->GetSOI())
1162  abandoned = false;
1163  }
1164 
1165  char ci[45];
1166  if (abandoned) {
1167  pShipSE->Abandon();
1168  snprintf(ci, sizeof(ci), "Abandoned: %s(%u)", GetName(), m_char->itemID());
1169  } else {
1170  snprintf(ci, sizeof(ci), "Ejected: %s(%u)", GetName(), m_char->itemID());
1171  }
1172 
1173  m_ship->SetCustomInfo(ci);
1174  m_ship->SetPlayer(nullptr);
1176  m_ship->Eject();
1177 
1178  pShipSE->DestinyMgr()->Eject();
1179 
1180  GPoint capsulePosition(pShipSE->GetPosition());
1181  capsulePosition.MakeRandomPointOnSphere(m_ship->radius() + m_pod->radius() + MakeRandomInt(30, 120));
1182  m_pod->SetPosition(capsulePosition);
1184 
1185  FactionData data = FactionData();
1186  data.ownerID = GetCharacterID();
1187  data.factionID = GetWarFactionID();
1188  data.allianceID = GetAllianceID();
1190  ShipSE* newShipSE = new ShipSE(m_pod, *(m_system->GetServiceMgr()), m_system, data);
1191  if (newShipSE == nullptr) {
1192  _log(PLAYER__ERROR, "%s Eject() - pShipSE = NULL for shipID %u.", m_char->name(), m_pod->itemID());
1193  // we should probably send char to their clone station if this happens....
1195  throw CustomError ("There was a problem creating your pod in space.<br>You have been transfered to your home station.<br>Ref: ServerError 15107.");
1196  }
1197 
1198  newShipSE->SetLauncherID(pShipSE->GetID());
1199  // set shipSE to null. this allows sending AddBalls when pod added to system
1200  SetShip(m_pod);
1201  m_system->AddEntity(newShipSE);
1202  pShipSE = newShipSE;
1203 
1204  UpdateNewShip();
1205  //SetStateTimer(Player::State::Board, Player::Timer::Board);
1207 }
1208 
1210 {
1211  m_autoPilot = false;
1212  m_bubbleWait = false; // allow client processing of subsquent destiny msgs
1213 
1214  if (m_pod.get() == nullptr)
1215  CreateNewPod();
1216 
1217  m_pod->SetPosition(position);
1218 
1219  FactionData data = FactionData();
1220  data.allianceID = GetAllianceID();
1222  data.factionID = GetWarFactionID();
1223  data.ownerID = GetCharacterID();
1224  ShipSE* newShipSE = new ShipSE(m_pod, *(m_system->GetServiceMgr()), m_system, data);
1225  if (newShipSE == nullptr) {
1226  _log(PLAYER__ERROR, "%s ResetAfterPopped() - pShipSE = NULL for shipID %u.", m_char->name(), m_pod->itemID());
1227  // we should probably send char to their clone station if this happens....
1230  throw CustomError ("There was a problem creating your pod in space.<br>You have been transfered to your home station.<br>Ref: ServerError 15107.");
1231  }
1232 
1233  newShipSE->SetLauncherID(pShipSE->GetID());
1234  pShipSE->DestinyMgr()->Eject();
1235  // nullify pilot before removing from bubble, which removes player from bubble map
1236  pShipSE->SetPilot(nullptr);
1237  // remove dead ship from bubble before calling SetShip() (it deletes pShipSE)
1238  sBubbleMgr.Remove(pShipSE);
1239  // set shipSE to null. this allows sending AddBalls when pod added to system
1240  SetShip(m_pod);
1241  // just in case something's a bit off, reset pod to full
1242  m_pod->Heal();
1243  // add pod to system
1244  m_system->AddEntity(newShipSE);
1245  pShipSE = newShipSE;
1246 
1247  UpdateNewShip();
1248  //SetStateTimer(Player::State::Killed, Player::Timer::Killed);
1250 }
1251 
1259  m_autoPilot = false;
1260 
1261  CreateNewPod();
1262  SetShip(m_pod);
1263 
1265 
1267  m_ship->SaveShip();
1268  m_char->ResetClone();
1269  m_char->SaveCharacter();
1270 
1272 
1273  //update session with new values
1274  UpdateSession();
1276 }
1277 
1279  shipRef->ChangeOwner(m_char->itemID());
1280  if (pShipSE != nullptr)
1281  pShipSE->SetPilot(nullptr);
1282 
1283  // nullify ship pointer, but do NOT delete...most callers need existing ship for system and destiny pointers
1284  pShipSE = nullptr;
1285 
1286  m_ship = shipRef;
1287  m_shipId = shipRef->itemID();
1289  if (sDataMgr.IsSolarSystem(m_locationID)) {
1290  m_char->Move(m_shipId, flagPilot, true);
1291  pSession->SetInt("shipid", m_shipId); // update shipID in session
1292  }
1293 
1295  m_ship->SetPlayer(this);
1296 }
1297 
1299  if (m_char.get() != nullptr)
1301 }
1302 
1304  std::string pod_name = m_char->itemName() + "'s Capsule";
1305  ItemData podItem( itemTypeCapsule, m_char->itemID(), locTemp, flagNone, pod_name.c_str() );
1306  m_pod = sItemFactory.SpawnShip( podItem );
1307  // make sure this is singleton
1308  m_pod->ChangeSingleton(true);
1309  m_pod->Move(m_char->solarSystemID(), flagCapsule);
1310  m_pod->SaveShip();
1311  m_char->SetActivePod(m_pod->itemID()); // is this used?
1312 }
1313 
1316  //create rookie ship of appropriate type
1317  using namespace Char;
1318  uint16 shipID(0), gunID(0);
1319  switch (m_char->race()) {
1320  case Race::Caldari: {
1321  gunID = Rookie::Weapon::Caldari;
1322  shipID = Rookie::Ship::Caldari;
1323  } break;
1324  case Race::Gallente: {
1325  gunID = Rookie::Weapon::Gallente;
1326  shipID = Rookie::Ship::Gallente;
1327  } break;
1328  case Race::Minmatar: {
1329  gunID = Rookie::Weapon::Minmatar;
1330  shipID = Rookie::Ship::Minmatar;
1331  } break;
1332  case Race::Amarr: {
1333  gunID = Rookie::Weapon::Amarr;
1334  shipID = Rookie::Ship::Amarr;
1335  } break;
1336  default: {
1337  // invalid race
1338  _log(CLIENT__ERROR, "SpawnNewRookieShip() - Invalid Race of %s(%u) for %s(%u)",
1339  sDataMgr.GetRaceName(m_char->race()), m_char->race(), m_char->name(),
1340  m_char->itemID());
1341  return ShipItemRef(nullptr);
1342  }
1343  }
1344 
1345  //create data for new rookie ship
1346  std::string name = m_char->itemName() + "'s Noob Ship";
1347  ItemData sData(shipID, m_char->itemID(), locTemp, flagNone, name.c_str());
1348  //spawn rookie ship
1349  ShipItemRef sRef = sItemFactory.SpawnShip(sData);
1350  if (sRef.get() != nullptr) {
1351  // noob ships come pre-assembled (and "fully fit")
1352  sRef->ChangeSingleton(true);
1353  sRef->Move(stationID, flagHangar);
1354  }
1355  // create and fit noob items in ship
1357  InventoryItemRef mRef = sItemFactory.SpawnItem(mData);
1358  if (mRef.get() != nullptr) {
1359  mRef->ChangeSingleton(true);
1360  mRef->Move(sRef->itemID(), flagHiSlot0);
1361  mRef->SetAttribute(AttrOnline, EvilOne, false);
1362  }
1363  ItemData wData(gunID, m_char->itemID(), locTemp, flagNone);
1364  InventoryItemRef wRef = sItemFactory.SpawnItem(wData);
1365  if (wRef.get() != nullptr) {
1366  wRef->ChangeSingleton(true);
1367  wRef->Move(sRef->itemID(), flagHiSlot1);
1368  wRef->SetAttribute(AttrOnline, EvilOne, false);
1369  }
1370  ItemData cData(itemTypeTrit, m_char->itemID(), locTemp, flagNone, 100);
1371  InventoryItemRef cRef = sItemFactory.SpawnItem(cData);
1372  if (cRef.get() != nullptr)
1373  cRef->Move(sRef->itemID(), flagCargoHold);
1374  // save new ship and items
1375  sRef->SaveShip();
1376 
1377  // in case caller needs ref to new ship
1378  return sRef;
1379 }
1380 
1382  if (m_jetcanTimer.Enabled()) {
1383  return (m_jetcanTimer.Check(false));
1384  } else {
1385  return true;
1386  }
1387 }
1388 
1390  PyDict* dict(nullptr);
1391  /*
1392  * for aggressorID, aggressor in aggressors.iteritems():
1393  * for aggresseeID, lastAggression in aggressor.iteritems():
1394  * lastAggression = int(lastAggression / SEC) * SEC
1395  * when = lastAggression + const.aggressionTime * MIN
1396  * self.clearAggressions[aggressorID, aggresseeID, solarsystemID] = when
1397  *
1398  * aggressionTime = 15
1399  */
1400  /* items are set here as
1401  * [PyInt 90971469] <- entity (aggressorID)
1402  * [PyDict 1 kvp] <- dictionary
1403  * [PyInt 1000127] <- entity (aggresseeID)
1404  * [PyIntegerVar 129550906897224125] <- beginning timestamp (lastAggression)
1405  */
1406 
1407  return dict;
1408 }
1409 
1410 void Client::StargateJump(uint32 fromGate, uint32 toGate) {
1412  sLog.Error("Client","%s: StargateJump called when a move is already pending. Ignoring.", m_char->name());
1413  // send client msg about state change in progress
1414  return;
1415  }
1416 
1417  // add jump to mapDynamicData for showing in StarMap (F10) -allan 06Mar14
1419 
1420  // call Stop() per packet sniff - shuts off AP. Halt() does also. try not calling any movement updates
1421  //pShipSE->DestinyMgr()->Halt(); // Stop() disables ap. try Halt() to reset ship movement to null
1422  pShipSE->DestinyMgr()->SendJumpOut(fromGate);
1423  // show gate animation in from gate. -working -allan 15Nov15
1424  pShipSE->DestinyMgr()->SendGateActivity(fromGate);
1425 
1426  //m_toGate = toGate;
1427  StaticData toData = StaticData();
1428  if (!sDataMgr.GetStaticInfo(toGate, toData)) {
1429  _log(DATA__ERROR, "Failed to retrieve data for stargate %u", toGate);
1430  // send client msg about new system info failure
1431  return;
1432  }
1433 
1434  // this is where we can put the msgs about system closed or w/e
1435 
1436  // add jump to mapDynamicData for showing in StarMap (F10) -allan 06Mar14
1437  MapDB::AddJump(toData.systemID);
1438  // used for showing Visited Systems in StarMap(F10) -allan 30Jan14
1439  m_char->VisitSystem(toData.systemID);
1440 
1441  m_movePoint = toData.position;
1442  // Make Jump-In point a random spot on ~10km radius sphere about the stargate radius
1443  m_movePoint.MakeRandomPointOnSphereLayer(toData.radius + 6500, toData.radius + 9500);
1444  m_moveSystemID = toData.systemID;
1445 /*
1446  char ci[25];
1447  snprintf(ci, sizeof(ci), "Jumping:%u", toGate);
1448  m_ship->SetCustomInfo(ci);
1449 */
1450  //delay the move 4sec so they can see the JumpOut animation
1452 }
1453 
1456  sLog.Error("Client","%s: CynoJump called when a move is already pending. Ignoring.", m_char->name());
1457  // send client msg about state change in progress
1458  return;
1459  }
1460 
1462 
1463  m_moveSystemID = beacon->locationID();
1466 
1468 
1469  m_movePoint = beacon->position();
1471 
1473 }
1474 
1476  if (m_movePoint == NULL_ORIGIN) { // this is part of infant AP hack
1478  _log(AUTOPILOT__TRACE, "ExecuteJump() - movePoint = null; state set to Idle");
1479  return;
1480  }
1481 
1482  //OnScannerInfoRemoved - no args. flushes scan data in client
1483  SendNotification("OnScannerInfoRemoved", "charid", new PyTuple(0), true); // this is sequenced
1484  pShipSE->Jump();
1485 
1487 
1489 
1491  m_moveSystemID = 0;
1492 }
1493 
1495  if (m_movePoint == NULL_ORIGIN) { // this is part of infant AP hack
1497  _log(AUTOPILOT__TRACE, "ExecuteJump() - movePoint = null; state set to Idle");
1498  return;
1499  }
1500 
1501  //OnScannerInfoRemoved - no args. flushes scan data in client
1502  SendNotification("OnScannerInfoRemoved", "charid", new PyTuple(0), true); // this is sequenced
1503  pShipSE->Jump(false);
1504 
1506 
1507  JumpInEffect();
1508 
1510 
1512  m_moveSystemID = 0;
1513 }
1514 
1515 void Client::SetBallParkTimer(uint32 time/*Player::Timer::Default*/)
1516 {
1517  if (time == 0) {
1519  _log(CLIENT__TIMER, "%s: Ballpark Timer Disabled", m_char->name());
1520  return;
1521  }
1522 
1523  if (m_ballparkTimer.Enabled()) {
1524  _log(CLIENT__ERROR, "%s: Ballpark Timer called but timer already enabled with %ums remaining.", m_char->name(), m_ballparkTimer.GetRemainingTime());
1525  EvE::traceStack();
1526  return;
1527  }
1528 
1529  _log(CLIENT__TIMER, "%s: Ballpark Timer set at %ums. current state time is %ums", m_char->name(), time, m_ballparkTimer.GetCurrentTime());
1530  m_ballparkTimer.Start(time);
1531 }
1532 
1533 void Client::SetCloakTimer(uint32 time/*Player::Timer::Default*/)
1534 {
1535  if (time == 0) {
1537  if (pShipSE != nullptr)
1538  if (pShipSE->DestinyMgr() != nullptr)
1539  pShipSE->DestinyMgr()->UnCloak();
1540  _log(CLIENT__TIMER, "%s: Cloak Timer Disabled");
1541  return;
1542  }
1543 
1544  if (m_cloakTimer.Enabled()) {
1545  _log(CLIENT__ERROR, "%s: Cloak Timer called but timer already enabled with %ums remaining.", m_char->name(), m_cloakTimer.GetRemainingTime());
1546  EvE::traceStack();
1547  return;
1548  }
1549 
1550  _log(CLIENT__TIMER, "%s: Cloak Timer set at %ums. current state time is %ums", m_char->name(), time, m_cloakTimer.GetCurrentTime());
1551  m_cloakTimer.Start(time);
1552  if (m_login)
1553  return;
1554  if (pShipSE != nullptr)
1555  if (pShipSE->DestinyMgr() != nullptr)
1556  pShipSE->DestinyMgr()->Cloak();
1557 }
1558 
1559 void Client::SetUncloakTimer(uint32 time/*Player::Timer::Default*/)
1560 {
1561  if (time == 0) {
1563  SetUncloak(false);
1564  _log(CLIENT__TIMER, "%s: Uncloak Timer Disabled");
1565  return;
1566  }
1567 
1568  if (m_uncloakTimer.Enabled()) {
1569  _log(CLIENT__ERROR, "%s: Uncloak Timer called but timer already enabled with %ums remaining.", m_char->name(), m_cloakTimer.GetRemainingTime());
1570  EvE::traceStack();
1571  return;
1572  }
1573 
1574  _log(CLIENT__TIMER, "%s: Uncloak Timer set at %ums. current state time is %ums", m_char->name(), time, m_uncloakTimer.GetCurrentTime());
1575  m_uncloakTimer.Start(time);
1576  SetUncloak(true);
1577 }
1578 
1579 void Client::SetInvulTimer(uint32 time/*Player::Timer::Default*/)
1580 {
1581  if (time == 0) {
1582  SetInvul(false);
1584  _log(CLIENT__TIMER, "%s: Invul Timer Disabled");
1585  return;
1586  }
1587 
1588  if (m_invulTimer.Enabled()) {
1589  _log(CLIENT__ERROR, "%s: Invul Timer called but timer already enabled with %ums remaining.", m_char->name(), m_invulTimer.GetRemainingTime());
1590  EvE::traceStack();
1591  return;
1592  }
1593 
1594  _log(CLIENT__TIMER, "%s: Invul Timer set at %ums. current state time is %ums", m_char->name(), time, m_invulTimer.GetCurrentTime());
1595  m_invulTimer.Start(time);
1596  SetInvul(true);
1597 }
1598 
1599 void Client::SetStateTimer( int8 state, uint32 time/*Player::Timer::Default*/)
1600 {
1601  if (time == 0) {
1603  _log(CLIENT__TIMER, "%s: State Timer Disabled");
1604  return;
1605  }
1606 
1607  if (m_stateTimer.Enabled()) {
1608  _log(CLIENT__ERROR, "%s: State Timer called but timer already enabled with %ums remaining.", m_char->name(), m_stateTimer.GetRemainingTime());
1609  EvE::traceStack();
1610  return;
1611  }
1612 
1613  _log(CLIENT__TIMER, "%s: Client Timer set from %s to %s at %ums. current state time: %u", m_char->name(), \
1614  GetStateName(m_clientState).c_str(), GetStateName(state).c_str(), time, m_stateTimer.GetCurrentTime());
1615  m_clientState = state;
1616  m_stateTimer.Start(time);
1617 }
1618 
1619 // these next two are for sending jump effects (easier to test here)
1621 {
1622  if (pShipSE != nullptr)
1623  if (pShipSE->DestinyMgr() != nullptr)
1624  if (!pShipSE->DestinyMgr()->IsCloaked())
1625  pShipSE->DestinyMgr()->SendJumpInEffect("effects.JumpIn");
1626 }
1627 
1629 {
1630  if (pShipSE != nullptr)
1631  if (pShipSE->DestinyMgr() != nullptr)
1632  if (!pShipSE->DestinyMgr()->IsCloaked())
1633  pShipSE->DestinyMgr()->SendJumpOutEffect("effects.JumpOut", locationID);
1634 }
1635 
1637 {
1638  switch (state) {
1639  case Player::State::Idle: return "Idle";
1640  case Player::State::Jump: return "Jump";
1641  case Player::State::DriveJump: return "DriveJump";
1642  case Player::State::Dock: return "Dock";
1643  case Player::State::Undock: return "Undock";
1644  case Player::State::Killed: return "Killed";
1645  case Player::State::Logout: return "Logout";
1646  case Player::State::Board: return "Board";
1647  case Player::State::Login: return "Login";
1648  }
1649  return "Undefined";
1650 }
1651 
1653  m_hangarLoaded.insert(std::make_pair(stationID, true));
1654 }
1655 
1657  m_hangarLoaded.erase(hangarID);
1658 }
1659 
1661  std::map<uint32, bool>::const_iterator itr = m_hangarLoaded.find(hangarID);
1662  if (itr != m_hangarLoaded.end())
1663  return itr->second;
1664  return false;
1665 }
1666 
1668  _log(PLAYER__INFO, "Client::LoadStationHangar() is loading personal hangar for %s(%u) in stationID %u", m_char->name(), m_char->itemID(), stationID);
1669  sItemFactory.SetUsingClient(this);
1671  sItemFactory.UnsetUsingClient();
1672 }
1673 
1675 {
1676  sItemFactory.SetUsingClient(this);
1677  InventoryItemRef iRef = sItemFactory.GetItem(itemID);
1678  if (iRef.get() == nullptr) {
1679  _log(INV__ERROR, "Client::MoveItem() - %s Unable to load item %u", m_char->name(), itemID);
1680  return;
1681  }
1682 
1683  EVEItemFlags oldflag = flagIllegal;
1684  oldflag = iRef->flag();
1685 
1686  iRef->Move(location, flag, true);
1687 
1688  if (IsPlayerItem(location)) {
1689  if (IsModuleSlot(iRef->flag())) {
1690  m_ship->UpdateModules(iRef->flag());
1691  } else if (IsCargoHoldFlag(iRef->flag()) or (iRef->flag() == flagDroneBay)) {
1692  // do nothing here. this is to avoid throwing error msg below
1693  } else {
1694  _log(INV__WARNING, "Client::MoveItem() - %s Unhandled PlayerItem %s (%u) from flag %s to flag %s.", \
1695  m_char->name(), iRef->name(), itemID, sDataMgr.GetFlagName(oldflag), sDataMgr.GetFlagName(flag));
1696  }
1697  } else {
1698  _log(INV__WARNING, "Client::MoveItem() - %s Unhandled NonPlayerItem %s (%u) from flag %s to flag %s.", \
1699  m_char->name(), iRef->name(), itemID, sDataMgr.GetFlagName(oldflag), sDataMgr.GetFlagName(flag));
1700  }
1701  sItemFactory.UnsetUsingClient();
1702 }
1703 
1705  std::map<uint32, uint32>::iterator itr = m_lpMap.find(corpID);
1706  if (itr != m_lpMap.end())
1707  return itr->second;
1708  return 0;
1709 }
1710 
1712 {
1713  uint16 count = qty;
1714  InventoryItemRef iRef(nullptr);
1715  if (sDataMgr.IsStation(m_locationID)) {
1716  iRef = sItemFactory.GetStationItem(m_locationID)->GetMyInventory()->GetByTypeFlag(typeID, flagHangar);
1717  if (iRef.get() != nullptr) {
1718  if (count < iRef->quantity()) {
1719  iRef->AlterQuantity(count, true);
1720  count = 0;
1721  } else {
1722  count -= iRef->quantity();
1723  iRef->Delete();
1724  }
1725  }
1726  }
1727 
1728  if (count) {
1729  iRef = GetShip()->GetMyInventory()->GetByTypeFlag(typeID, flagCargoHold);
1730  if (iRef.get() != nullptr){
1731  if (count < iRef->quantity()) {
1732  iRef->AlterQuantity(count, true);
1733  count = 0;
1734  } else {
1735  count -= iRef->quantity();
1736  iRef->Delete();
1737  }
1738  }
1739  }
1740  if (count)
1741  ; // make error here for not enough?
1742 }
1743 
1744 bool Client::ContainsTypeQty(uint16 typeID, uint32 qty) const
1745 {
1746  uint16 count = 0;
1747  InventoryItemRef iRef(nullptr);
1748  // this is for missions....we will have to determine if we have the TOTAL qty desired, in both cargo and hangar
1749  if (sDataMgr.IsStation(m_locationID)) {
1750  iRef = sItemFactory.GetStationItem(m_locationID)->GetMyInventory()->GetByTypeFlag(typeID, flagHangar);
1751  if (iRef.get() != nullptr)
1752  count = iRef->quantity();
1753  }
1754 
1755  iRef = GetShip()->GetMyInventory()->GetByTypeFlag(typeID, flagCargoHold);
1756  if (iRef.get() != nullptr)
1757  count += iRef->quantity();
1758 
1759  if (count >= qty)
1760  return true;
1761  return false;
1762 }
1763 
1765 {
1766  // dont know all the stipulations of "completion" yet, but skeleton code for starters...
1767  switch (data.typeID) {
1768  case Mission::Type::Tutorial: {
1769  } break;
1770  case Mission::Type::Encounter: {
1771  } break;
1772  case Mission::Type::Courier: {
1773  if (m_locationID == data.destinationID)
1775  return true;
1776  } break;
1777  case Mission::Type::Trade: {
1778  } break;
1779  case Mission::Type::Mining: {
1780  } break;
1781  case Mission::Type::Research: {
1782  } break;
1783  case Mission::Type::Data: {
1784  } break;
1785  case Mission::Type::Storyline: {
1786  } break;
1787  case Mission::Type::Cosmos: {
1788  } break;
1789  case Mission::Type::Arc: {
1790  } break;
1791  case Mission::Type::Anomic: {
1792  } break;
1793  }
1794 
1795  return false;
1796 }
1797 
1798 
1800  m_channels.insert(chan);
1801 }
1802 
1804  if (m_loaded)
1805  m_channels.erase(chan);
1806 }
1807 
1808 /************************************************************************/
1809 /* character notification messages wrapper */
1810 /************************************************************************/
1812  // clear station data
1813  // remove client from station guest list
1814  sEntityList.GetStationByID(m_StationData.stationID)->RemoveGuest(this);
1815  m_system->SetDockCount(this, false);
1816  OnCharNoLongerInStation ocnis;
1817  ocnis.charID = m_char->itemID();
1818  ocnis.corpID = GetCorporationID();
1819  ocnis.allianceID = GetAllianceID();
1820  ocnis.factionID = GetWarFactionID();
1821  PyTuple* tmp = ocnis.Encode();
1822  if (tmp == nullptr)
1823  return;
1824  std::vector<Client*> clients;
1825  clients.clear();
1826  sEntityList.GetStationGuestList(m_StationData.stationID, clients);
1827  for (auto cur : clients) {
1828  PyIncRef(tmp);
1829  cur->SendNotification("OnCharNoLongerInStation", "stationid", &tmp); //consumed
1830  }
1831  PyDecRef(tmp);
1832 
1833  // delete current station data
1835 }
1836 
1838  m_system->SetDockCount(this, true);
1839  OnCharNowInStation ocnis;
1840  ocnis.charID = m_char->itemID();
1841  ocnis.corpID = GetCorporationID();
1842  ocnis.allianceID = GetAllianceID();
1843  ocnis.warFactionID = GetWarFactionID();
1844  PyTuple* tmp = ocnis.Encode();
1845  std::vector<Client*> clients;
1846  clients.clear();
1847  sEntityList.GetStationGuestList(m_locationID, clients);
1848  for (auto cur : clients) {
1849  PySafeIncRef(tmp);
1850  cur->SendNotification("OnCharNowInStation", "stationid", &tmp);
1851  }
1852  PySafeDecRef(tmp);
1853 }
1854 
1855 /**********************************************************************
1856  * session shit and other non-player-related things
1857  * ****************************************************************/
1858 void Client::InitSession(int32 characterID)
1859 {
1860  if (!IsCharacterID(characterID)) {
1861  sLog.Error("Client::InitSession()", "characterID is not valid");
1862  return;
1863  }
1864 
1865  std::map<std::string, int64> characterDataMap;
1866  CharacterDB::GetCharacterData(characterID, characterDataMap);
1867  if (characterDataMap.size() < 1) {
1868  sLog.Error("Client::InitSession()", "characterDataMap.size() returned zero.");
1869  return;
1870  }
1871 
1872  int32 stationID = (int32)(characterDataMap["stationID"]);
1873  int32 solarSystemID = (int32)(characterDataMap["solarSystemID"]);
1874  m_shipId = (int32)(characterDataMap["shipID"]);
1875 
1876  pSession->SetInt("genderID", (int32)(characterDataMap["gender"]));
1877  pSession->SetInt("bloodlineID", (int32)(characterDataMap["bloodlineID"]));
1878  pSession->SetInt("raceID", (int32)(characterDataMap["raceID"]));
1879  pSession->SetInt("charid", characterID);
1880  pSession->SetInt("corpid", (int32)(characterDataMap["corporationID"]));
1881 
1882  pSession->SetInt("cloneStationID", (int32)(characterDataMap["cloneStationID"]));
1883  pSession->SetInt("solarsystemid2", solarSystemID);
1884  pSession->SetInt("constellationid", (int32)(characterDataMap["constellationID"]));
1885  pSession->SetInt("regionid", (int32)(characterDataMap["regionID"]));
1886 
1887  pSession->SetInt("hqID", (int32)(characterDataMap["corporationHQ"]));
1888  pSession->SetInt("baseID", characterDataMap["baseID"]);
1889  pSession->SetInt("corpAccountKey", characterDataMap["corpAccountKey"]);
1890 
1891  //Only set allianceID if it is not 0
1892  if (characterDataMap["allianceID"] != 0){
1893  pSession->SetInt("allianceid", characterDataMap["allianceID"]);
1894  }
1895 
1896  pSession->SetInt("warfactionid", characterDataMap["warFactionID"]);
1897 
1898  pSession->SetLong("corprole", characterDataMap["corpRole"]);
1899  pSession->SetLong("rolesAtAll", characterDataMap["rolesAtAll"]);
1900  pSession->SetLong("rolesAtBase", characterDataMap["rolesAtBase"]);
1901  pSession->SetLong("rolesAtHQ", characterDataMap["rolesAtHQ"]);
1902  pSession->SetLong("rolesAtOther", characterDataMap["rolesAtOther"]);
1903 
1904  /* solarSystemID != 0 -character in space
1905  * also used as current system in following menus:
1906  * JumpPortalBridgeMenu, GetHybridBeaconJumpMenu, GetHybridBridgeMenu
1907  */
1908  if (sDataMgr.IsStation(stationID)) {
1909  m_locationID = stationID;
1910  pSession->Clear("solarsystemid"); //must be 0 in station
1911  pSession->Clear("shipid"); //must be 0 in station
1912  pSession->SetInt("stationid", stationID);
1913  pSession->SetInt("stationid2", stationID);
1914  pSession->SetInt("locationid", stationID);
1915  pSession->SetInt("worldspaceid", stationID);
1916  } else {
1917  m_locationID = solarSystemID;
1918  pSession->Clear("stationid"); //must be 0 in space
1919  pSession->Clear("stationid2"); //must be 0 in space
1920  pSession->Clear("worldspaceid"); //must be 0 in space
1921  pSession->SetInt("shipid", m_shipId);
1922  pSession->SetInt("solarsystemid", solarSystemID);
1923  pSession->SetInt("locationid", solarSystemID);
1924  }
1925 
1926  sDataMgr.GetSystemData(m_locationID, m_SystemData);
1927  if ((sDataMgr.IsSolarSystem(m_SystemData.systemID))
1930  {
1931  m_validSession = true;
1932  }
1933 }
1934 
1936 {
1937  if (m_char.get() == nullptr)
1938  return;
1939  uint32 stationID = m_char->stationID();
1940  uint32 solarsystemID = m_char->solarSystemID();
1941  if (sDataMgr.IsStation(stationID)) {
1942  pSession->Clear("solarsystemid"); //must be 0 in station
1943  pSession->Clear("shipid"); //must be 0 in station
1944  //pSession->Clear("worldspaceid"); //not used here (yet)
1945 
1946  pSession->SetInt("stationid", stationID);
1947  pSession->SetInt("stationid2", stationID); // client uses this for continer location checks
1948  pSession->SetInt("worldspaceid", stationID);
1949  pSession->SetInt("locationid", stationID);
1950  } else {
1951  pSession->Clear("stationid");
1952  pSession->Clear("stationid2");
1953  pSession->Clear("worldspaceid");
1954  pSession->SetInt("solarsystemid", solarsystemID); // used to tell client they are in space
1955  pSession->SetInt("locationid", solarsystemID);
1956  pSession->SetInt("shipid", m_shipId);
1957  }
1958 
1959  // solarsystemid2 is used by client to determine current system. NOTE: *MUST* be set to current system.
1960  pSession->SetInt("solarsystemid2", solarsystemID);
1961  pSession->SetInt("constellationid", m_char->constellationID());
1962  pSession->SetInt("regionid", m_char->regionID());
1963 }
1964 
1965 void Client::UpdateSessionInt(const char *id, int value)
1966 {
1967  pSession->SetInt(id, value);
1968 }
1969 
1971 {
1972  // session.Set* methods only update on change
1973  pSession->SetInt("corpid", data.corporationID);
1974  pSession->SetInt("baseID", data.baseID);
1975  pSession->SetInt("hqID", data.corpHQ);
1976 
1977  //Only set allianceID if it is not 0
1978  if (data.allianceID != 0){
1979  pSession->SetInt("allianceid", data.allianceID);
1980  }
1981 
1982  pSession->SetInt("warfactionid", data.warFactionID);
1983  pSession->SetInt("corpAccountKey", data.corpAccountKey);
1984  pSession->SetLong("corprole", data.corpRole);
1985  pSession->SetLong("rolesAtAll", data.rolesAtAll);
1986  pSession->SetLong("rolesAtBase", data.rolesAtBase);
1987  pSession->SetLong("rolesAtHQ", data.rolesAtHQ);
1988  pSession->SetLong("rolesAtOther", data.rolesAtOther);
1990 }
1991 
1993 {
1994  m_fleet = fleet.fleetID;
1995  m_wing = fleet.wingID;
1996  m_squad = fleet.squadID;
1997 
1998  pSession->SetInt("fleetjob", fleet.job);
1999  pSession->SetInt("fleetrole", fleet.role);
2000  pSession->SetInt("fleetbooster", fleet.booster);
2001  pSession->SetInt("fleetid", m_fleet);
2002  pSession->SetInt("wingid", m_wing);
2003  pSession->SetInt("squadid", m_squad);
2005 }
2006 
2008 {
2009  SessionInitialState scn;
2010  scn.initialstate = new PyDict();
2011 
2012  pSession->EncodeInitialState (scn.initialstate);
2013 
2014  if (is_log_enabled(CLIENT__SESSION)) {
2015  _log(CLIENT__SESSION, "Session initialized. Sending initial session state");
2016  scn.initialstate->Dump(CLIENT__SESSION, " Changes: ");
2017  }
2018 
2019  scn.sessionID = pSession->GetSessionID();
2020 
2021  //build the packet:
2022  PyPacket* packet = new PyPacket();
2023  packet->type_string = "macho.SessionInitialStateNotification";
2025 
2026  packet->source.type = PyAddress::Node;
2027  packet->source.objectID = m_services.GetNodeID();
2028  packet->source.callID = 0;
2029 
2030  packet->dest.type = PyAddress::Client;
2031  packet->dest.objectID = 0; //GetClientID();
2032  packet->dest.callID = 0;
2033 
2034  packet->userid = GetUserID();
2035 
2036  packet->payload = scn.Encode();
2037  packet->named_payload = nullptr;
2038 
2039  if (is_log_enabled(CLIENT__SESSION_DUMP)) {
2040  _log(CLIENT__SESSION_DUMP, "Sending Session packet:");
2041  PyLogDumpVisitor dumper(CLIENT__SESSION_DUMP, CLIENT__SESSION_DUMP);
2042  packet->Dump(CLIENT__SESSION_DUMP, dumper);
2043  }
2044 
2045  QueuePacket(packet);
2046 }
2047 
2049 {
2050  if (!pSession->isDirty())
2051  return;
2052 
2053  // this should never happen now. -allan 3Aug16
2054  if (m_locationID == 0) {
2055  if (m_char.get() != nullptr) {
2056  codelog(CLIENT__ERROR, "Session::LocationID == 0 for %s(%u)", m_char->name(), m_char->itemID());
2057  EvE::traceStack();
2058  if (sDataMgr.IsStation(m_char->stationID())) {
2060  } else {
2062  }
2063  /* a `session.locationid` change will trigger a ballpark update (add/delete bp) */
2064  pSession->SetInt("locationid", m_locationID);
2065  }
2066  }
2067 
2068  SessionChangeNotification scn;
2069  scn.changes = new PyDict();
2070 
2071  pSession->EncodeChanges(scn.changes);
2072  if (scn.changes->empty())
2073  return;
2074 
2075  if (is_log_enabled(CLIENT__SESSION)) {
2076  _log(CLIENT__SESSION, "Session updated. Sending session change");
2077  scn.changes->Dump(CLIENT__SESSION, " Changes: ");
2078  }
2079 
2080  scn.sessionID = 0; //pSession->GetSessionID();
2081  scn.clueless = 0;
2082  scn.nodesOfInterest.push_back(-1); /* this means 'all nodes' */
2083  scn.nodesOfInterest.push_back(m_services.GetNodeID()); /* add current node to list */
2084  /* if other nodes are created, add those that are 'live' for this client here */
2085  // will need *some way* to track active nodes for each client
2086  //scn.nodesOfInterest.push_back(m_services.GetNodeID());
2087 
2088  //build the packet:
2089  PyPacket* packet = new PyPacket();
2090  packet->type_string = "macho.SessionChangeNotification";
2091  packet->type = SESSIONCHANGENOTIFICATION;
2092 
2093  packet->source.type = PyAddress::Node;
2094  packet->source.objectID = m_services.GetNodeID();
2095  packet->source.callID = 0;
2096 
2097  packet->dest.type = PyAddress::Client;
2098  packet->dest.objectID = 0; //GetClientID();
2099  packet->dest.callID = 0;
2100 
2101  packet->userid = GetUserID();
2102 
2103  packet->payload = scn.Encode();
2104  packet->named_payload = nullptr;
2105 
2106  if (is_log_enabled(CLIENT__SESSION_DUMP)) {
2107  _log(CLIENT__SESSION_DUMP, "Sending Session packet:");
2108  PyLogDumpVisitor dumper(CLIENT__SESSION_DUMP, CLIENT__SESSION_DUMP);
2109  packet->Dump(CLIENT__SESSION_DUMP, dumper);
2110  }
2111 
2112  QueuePacket(packet);
2113 
2114  // clean up packet after being created by 'new'
2115  //SafeDelete(packet);
2116 }
2117 
2119  if ((!m_destinyUpdateQueue->empty())
2120  or (!m_destinyEventQueue->empty()))
2122 }
2123 
2125  if ((event == nullptr) or ((*event) == nullptr))
2126  return;
2127  m_destinyEventQueue->AddItem(*event);
2128  //PyDecRef(*event);
2129 }
2130 
2131 void Client::QueueDestinyUpdate(PyTuple **update, bool DoPackage /*false*/, bool IsSetState /*false*/) {
2132  if ((update == nullptr) or ((*update) == nullptr))
2133  return;
2134  if (sDataMgr.IsStation(m_locationID))
2135  return;
2136  DoDestinyAction act;
2137  act.stamp = sEntityList.GetStamp();
2138  if (DoPackage/* or m_packaged*/) {
2139  if (IsSetState) {
2140  // send the setstate buffer alone
2141  act.update = *update;
2142  } else {
2143  // this will package all current updates (and those coming in before next flush) into
2144  // a single PackagedAction packet, which is then inserted into the DoDestinyAction packet.
2145  PyList* paList = new PyList();
2146  paList->AddItem(*update);
2147  if (!m_destinyUpdateQueue->empty())
2148  paList->AddItem(m_destinyUpdateQueue);
2149  PackagedAction pa;
2150  pa.substream = new PySubStream(paList);
2151  act.update = pa.Encode();
2152  m_packaged = false;
2153  }
2154  DoDestinyUpdateMain_2 dum;
2155  dum.updates = new PyList();
2156  dum.updates->AddItem(act.Encode());
2157  dum.waitForBubble = m_bubbleWait;
2158  PyTuple* t = dum.Encode();
2159  if (is_log_enabled(CLIENT__QUEUE_DUMP))
2160  t->Dump(CLIENT__QUEUE_DUMP, "");
2161  SendNotification("DoDestinyUpdate", "clientID", &t, false);
2162  PyDecRef(t);
2163  } else {
2164  act.update = *update;
2165  m_packaged = true;
2166  m_destinyUpdateQueue->AddItem(act.Encode());
2167  }
2168 }
2169 
2171  if (!m_destinyUpdateQueue->empty()) {
2172  if (m_destinyEventQueue->empty()) {
2173  DoDestinyUpdateMain_2 dum;
2174  dum.updates = m_destinyUpdateQueue;
2175  dum.waitForBubble = m_bubbleWait;
2176  PyTuple* t = dum.Encode();
2177  if (is_log_enabled(CLIENT__QUEUE_DUMP))
2178  t->Dump(CLIENT__QUEUE_DUMP, "");
2179  SendNotification("DoDestinyUpdate", "clientID", &t);
2180  } else {
2181  DoDestinyUpdateMain dum;
2182  dum.updates = m_destinyUpdateQueue;
2183  dum.events = m_destinyEventQueue;
2184  dum.waitForBubble = m_bubbleWait;
2185  PyTuple* t = dum.Encode();
2186  if (is_log_enabled(CLIENT__QUEUE_DUMP))
2187  t->Dump(CLIENT__QUEUE_DUMP, "");
2188  SendNotification("DoDestinyUpdate", "clientID", &t);
2189  }
2190  } else if (!m_destinyEventQueue->empty()) {
2191  Notify_OnMultiEvent nom;
2192  nom.events = m_destinyEventQueue;
2193  PyTuple* t = nom.Encode();
2194  if (is_log_enabled(CLIENT__QUEUE_DUMP))
2195  t->Dump(CLIENT__QUEUE_DUMP, "");
2196  SendNotification("OnMultiEvent", "charid", &t);
2197  } //else nothing to be sent ...
2198 
2199  // clear the queues now, after the packets have been sent
2202  m_packaged = false;
2203 }
2204 
2205 void Client::SendNotification(const char *notifyType, const char *idType, PyTuple *payload, bool seq /*true*/) {
2206  //build a little notification out of it.
2207  EVENotificationStream notify;
2208  notify.notifyType = notifyType;
2209  notify.remoteObject = 1;
2210  notify.args = payload;
2211 
2212  PyAddress dest;
2213  // are all of these 'Broadcast'?
2214  dest.type = PyAddress::Broadcast;
2215  dest.service = notifyType;
2216  dest.bcast_idtype = idType;
2217  /*
2218  if (dest.bcast_idtype.compare("clientID") == 0)
2219  dest.objectID = GetClientID();*/
2220 
2221  //now send it to the client
2222  SendNotification(dest, notify, seq);
2223 }
2224 
2225 void Client::SendNotification(const char *notifyType, const char *idType, PyTuple **payload, bool seq /*true*/) {
2226  if ((*payload) == nullptr)
2227  return;
2228  //build a little notification out of it.
2229  EVENotificationStream notify;
2230  notify.notifyType = notifyType;
2231  notify.remoteObject = 1;
2232  notify.args = (*payload);
2233 
2234  PyAddress dest;
2235  // are all of these 'Broadcast'?
2236  dest.type = PyAddress::Broadcast;
2237  dest.service = notifyType;
2238  dest.bcast_idtype = idType;
2239  dest.objectID = 0; //GetClientID();
2240 
2241  //now send it to the client
2242  SendNotification(dest, notify, seq);
2243 }
2244 
2245 void Client::SendNotification(const PyAddress &dest, EVENotificationStream &noti, bool seq/*true*/) {
2246  //build the packet:
2247  PyPacket *packet = new PyPacket();
2248  packet->type_string = "macho.Notification";
2249  packet->type = NOTIFICATION;
2250 
2251  // is source type right here?
2252  packet->source.type = PyAddress::Node;
2253  packet->source.objectID = m_services.GetNodeID();
2254 
2255  packet->dest = dest;
2256 
2257  packet->userid = GetUserID();
2258 
2259  packet->payload = noti.Encode();
2260 
2261  if (seq) {
2262  packet->named_payload = new PyDict();
2263  packet->named_payload->SetItemString("sn", new PyInt(++m_nextNotifySequence));
2264  }
2265 
2266  if (is_log_enabled(CLIENT__NOTIFY_DUMP)) {
2267  _log(CLIENT__NOTIFY_REP, "Sending notify of type %s with ID type %s to %s", dest.service.c_str(), dest.bcast_idtype.c_str(), GetName());
2268  PyLogDumpVisitor dumper(CLIENT__NOTIFY_DUMP, CLIENT__NOTIFY_REP, "", true, true);
2269  packet->Dump(CLIENT__NOTIFY_DUMP, dumper);
2270  }
2271 
2272  QueuePacket(packet);
2273 }
2274 
2275 /************************************************************************/
2276 /* EVEAdministration Interface */
2277 /************************************************************************/
2278  // only used by GM Command
2280 {
2281  SendNotifyMsg("You have been kicked from this server and will be disconnected shortly.");
2282 
2283  //initiate closing the client TCP Connection
2285 }
2286 // only used by GM Command
2288 {
2289  //send message to client
2290  SendNotifyMsg("You have been banned from this server and will be disconnected shortly. You will no longer be able to log in");
2291 
2292  //ban the client
2294 }
2295 
2296 /************************************************************************/
2297 /* EVEClientSession interface */
2298 /************************************************************************/
2299 void Client::_GetVersion(VersionExchangeServer& version)
2300 {
2301  version.birthday = EVEBirthday;
2302  version.macho_version = MachoNetVersion;
2303  version.user_count = sEntityList.GetClientCount();
2304  version.version_number = EVEVersionNumber;
2305  version.build_version = EVEBuildVersion;
2306  version.project_version = EVEProjectVersion;
2307 }
2308 
2310 {
2311  return sEntityList.GetClientCount();
2312 }
2313 
2314 bool Client::_VerifyVersion(VersionExchangeClient& version)
2315 {
2316  version.Dump(NET__PRES_REP, " ");
2317  if (version.birthday != EVEBirthday)
2318  sLog.Error("Client","%s: Client's birthday does not match ours!", GetAddress().c_str());
2319  if (version.macho_version != MachoNetVersion)
2320  sLog.Error("Client","%s: Client's macho_version not match ours!", GetAddress().c_str());
2321  if (version.version_number != EVEVersionNumber)
2322  sLog.Error("Client","%s: Client's version_number not match ours!", GetAddress().c_str());
2323  if (version.build_version != EVEBuildVersion)
2324  sLog.Error("Client","%s: Client's build_version not match ours!", GetAddress().c_str());
2325  if (version.project_version != EVEProjectVersion)
2326  sLog.Error("Client","%s: Client's project_version not match ours!", GetAddress().c_str());
2327  return true;
2328 }
2329 
2330 bool Client::_VerifyCrypto(CryptoRequestPacket& cr)
2331 {
2332  if (cr.keyVersion != "placebo") {
2333  //I'm sure cr.keyVersion can specify either CryptoAPI or PyCrypto, but its all binary so im not sure how.
2334  CryptoAPIRequestParams car;
2335  if (!car.Decode(cr.keyParams)) {
2336  sLog.Error("Client","%s: Received invalid CryptoAPI request!", GetAddress().c_str());
2337  } else {
2338  sLog.Error("Client","%s: Unhandled CryptoAPI request: hashmethod=%s sessionkeylength=%d provider=%s sessionkeymethod=%s", GetAddress().c_str(), car.hashmethod.c_str(), car.sessionkeylength, car.provider.c_str(), car.sessionkeymethod.c_str());
2339  SendErrorMsg("Invalid CryptoAPI request - You must change your client to use Placebo crypto in common.ini to talk to this server.");
2340  }
2341 
2342  return false;
2343  } else {
2344  sLog.Debug("Client","%s: Received Placebo crypto request, accepting.", GetAddress().c_str());
2345 
2346  //send out accept response
2347  PyRep* rsp = new PyString("OK CC");
2348  mNet->QueueRep(rsp);
2349  }
2350 
2351  return true;
2352 }
2353 
2354 bool Client::_VerifyLogin(CryptoChallengePacket& ccp)
2355 {
2356  /* send passwordVersion required: 1=plain, 2=hashed */
2357  // this doesnt work as i want it to.
2358  // sending '2' will have client use hashed pass.
2359  // sending '1' will have client send hashed pass first, then a second authentication packet using plain pass
2360  PyRep* res = new PyInt(2);
2361  mNet->QueueRep(res);
2362 
2363  std::string failMsg = "Login Authorization Invalid.";
2364 
2365  // test account name for invalid chars (which may allow sql injection)
2366  if (!ServiceDB::ValidateAccountName(ccp, failMsg))
2367  return _LoginFail(failMsg);
2368 
2369  AccountData aData = AccountData();
2370  if (!ServiceDB::GetAccountInformation(ccp, aData, failMsg))
2371  return _LoginFail(failMsg);
2372 
2373  if (aData.banned) {
2374  failMsg = "Your account is banned. Contact Allan for further support";
2375  return _LoginFail(failMsg);
2376  }
2377 
2378  if (aData.online) {
2379  failMsg = "This account is currently online.";
2380  return _LoginFail(failMsg);
2381  }
2382 
2383  if (!ccp.user_password.empty()) {
2384  sLog.Warning(" Client::Login()", "%s(%li) - Using Plain Password", aData.name.c_str(), aData.clientID);
2385  if (strcmp(aData.password.c_str(), ccp.user_password.c_str()) != 0) {
2386  failMsg = "The plain Password you entered is incorrect for this account.";
2387  return _LoginFail(failMsg);
2388  }
2389  } else {
2390  //sLog.Warning(" Client::Login()", "%s(%li) - Using Hashed Password", aData.name.c_str(), aData.clientID);
2391  if (strcmp(aData.hash.c_str(), ccp.user_password_hash.c_str()) != 0) {
2392  failMsg = "The Password you entered is incorrect for this account.";
2393  return _LoginFail(failMsg);
2394  }
2395 
2396  if (!ccp.user_password.empty())
2397  ServiceDB::UpdatePassword(aData.id, ccp.user_password.c_str());
2398  }
2399 
2402  /* send our handshake */
2403  CryptoServerHandshake server_shake;
2404  //server_shake.context = ??
2405  server_shake.serverChallenge = "";
2406  server_shake.func_marshaled_code = new PyBuffer(marshaledNone, marshaledNone + sizeof(marshaledNone));
2407  server_shake.verification = new PyBool(false);
2408  server_shake.cluster_usercount = sEntityList.GetClientCount(); //GetUserCount();
2409  server_shake.proxy_nodeid = 0xFFAA; //888444
2410  server_shake.user_logonqueueposition = _GetQueuePosition();
2411  // binascii.crc_hqx of marshaled single-element tuple containing 64 zero-bytes string
2412  server_shake.challenge_responsehash = "55087";
2413 
2414  // the image server to be used by the client to download images
2415  server_shake.imageserverurl = sImageServer.url();
2416 
2417  server_shake.macho_version = MachoNetVersion;
2418  server_shake.boot_version = EVEVersionNumber;
2419  server_shake.boot_build = EVEBuildVersion;
2420  server_shake.boot_codename = EVEProjectCodename;
2421  server_shake.boot_region = EVEProjectRegion;
2422  res = server_shake.Encode();
2423  mNet->QueueRep(res);
2424 
2425  // Setup session, but don't send the change yet.
2426  pSession->SetString("address", EVEClientSession::GetAddress().c_str());
2427  pSession->SetString("languageID", ccp.user_languageid.c_str());
2428 
2429  pSession->SetInt("userType", Acct::Type::Mammon); //aData.type - incomplete (db fields done)
2430  pSession->SetInt("userid", aData.id);
2431  pSession->SetLong("role", aData.role);
2432  pSession->SetLong("clientID", 0 /*1000000L * aData.clientID + 888444*/); // kinda arbitrary
2433  pSession->SetLong("sessionID", 0 /*pSession->GetSessionID()*/);
2434 
2435  sLog.Green(" Client::Login()","Account %u (%s) logging in from %s", aData.id, aData.name.c_str(), EVEClientSession::GetAddress().c_str());
2436 
2437  return true;
2438 }
2439 
2440 bool Client::_LoginFail(std::string fail_msg)
2441 {
2442  GPSTransportClosed* except = new GPSTransportClosed(fail_msg);
2443  mNet->QueueRep(except);
2444  return false;
2445 }
2446 
2447 bool Client::_VerifyFuncResult(CryptoHandshakeResult& result)
2448 {
2449  _log(NET__PRES_DEBUG, "%s: Handshake result received.", GetAddress().c_str());
2450 
2451  //send this before session change
2452  CryptoHandshakeAck ack;
2453  ack.jit = GetLanguageID();
2454  ack.userid = GetUserID(); //5654387 accountID?
2455  ack.maxSessionTime = PyStatic.NewNone(); // set this for an auto-logout time?
2456  ack.userType = Acct::Type::Mammon; //GetAccountType() - not written yet
2457  ack.role = Acct::Role::PLAYER | Acct::Role::NEWBIE | Acct::Role::LOGIN; /* live returns these */
2458  ack.address = GetAddress();
2459  ack.inDetention = PyStatic.NewNone(); // dont know what this is or what it's for
2460  ack.client_hash = PyStatic.NewNone();
2461  ack.user_clientid = 0; //GetClientID(); //241241000001103
2462  ack.live_updates = sLiveUpdateDB.GetUpdates();
2463  ack.sessionID = 0; //pSession->GetSessionID(); //398773966249980114
2464  PyRep* res(ack.Encode());
2465  if (is_log_enabled(CLIENT__CALL_DUMP))
2466  res->Dump(CLIENT__CALL_DUMP, " ");
2467  mNet->QueueRep(res, false);
2468 
2469  // send out the initial session status
2471 
2472  return true;
2473 }
2474 
2475 void Client::_SendCallReturn(const PyAddress& source, int64 callID, PyResult &rsp)
2476 {
2477  //build the packet:
2478  PyPacket* packet = new PyPacket();
2479  packet->type_string = "macho.CallRsp";
2480  packet->type = CALL_RSP;
2481 
2482  packet->source = source; /* address should be 'ship' for warpto response */
2483 
2484  packet->dest.type = PyAddress::Client;
2485  packet->dest.objectID = 0; //GetClientID();
2486  packet->dest.callID = callID;
2487 
2488  packet->userid = GetUserID();
2489 
2490  packet->payload = new PyTuple(1);
2491  packet->payload->SetItem(0, new PySubStream(rsp.ssResult));
2492  packet->named_payload = rsp.ssNamedResult;
2493 
2494  if (is_log_enabled(COLLECT__PACKET_DUMP)) {
2495  _log(COLLECT__PACKET_DUMP, "_SendCallReturn: Dump()");
2496  PyLogDumpVisitor dumper(COLLECT__PACKET_DUMP, COLLECT__PACKET_DUMP, "", true, true);
2497  packet->Dump(COLLECT__PACKET_DUMP, dumper);
2498  }
2499 
2500  QueuePacket(packet);
2501 }
2502 
2503 void Client::_SendException(const PyAddress& source, int64 callID, MACHONETMSG_TYPE msgType, MACHONETERR_TYPE errCode, PyRep** payload)
2504 {
2505  //build the packet:
2506  PyPacket* packet = new PyPacket();
2507  packet->type_string = "macho.ErrorResponse";
2508  packet->type = ERRORRESPONSE;
2509 
2510  packet->source = source;
2511 
2512  packet->dest.type = PyAddress::Client;
2513  packet->dest.objectID = 0; //GetClientID();
2514  packet->dest.callID = callID;
2515 
2516  packet->userid = GetUserID();
2517 
2518  ErrorResponse e;
2519  e.MsgType = msgType;
2520  e.ErrorCode = errCode;
2521  e.payload = *payload;
2522  payload = nullptr;
2523 
2524  packet->payload = e.Encode();
2525  QueuePacket(packet);
2526 }
2527 
2529 {
2530  PyPacket *packet = new PyPacket();
2531 
2532  packet->type = PING_REQ;
2533  packet->type_string = "macho.PingReq";
2534 
2535  packet->source.type = PyAddress::Node;
2536  packet->source.objectID = m_services.GetNodeID();
2537  packet->source.service = "ping";
2538  packet->source.callID = 0;
2539 
2540  packet->dest.type = PyAddress::Client;
2541  packet->dest.objectID = 0; //GetClientID();
2542  packet->dest.callID = 0;
2543 
2544  packet->userid = GetUserID();
2545 
2546  packet->payload = new_tuple(new PyList()); //times
2547  packet->named_payload = new PyDict();
2548 
2549  QueuePacket(packet);
2550 }
2551 
2552 void Client::_SendPingResponse(const PyAddress& source, int64 callID)
2553 {
2554  PyPacket* packet = new PyPacket();
2555  packet->type = PING_RSP;
2556  packet->type_string = "macho.PingRsp";
2557 
2558  packet->source = source;
2559 
2560  packet->dest.type = PyAddress::Client;
2561  packet->dest.objectID = 0; //GetClientID();
2562  packet->dest.callID = callID;
2563 
2564  packet->userid = GetUserID();
2565 
2566  /* Here the hacking begins, the ping packet handles the timestamps of various packet handling steps.
2567  * To really simulate/emulate that we need the various packet handlers which in fact we don't have (:P).
2568  * So the next piece of code "fake's" it, with a slight delay on the received packet time.
2569  */
2570  PyList* pingList = new PyList();
2571  PyTuple* pingTuple(nullptr);
2572 
2573  pingTuple = new PyTuple(3);
2574  pingTuple->SetItem(0, new PyLong(Win32TimeNow() - 20)); // this should be the time the packet was received (we cheat here a bit)
2575  pingTuple->SetItem(1, new PyLong(Win32TimeNow())); // this is the time the packet is (handled/written) by the (proxy/server) so we're cheating a bit again.
2576  pingTuple->SetItem(2, new PyString("proxy::handle_message"));
2577  pingList->AddItem(pingTuple);
2578 
2579  pingTuple = new PyTuple(3);
2580  pingTuple->SetItem(0, new PyLong(Win32TimeNow() - 20));
2581  pingTuple->SetItem(1, new PyLong(Win32TimeNow()));
2582  pingTuple->SetItem(2, new PyString("proxy::writing"));
2583  pingList->AddItem(pingTuple);
2584 
2585  pingTuple = new PyTuple(3);
2586  pingTuple->SetItem(0, new PyLong(Win32TimeNow() - 20));
2587  pingTuple->SetItem(1, new PyLong(Win32TimeNow()));
2588  pingTuple->SetItem(2, new PyString("server::handle_message"));
2589  pingList->AddItem(pingTuple);
2590 
2591  pingTuple = new PyTuple(3);
2592  pingTuple->SetItem(0, new PyLong(Win32TimeNow() - 20));
2593  pingTuple->SetItem(1, new PyLong(Win32TimeNow()));
2594  pingTuple->SetItem(2, new PyString("server::turnaround"));
2595  pingList->AddItem(pingTuple);
2596 
2597  pingTuple = new PyTuple(3);
2598  pingTuple->SetItem(0, new PyLong(Win32TimeNow() - 20));
2599  pingTuple->SetItem(1, new PyLong(Win32TimeNow()));
2600  pingTuple->SetItem(2, new PyString("proxy::handle_message"));
2601  pingList->AddItem(pingTuple);
2602 
2603  pingTuple = new PyTuple(3);
2604  pingTuple->SetItem(0, new PyLong(Win32TimeNow() - 20));
2605  pingTuple->SetItem(1, new PyLong(Win32TimeNow()));
2606  pingTuple->SetItem(2, new PyString("proxy::writing"));
2607  pingList->AddItem(pingTuple);
2608 
2609  // Set payload
2610  packet->payload = new PyTuple(1);
2611  packet->payload->SetItem(0, pingList);
2612 
2613  // Don't clone so it eats the ret object upon sending.
2614  QueuePacket(packet);
2615 }
2616 
2617 /************************************************************************/
2618 /* EVEPacketDispatcher interface */
2619 /************************************************************************/
2621 {
2622  PyCallable* dest(nullptr);
2623  if (packet->dest.service == "") {
2624  //bound object
2625  uint32 nodeID = 0, bindID = 0;
2626  if (sscanf(req.remoteObjectStr.c_str(), "N=%u:%u", &nodeID, &bindID) != 2) {
2627  sLog.Error("Client::CallReq","Failed to parse bind string '%s'.", req.remoteObjectStr.c_str());
2628  return false;
2629  }
2630 
2631  if (nodeID != m_services.GetNodeID()) {
2632  sLog.Error("Client::CallReq","Unknown nodeID - received %u but expected %u.", nodeID, m_services.GetNodeID());
2633  return false;
2634  }
2635 
2636  dest = m_services.FindBoundObject(bindID);
2637  if (dest == nullptr) {
2638  sLog.Error("Client::CallReq", "Failed to find bound object %u.", bindID);
2639  return false;
2640  }
2641  } else {
2642  //service
2643  dest = m_services.LookupService(packet->dest.service);
2644  if (dest == nullptr) {
2645  sLog.Error("Client::CallReq","Unable to find service to handle call to: %s", packet->dest.service.c_str());
2646  packet->dest.Dump(CLIENT__CALL_DUMP, " ");
2647  throw UserError ("ServiceNotFound"); // this message is invalid (message not found)
2648  }
2649  }
2650 
2651  //build arguments
2652  PyCallArgs args(this, req.arg_tuple, req.arg_dict);
2653 
2654  //parts of call may be consumed here
2655  m_canThrow = true; // test for throwable. -allan 29Jul16 should we use try/catch here? yes
2656  PyResult result(dest->Call(req.method, args));
2657  m_canThrow = false;
2658 
2659  SendSessionChange(); //send out the session change before the return.
2660  if (is_log_enabled(CLIENT__OUT_ALL)) {
2661  if (result.ssResult != nullptr)
2662  result.ssResult->Dump(CLIENT__OUT_ALL, " ");
2663  if (result.ssNamedResult != nullptr)
2664  result.ssNamedResult->Dump(CLIENT__OUT_ALL, " ");
2665  }
2666 
2667  _SendCallReturn(packet->dest, packet->source.callID, result);
2668 
2669  return true;
2670 }
2671 
2673 {
2674  //turn this thing into a notify stream:
2675  ServerNotification notify;
2676  if (!notify.Decode(packet->payload)) {
2677  sLog.Error("Client::Notify","Failed to convert rep into a notify stream");
2678  return false;
2679  }
2680 
2681  if (notify.method == "ClientHasReleasedTheseObjects") {
2682  _log(SERVICE__MESSAGE, "Client Has Released These Objects:");
2683  ServerNotification_ReleaseObj element;
2684 
2685  uint32 nodeID(0), bindID(0);
2686  PyList::const_iterator cur = notify.elements->begin();
2687  for (; cur != notify.elements->end(); ++cur) {
2688  if (!element.Decode(*cur)) {
2689  sLog.Error("Client::Notify","Notification '%s' from %s: Failed to decode element. Skipping.", notify.method.c_str(), m_char->name());
2690  continue;
2691  }
2692 
2693  if (sscanf(element.boundID.c_str(), "N=%u:%u", &nodeID, &bindID) != 2) {
2694  sLog.Error("Client::Notify","Notification '%s' from %s: Failed to parse bind string '%s'. Skipping.", \
2695  notify.method.c_str(), m_char->name(), element.boundID.c_str());
2696  continue;
2697  }
2698 
2699  if (nodeID != m_services.GetNodeID()) {
2700  sLog.Error("Client::Notify","Notification '%s' from %s: Unknown nodeID %u received (expected %u). Skipping.", \
2701  notify.method.c_str(), m_char->name(), nodeID, m_services.GetNodeID());
2702  continue;
2703  }
2704 
2705  // clear bindID from internal map
2706  m_bindSet.erase(bindID);
2707  m_services.ClearBoundObject(bindID);
2708  }
2709  } else {
2710  sLog.Error("Client::Notify","Unhandled notification from %s: unknown method '%s'", m_char->name(), notify.method.c_str());
2711  return false;
2712  }
2713 
2714  return true;
2715 }
2716 
2717 // NOTE: 'OnRemoteMessage' can be disabled in client
2718 //this displays a modal error dialog on the client side.
2719 void Client::SendErrorMsg(const char* fmt, ...)
2720 {
2721  va_list args;
2722  va_start(args, fmt);
2723  char* str(nullptr);
2724  vasprintf(&str, fmt, args);
2725  assert(str);
2726  va_end(args);
2727 
2728  Notify_OnRemoteMessage n;
2729  n.msgType = "CustomError";
2730  n.args[ "error" ] = new PyString(str);
2731 
2732  PyTuple* tmp = n.Encode();
2733  SendNotification("OnRemoteMessage", "charid", &tmp);
2734 
2735  SafeFree(str);
2736 }
2737 
2738 void Client::SendErrorMsg(const char* fmt, va_list args)
2739 {
2740  char* str(nullptr);
2741  vasprintf(&str, fmt, args);
2742  assert(str);
2743 
2744  Notify_OnRemoteMessage n;
2745  n.msgType = "CustomError";
2746  n.args[ "error" ] = new PyString(str);
2747 
2748  PyTuple* tmp = n.Encode();
2749  SendNotification("OnRemoteMessage", "charid", &tmp);
2750 
2751  SafeFree(str);
2752 
2753 }
2754 
2755 //this displays a modal info dialog on the client side.
2756 void Client::SendInfoModalMsg(const char* fmt, ...)
2757 {
2758  va_list args;
2759  va_start(args, fmt);
2760  char* str(nullptr);
2761  vasprintf(&str, fmt, args);
2762  assert(str);
2763  va_end(args);
2764 
2765  Notify_OnRemoteMessage n;
2766  n.msgType = "ServerMessage";
2767  n.args[ "msg" ] = new PyString(str);
2768 
2769  PyTuple* tmp = n.Encode();
2770  SendNotification("OnRemoteMessage", "charid", &tmp);
2771 
2772  SafeFree(str);
2773 }
2774 
2775 //this displays a little notice (like combat messages)
2776 void Client::SendNotifyMsg(const char* fmt, ...)
2777 {
2778  va_list args;
2779  va_start(args, fmt);
2780  char* str(nullptr);
2781  vasprintf(&str, fmt, args);
2782  assert(str);
2783  va_end(args);
2784 
2785  Notify_OnRemoteMessage n;
2786  n.msgType = "CustomNotify";
2787  n.args[ "notify" ] = new PyString(str);
2788 
2789  PyTuple* tmp = n.Encode();
2790  SendNotification("OnRemoteMessage", "charid", &tmp);
2791 
2792  SafeFree(str);
2793 }
2794 
2795 void Client::SendNotifyMsg(const char* fmt, va_list args)
2796 {
2797  char* str(nullptr);
2798  vasprintf(&str, fmt, args);
2799  assert(str);
2800 
2801  Notify_OnRemoteMessage n;
2802  n.msgType = "CustomNotify";
2803  n.args[ "notify" ] = new PyString(str);
2804 
2805  PyTuple* tmp = n.Encode();
2806  SendNotification("OnRemoteMessage", "charid", &tmp);
2807 
2808  SafeFree(str);
2809 }
2810 
2811 //there may be a less hackish way to do this.
2812 void Client::SelfChatMessage(const char* fmt, ...)
2813 {
2814  va_list args;
2815  va_start(args, fmt);
2816  char* str(nullptr);
2817  vasprintf(&str, fmt, args);
2818  assert(str);
2819  va_end(args);
2820 
2821  if (m_channels.empty()) {
2822  if (m_char.get() != nullptr)
2823  sLog.Error("Client", "%s: Tried to send self chat, but we are not joined to any channels: %s", m_char->name(), str);
2824  free(str);
2825  return;
2826  }
2827 
2828  if (m_char.get() != nullptr)
2829  sLog.White("Client","%s: Self message on all channels: %s", m_char->name(), str);
2830 
2831  //this is such a pile of crap, but im not sure whats better.
2832  //maybe a private message...
2833  std::set<LSCChannel*>::iterator cur = m_channels.begin();
2834  for (; cur != m_channels.end(); ++cur)
2835  (*cur)->SendMessage(this, str, true);
2836 
2837  //m_channels[
2838 
2839  //just send it to the first channel we are in..
2840  /*LSCChannel *chan = *(m_channels.begin());
2841  * char self_id[24]; //such crap..
2842  * snprintf(self_id, sizeof(self_id), "%u", m_char->itemID());
2843  * if (chan->GetName() == self_id) {
2844  * if (m_channels.size() > 1) {
2845  * chan = *(++m_channels.begin());
2846 }
2847 }*/
2848 
2849  SafeFree(str);
2850 }
2851 
PyDict * arg_dict
Definition: PyPacket.h:159
std::string name
Base Python wire object.
Definition: PyRep.h:66
bool m_setStateSent
Definition: Client.h:368
static bool IncrementLoginCount(uint32 accountID)
Definition: ServiceDB.cpp:140
#define sConfig
A macro for easier access to the singleton.
PyDict * ssNamedResult
Definition: PyCallable.h:66
uint32 GetUserCount()
Definition: Client.cpp:2309
void UpdateSessionInt(const char *sessionType, int value)
Definition: Client.cpp:1965
void SetPosition(const GPoint &pos)
Definition: SystemEntity.h:212
static void SetCharacterOnlineStatus(uint32 char_id, bool online=false)
Definition: ServiceDB.cpp:177
void SendNotification(const PyAddress &dest, EVENotificationStream &noti, bool seq=true)
Definition: Client.cpp:2245
int64 callID
Definition: PyPacket.h:90
double radius() const
void AddEntity(SystemEntity *pSE, bool addSignal=true)
void AddGuest(Client *pClient)
Definition: Station.cpp:219
void Reset()
Resets session.
Definition: EVESession.cpp:50
#define IsConstellationID(itemID)
Definition: EVE_Defines.h:276
void SendErrorMsg(const char *fmt,...)
Definition: Client.cpp:2719
void ExecuteDriveJump()
Definition: Client.cpp:1494
SystemData m_SystemData
Definition: Client.h:336
bool m_showall
Definition: Client.h:361
void RemoveClient(Client *pClient, bool count=false, bool jump=false)
void SendInitialSessionStatus()
Definition: Client.cpp:2007
void SetActiveShip(uint32 shipID)
Definition: Character.cpp:1240
void ChannelLeft(LSCChannel *chan)
Definition: Client.cpp:1803
#define _log(type, fmt,...)
Definition: logsys.h:124
#define stDataMgr
PyBoundObject * FindBoundObject(uint32 bindID)
#define sConsole
#define sImageServer
Definition: ImageServer.h:93
void Disable()
Definition: timer.h:39
void LoadStationOffice(uint32 corpID)
Definition: Station.cpp:144
Python string.
Definition: PyRep.h:430
void DisconnectClient()
Definition: Client.cpp:2279
static const char *const EVEProjectCodename
Definition: EVEVersion.h:37
#define PySafeIncRef(op)
Definition: PyRep.h:60
uint32 corpHQ
static const uint8 marshaledNone[]
Definition: EVE_Consts.h:23
void SetLocation(uint32 stationID, SystemData &data)
Definition: Character.cpp:412
std::map< uint32, bool > m_hangarLoaded
Definition: Client.h:398
void SetAutoPilot(bool set=false)
Definition: Client.cpp:669
uint32 m_nextNotifySequence
Definition: Client.h:464
bool m_uncloak
Definition: Client.h:360
Python's dictionary.
Definition: PyRep.h:719
void JumpOutEffect(uint32 locationID)
Definition: Client.cpp:1628
void SetActivePod(uint32 podID)
Definition: Character.cpp:1246
void _SendPingResponse(const PyAddress &source, int64 callID)
Definition: Client.cpp:2552
void _SendException(const PyAddress &source, int64 callID, MACHONETMSG_TYPE in_response_to, MACHONETERR_TYPE exception_type, PyRep **payload)
Definition: Client.cpp:2503
void SendGateActivity(uint32 gateID) const
bool m_canThrow
Definition: Client.h:439
CharacterRef m_char
Definition: Client.h:340
bool SetFlag(EVEItemFlags flag, bool notify=false)
BoostData boost
Definition: FleetData.h:118
void SetLong(const char *name, int64 value)
void JumpInEffect()
Definition: Client.cpp:1620
void SetLogonMinutes()
Definition: Character.cpp:1306
void MoveToLocation(uint32 location, const GPoint &pt)
Definition: Client.cpp:684
ModuleManager * GetModuleManager()
Definition: Ship.h:80
std::string name
PyService * LookupService(const std::string &name)
void UpdateFleetSession(CharFleetData &fleet)
Definition: Client.cpp:1992
void SetPodItem()
Definition: Client.cpp:1038
const GPoint & position() const
void ExecuteJump()
Definition: Client.cpp:1475
PyAddress dest
Definition: PyPacket.h:117
int64 rolesAtHQ
Client(PyServiceMgr &services, EVETCPConnection **con)
Definition: Client.cpp:59
SystemBubble * SysBubble()
Definition: SystemEntity.h:195
void FlushQueue()
Definition: Client.cpp:2118
void SendJumpInEffect(std::string JumpEffect) const
int64 rolesAtBase
int32 m_wing
Definition: Client.h:371
EVEItemFlags
Definition: EVE_Flags.h:13
void SendJumpOutEffect(std::string JumpEffect, uint32 locationID) const
ShipItemRef GetShipItemRef()
Definition: Ship.h:362
void SetBallParkTimer(uint32 time=Player::Timer::Default)
Definition: Client.cpp:1515
Client * leader
Definition: FleetData.h:129
bool m_loaded
Definition: Client.h:358
void MoveItem(uint32 itemID, uint32 location, EVEItemFlags flag)
Definition: Client.cpp:1674
void QueueDestinyEvent(PyTuple **multiEvent)
Definition: Client.cpp:2124
#define sProfiler
Definition: dbcore.cpp:39
void ProcessClient()
Definition: Client.cpp:433
bool m_portrait
Definition: Client.h:364
bool IsMissionComplete(MissionOffer &data)
Definition: Client.cpp:1764
int64 objectID
Definition: PyPacket.h:89
PyList * m_destinyEventQueue
Definition: Client.h:460
void SendInfoModalMsg(const char *fmt,...)
Definition: Client.cpp:2756
bool SelectCharacter(int32 char_id=0)
Definition: Client.cpp:316
int32 GetCharacterID() const
Definition: Client.h:113
int32 GetWarFactionID() const
Definition: Client.h:126
bool Handle_Notify(PyPacket *packet)
Definition: Client.cpp:2672
uint32 m_shipId
Definition: Client.h:375
int32 GetCorporationID() const
Definition: Client.h:123
int8 leader
Definition: FleetData.h:71
void _GetVersion(VersionExchangeServer &version)
Obtains version.
Definition: Client.cpp:2299
std::string hash
bool _LoginFail(std::string fail_msg)
Definition: Client.cpp:2440
#define sEntityList
Definition: EntityList.h:208
storage_type::const_iterator const_iterator
Definition: PyRep.h:644
bool m_autoPilot
Definition: Client.h:365
void CharNowInStation()
Definition: Client.cpp:1837
uint32 GetID() const
Definition: SystemManager.h:80
uint32 m_moveSystemID
Definition: Client.h:378
std::string GetAddress() const
Definition: EVESession.h:67
std::string GetStateName(int8 state)
Definition: Client.cpp:1636
static void SetAccountBanStatus(uint32 accountID, bool banned=false)
Definition: ServiceDB.cpp:205
Timer m_ballparkTimer
Definition: Client.h:392
MACHONETMSG_TYPE
Definition: packet_types.h:70
bool m_undock
Definition: Client.h:357
void SetPosition(const GPoint &pos)
std::string method
Definition: PyPacket.h:157
void QueueRep(const PyRep *rep, bool compress=true)
Queues given PyRep into send queue.
int8 siege
Definition: FleetData.h:74
void CharNoLongerInStation()
Definition: Client.cpp:1811
bool m_sessionChangeActive
Definition: Client.h:369
void SendSessionChange()
Definition: Client.cpp:2048
const char * name()
bool IsInSpace()
Definition: Client.h:228
bool m_charCreation
Definition: Client.h:441
uint32 GetNodeID() const
Definition: PyServiceMgr.h:67
PyRep * GetAggressors() const
Definition: Client.cpp:1389
void SendNotifyMsg(const char *fmt,...)
Definition: Client.cpp:2776
CharacterRef GetChar() const
Definition: Client.h:164
Python tuple.
Definition: PyRep.h:567
uint16 GetSOI()
Definition: Tower.h:90
void InitSession(int32 characterID)
Definition: Client.cpp:1858
Definition: Ship.h:301
Advanced version of UserError that allows to send a full custom message.
Definition: PyExceptions.h:453
uint32 GetRemainingTime() const
Definition: timer.cpp:114
void Dump(FILE *into, const char *pfx) const
Dumps object to file.
Definition: PyRep.cpp:84
bool ContainsTypeQty(uint16 typeID, uint32 qty) const
Definition: Client.cpp:1744
int64 rolesAtOther
signed __int8 int8
Definition: eve-compat.h:45
uint32 solarSystemID() const
Definition: Character.h:327
void SendSetState() const
int32 GetAllianceID() const
Definition: Client.h:125
const GPoint & GetPosition() const
Definition: SystemEntity.h:211
void Move(uint32 new_location=locTemp, EVEItemFlags flag=flagNone, bool notify=false)
void Clear(const char *name)
Timer m_sessionTimer
Definition: Client.h:391
static const uint16 MachoNetVersion
Definition: EVEVersion.h:33
std::set< LSCChannel * > m_channels
Definition: Client.h:397
bool Handle_CallReq(PyPacket *packet, PyCallStream &req)
Definition: Client.cpp:2620
TowerSE * GetTowerSE()
Definition: SystemBubble.h:142
void CancelTrade(Client *pClient)
void AddItem(PyRep *i)
Definition: PyRep.h:701
void SafeDelete(T *&p)
Deletes and nullifies a pointer.
Definition: SafeMem.h:83
void RemoveMissionItem(uint16 typeID, uint32 qty)
Definition: Client.cpp:1711
PyTuple * payload
Definition: PyPacket.h:119
void SelfChatMessage(const char *fmt,...)
Definition: Client.cpp:2812
signed __int32 int32
Definition: eve-compat.h:49
uint32 m_locationID
Definition: Client.h:377
const GPoint GetRandPointOnPlanet(uint32 systemID)
void MoveToPosition(const GPoint &pt)
Definition: Client.cpp:928
Timer m_uncloakTimer
Definition: Client.h:385
void Dump(FILE *into, const char *pfx) const
Definition: PyPacket.cpp:284
* args
uint32 constellationID() const
Definition: Character.h:328
GPoint m_dockPoint
Definition: Client.h:395
GPoint m_movePoint
Definition: Client.h:394
Python boolean.
Definition: PyRep.h:323
void CheckBallparkTimer()
Definition: Client.cpp:913
std::string GetLanguageID() const
Definition: Client.h:107
int vasprintf(char **strp, const char *fmt, va_list ap)
Definition: eve-compat.cpp:70
bool HasShip(Client *pClient)
Definition: Station.cpp:242
#define is_log_enabled(type)
Definition: logsys.h:78
void LogOut()
Definition: Ship.cpp:84
#define sFltSvc
Definition: FleetService.h:147
#define sLog
Evaluates to a NewLog instance.
Definition: LogNew.h:250
Value keeper for single EVE session.
Definition: ClientSession.h:37
void Dump(LogType type, PyVisitor &dumper)
Definition: PyPacket.cpp:95
PyRep * ssResult
Definition: PyCallable.h:65
bool InPod()
Definition: Client.h:227
void RemoveStationHangar(uint32 stationID)
Definition: Client.cpp:1656
uint32 clientID
std::string notifyType
Definition: PyPacket.h:172
int64 GetSessionID()
Definition: ClientSession.h:76
MACHONETMSG_TYPE type
Definition: PyPacket.h:115
void SafeFree(T *&p)
Frees and nullifies an array pointer.
Definition: SafeMem.h:111
Definition: gpoint.h:33
bool isSingleton() const
Definition: InventoryItem.h:96
Base class for exceptions that can be converted to python objects.
Definition: PyExceptions.h:39
bool m_autoStop
Definition: Client.h:362
uint32 regionID() const
Definition: Character.h:329
void Heal()
Definition: Ship.cpp:458
DestinyManager * DestinyMgr()
Definition: SystemEntity.h:198
SystemManager * SystemMgr()
Definition: SystemEntity.h:196
SystemGPoint m_SGP
Definition: Client.h:342
double GetTimeUSeconds()
Definition: utils_time.cpp:116
void SetInvul(bool invul=false)
Definition: Client.h:244
bool _VerifyVersion(VersionExchangeClient &version)
Verifies version.
Definition: Client.cpp:2314
Timer m_cloakTimer
Definition: Client.h:384
void VisitSystem(uint32 solarSystemID)
Definition: Character.cpp:1395
uint16 courierTypeID
Definition: EVE_Missions.h:38
EVE derivation of TCP connection.
uint32 stationID() const
Definition: Character.h:326
static const char *const EVEProjectVersion
Definition: EVEVersion.h:36
bool ProcessNet()
Definition: Client.cpp:292
#define IsPlayerItem(itemID)
Definition: EVE_Defines.h:256
uint32 stationID
static const double EVEVersionNumber
Definition: EVEVersion.h:32
bool Enabled() const
Definition: timer.h:41
PyTuple * new_tuple(int64 arg1)
Definition: PyRep.cpp:1160
AddrType type
Definition: PyPacket.h:88
void _SendPingRequest()
Definition: Client.cpp:2528
static const int32 EVEBuildVersion
Definition: EVEVersion.h:34
bool m_afk
Definition: Client.h:354
const char * MACHONETMSG_TYPE_NAMES[MACHONETMSG_TYPE_COUNT]
Definition: PyPacket.cpp:36
bool isDirty() const
Definition: ClientSession.h:43
static void UpdatePassword(uint32 accountID, const char *pass)
Definition: ServiceDB.cpp:170
#define codelog(type, fmt,...)
Definition: logsys.h:128
void SetItem(size_t index, PyRep *object)
Stores Python object.
Definition: PyRep.h:610
static void SetAccountOnlineStatus(uint32 accountID, bool online=false)
Definition: ServiceDB.cpp:198
bool IsDocked()
Definition: Client.h:229
void SendJumpOut(uint32 gateID) const
bool m_validSession
Definition: Client.h:440
std::map< uint32, uint32 > m_lpMap
Definition: Client.h:466
void SetShip(ShipItemRef shipRef)
Definition: Client.cpp:1278
static const GPoint NULL_ORIGIN(0, 0, 0)
#define snprintf
Definition: eve-compat.h:184
void RemoveEntity(SystemEntity *pSE)
PyList * m_destinyUpdateQueue
Definition: Client.h:461
void ChannelJoined(LSCChannel *chan)
Definition: Client.cpp:1799
void SetShipCapacitorLevel(float fraction)
Definition: Ship.cpp:881
void MakeRandomPointOnSphereLayer(double radiusInner, double radiusOuter)
Definition: gpoint.h:59
int64 rolesAtAll
uint32 locationID() const
void SetLauncherID(uint32 shipID)
Definition: Ship.h:359
Python integer.
Definition: PyRep.h:231
bool AlterQuantity(int32 qty, bool notify=false)
PyTuple * arg_tuple
Definition: PyPacket.h:158
void CharacterLogin(Client *pClient)
Definition: LSCService.cpp:907
uint8 race() const
Definition: Character.h:278
bool m_bubbleWait
Definition: Client.h:367
#define sLiveUpdateDB
Definition: LiveUpdateDB.h:47
void UpdateCorpSession(CorpData &data)
Definition: Client.cpp:1970
TradeSession * GetTradeSession()
Definition: Client.h:311
void SetDockCount(Client *pClient, bool docked=false)
int8 info
Definition: FleetData.h:72
void SetSpeedFraction(float fraction=1.0f, bool startMovement=false)
PyServiceMgr & m_services
Definition: Client.h:341
void SetUncloakTimer(uint32 time=Player::Timer::Default)
Definition: Client.cpp:1559
void SetUndocking(bool set=false)
Definition: Ship.h:151
uint32 GetID()
Definition: SystemEntity.h:207
uint32 GetCurrentTime()
Definition: timer.cpp:134
std::string password
void PickAlternateShip()
Definition: Client.cpp:1298
int32 allianceID
void WarpIn()
Definition: Client.cpp:628
bool Check(bool reset=true)
Definition: timer.cpp:62
void AddClient(Client *pClient, bool count=false, bool jump=false)
#define PyStatic
Definition: PyRep.h:1209
void SaveCharacter()
Definition: Character.cpp:1257
X * get() const
Definition: RefPtr.h:213
void BanClient()
Definition: Client.cpp:2287
ShipItemRef GetShip() const
Definition: Client.h:167
void LogOut()
Definition: Character.cpp:336
const char * GetName() const
Definition: Client.h:94
void ChangeOwner(uint32 new_owner, bool notify=false)
int64 Win32TimeNow()
Definition: utils_time.cpp:70
void Board(ShipSE *newShipSE)
Definition: Client.cpp:1086
void ResetAfterPopped(GPoint &position)
Definition: Client.cpp:1209
void SkillQueueLoop(bool update=true)
Definition: Character.cpp:998
ShipItemRef m_pod
Definition: Client.h:338
int64 corpRole
void UpdateNewShip(const ShipItemRef newShipRef)
void SetBallPark()
Definition: Client.cpp:887
void QueueDestinyUpdate(PyTuple **update, bool DoPackage=false, bool IsSetState=false)
Definition: Client.cpp:2131
#define PyDecRef(op)
Definition: PyRep.h:57
#define IsCharacterID(itemID)
Definition: EVE_Defines.h:206
bool IsFleetBoss()
Definition: Client.h:143
#define IsSquadID(itemID)
Definition: EVE_Defines.h:231
ShipItemRef m_ship
Definition: Client.h:337
Client * booster
Definition: FleetData.h:130
Python object "ccp_exceptions.UserError".
Definition: PyExceptions.h:121
LSCService * lsc_service
Definition: PyServiceMgr.h:77
void clear()
Definition: PyRep.cpp:627
void SetUncloak(bool uncloak=false)
Definition: Client.h:247
StationItemRef GetStationFromInventory(uint32 stationID)
std::string bcast_idtype
Definition: PyPacket.h:93
Client session from server's side.
Definition: EVESession.h:49
unsigned __int32 uint32
Definition: eve-compat.h:50
void SetPosition(const GPoint &pt, bool update=false)
uint32 systemID
#define PyIncRef(op)
Definition: PyRep.h:56
uint32 baseID
void UpdateModules()
Definition: Ship.cpp:862
int8 armored
Definition: FleetData.h:70
uint32 regionID
void CloseClientConnection()
Disconnects client from the server.
Definition: EVESession.h:93
void WarpOut()
Definition: Client.cpp:647
void SetCustomInfo(const char *ci)
EVEItemFlags flag() const
bool IsJetcanAvalible()
Definition: Client.cpp:1381
PyServiceMgr * GetServiceMgr()
Definition: SystemManager.h:88
GPoint position
int32 GetCloneStationID() const
Definition: Client.h:116
void LoadStationHangar(uint32 stationID)
Definition: Client.cpp:1667
void ApplyBoost(BoostData &bData)
Definition: Ship.cpp:2757
static const int32 EVEBirthday
Definition: EVEVersion.h:39
int8 skirmish
Definition: FleetData.h:75
uint32 corporationID
int32 m_squad
Definition: Client.h:372
EVETCPConnection *const mNet
Definition: EVESession.h:155
void QueuePacket(PyPacket *packet)
Queues new packet, retaking ownership.
Definition: EVESession.cpp:66
void ResetClone()
Definition: Character.cpp:1252
bool m_packaged
Definition: Client.h:363
void SetInvulTimer(uint32 time=Player::Timer::Default)
Definition: Client.cpp:1579
std::set< uint32 > m_bindSet
Definition: Client.h:443
void Eject()
Definition: Ship.cpp:350
Timer m_stateTimer
Definition: Client.h:381
void VerifySP()
Definition: Character.cpp:311
uint32 corporationID
void CharacterLeavingShip()
uint32 GetLoyaltyPoints(uint32 corpID)
Definition: Client.cpp:1704
double GetFileTimeNow()
Definition: utils_time.cpp:84
RefPtr< ShipItem > ShipItemRef
Definition: ItemRef.h:54
void BoardShip(ShipItemRef newShipRef)
Definition: Client.cpp:1064
static void GetCharacterData(uint32 charID, std::map< std::string, int64 > &characterDataMap)
GPoint dockPosition
#define IsModuleSlot(flag)
Definition: EVE_Defines.h:350
Timer m_scanTimer
Definition: Client.h:383
const char * GetName() const
Definition: SystemManager.h:84
Timer m_invulTimer
Definition: Client.h:386
int64 MakeRandomInt(int64 low, int64 high)
Generates random integer from interval [low; high].
Definition: misc.cpp:109
signed __int64 int64
Definition: eve-compat.h:51
#define IsWingID(itemID)
Definition: EVE_Defines.h:228
const std::string & itemName() const
#define IsCargoHoldFlag(flag)
Definition: EVE_Defines.h:336
void SetDestiny(const GPoint &pt, bool update=false)
Definition: Client.cpp:847
bool IsJump()
Definition: Client.h:232
int16 corpAccountKey
void ResetShipSystemMgr(SystemManager *pSystem)
Definition: Ship.cpp:2512
void StargateJump(uint32 fromGate, uint32 toGate)
Definition: Client.cpp:1410
static bool GetAccountInformation(CryptoChallengePacket &ccp, AccountData &aData, std::string &failMsg)
Definition: ServiceDB.cpp:70
bool HasTower()
Definition: SystemBubble.h:141
void UndockFromStation()
Definition: Client.cpp:975
void _SendQueuedUpdates()
Definition: Client.cpp:2170
#define IsFleetID(itemID)
Definition: EVE_Defines.h:225
~Client()
Definition: Client.cpp:226
void Undock()
Definition: Ship.cpp:370
virtual void SetPlayer(Client *pClient)
Definition: Ship.cpp:106
void SetString(const char *name, const char *value)
uint32 systemID
Client * leader
Definition: FleetData.h:107
GaExpInl bool isZero() const
Definition: GaTypes.h:188
int32 warFactionID
PyPacket * PopPacket()
Pops new packet from queue.
Definition: EVESession.cpp:80
int8 mining
Definition: FleetData.h:73
typeID Spawn an NPC with the specified type text Search for items matching the specified query() type()() itemID() copy() materialLevel()() itemID(attributeID)-Retrieves attribute value." ) COMMAND( setattr
uint32 PickAlternateShip(uint32 locationID)
Definition: Character.cpp:457
bool LoadContents()
Definition: Inventory.cpp:113
ShipItemRef SpawnNewRookieShip(uint32 stationID)
Definition: Client.cpp:1314
void SetStateTimer(int8 state, uint32 time=Player::Timer::Default)
Definition: Client.cpp:1599
void Undock(GPoint dir)
uint32 userid
Definition: PyPacket.h:118
void ProcessScan(bool useProbe=false)
Definition: Scan.cpp:56
virtual void SetPilot(Client *pClient)
Definition: Ship.cpp:2517
ShipSE * pShipSE
Definition: Client.h:343
SystemManager * m_system
Definition: Client.h:346
int8 GetSkillLevel(uint16 skillTypeID, bool zeroForNotInjected=true) const
Definition: Character.cpp:575
state_t GetState() const
Definition: EVESession.h:65
PyRep * ssException
Definition: PyExceptions.h:48
Timer m_jetcanTimer
Definition: Client.h:389
Client * booster
Definition: FleetData.h:120
uint32 m_dockStationID
Definition: Client.h:379
void ResetAfterPodded()
Definition: Client.cpp:1252
static void AddJump(uint32 sysID)
Definition: MapDB.cpp:218
Python object "exceptions.GPSTransportClosed".
Definition: PyExceptions.h:59
PyDict * named_payload
Definition: PyPacket.h:120
void traceStack(void)
Definition: misc.cpp:169
void SendServerMOTD(Client *pClient)
Definition: Tower.h:19
virtual void Delete()
std::string service
Definition: PyPacket.h:92
#define PySafeDecRef(op)
Definition: PyRep.h:61
void DockToStation()
Definition: Client.cpp:942
#define sItemFactory
Definition: ItemFactory.h:165
virtual PyResult Call(const std::string &method, PyCallArgs &args)
Definition: PyCallable.cpp:39
Python buffer.
Definition: PyRep.h:382
static bool ValidateAccountName(CryptoChallengePacket &ccp, std::string &failMsg)
Definition: ServiceDB.cpp:43
void EnterSystem(uint32 systemID)
Definition: Client.cpp:679
StationData m_StationData
Definition: Client.h:339
Timer m_pingTimer
Definition: Client.h:382
bool m_login
Definition: Client.h:356
uint32 constellationID
uint32 _GetQueuePosition()
Definition: Client.h:409
EvilNumber EvilOne
Definition: EvilNumber.cpp:34
void Dock()
Definition: Ship.cpp:2543
void SaveShip()
Definition: Ship.cpp:1060
bool DispatchPacket(PyPacket *packet)
BoostData boost
Definition: FleetData.h:128
void CreateShipSE()
Definition: Client.cpp:1004
GVector dockOrientation
bool IsFleetBooster()
Definition: Client.h:144
std::string remoteObjectStr
Definition: PyPacket.h:155
void DestroyShipSE()
Definition: Client.cpp:1014
GaExpInl GaFloat distance(const GaVec3 &oth) const
Definition: GaTypes.h:158
TradeSession * m_TS
Definition: Client.h:344
PyAddress source
Definition: PyPacket.h:116
void SetDocked()
Definition: Ship.h:150
uint32 capsuleID() const
Definition: Character.h:342
void SetInt(const char *name, int32 value)
void SetSessionTimer()
Definition: Client.h:250
uint16 courierAmount
Definition: EVE_Missions.h:39
bool m_beyonce
Definition: Client.h:359
void MakeRandomPointOnSphere(double radius)
Definition: gpoint.h:46
ClientSession * pSession
Definition: Client.h:345
#define IsRegionID(itemID)
Definition: EVE_Defines.h:273
uint32 destinationID
Definition: EVE_Missions.h:51
void SetShipShield(float fraction)
Definition: Ship.cpp:897
void ClearBoundObject(uint32 bindID)
std::string type_string
Definition: PyPacket.h:112
void _SendCallReturn(const PyAddress &source, int64 callID, PyResult &rsp)
Definition: Client.cpp:2475
void UpdateSession()
Definition: Client.cpp:1935
Scan * m_scan
Definition: Client.h:334
#define sBubbleMgr
bool _VerifyCrypto(CryptoRequestPacket &cr)
Verifies crypto.
Definition: Client.cpp:2330
Client * booster
Definition: FleetData.h:108
void CreateNewPod()
Definition: Client.cpp:1303
Inventory * GetMyInventory()
Definition: InventoryItem.h:91
static const char *const EVEProjectRegion
Definition: EVEVersion.h:35
void SetCloakTimer(uint32 time=Player::Timer::Default)
Definition: Client.cpp:1533
bool HasForceField()
Definition: Tower.h:76
Client * leader
Definition: FleetData.h:119
unsigned __int16 uint16
Definition: eve-compat.h:48
entityID heal the character with the entityID note giving you detailed ship status information gives a list of all dynamic entities and players and their destinyState in this bubble shows some current destiny variables save all kick all and halt server immediate command list all items in current location s gives list of cargo contents and volumes in all holds list current session values show current ship DNA show current objects in their destiny state
virtual void Abandon()
void CynoJump(InventoryItemRef beacon)
Definition: Client.cpp:1454
InventoryItemRef GetByTypeFlag(uint32 typeID, EVEItemFlags flag) const
Definition: Inventory.cpp:444
bool m_scanProbe
Definition: Client.h:366
void SetLoginTime()
Definition: Character.cpp:1290
void SetClient(Client *pClient)
Definition: Character.h:231
uint16 typeID() const
bool empty() const
Definition: PyRep.h:664
int64 m_skillTimer
Definition: Client.h:400
bool _VerifyLogin(CryptoChallengePacket &ccp)
Verifies login.
Definition: Client.cpp:2354
void UpdateNewShip()
Definition: Client.cpp:1025
Python list.
Definition: PyRep.h:639
bool IsHangarLoaded(uint32 stationID)
Definition: Client.cpp:1660
std::string GetAddress() const
Definition: Client.h:106
Timer m_fleetTimer
Definition: Client.h:387
void CheckShipRef(ShipItemRef newShipRef)
Definition: Client.cpp:1049
void EncodeChanges(PyDict *into)
uint32 m_fleet
Definition: Client.h:374
uint32 itemID() const
Definition: InventoryItem.h:98
void SetItemString(const char *key, PyRep *value)
SetItemString adds or sets a database entry.
Definition: PyRep.h:812
void EncodeInitialState(PyDict *into)
void AddStationHangar(uint32 stationID)
Definition: Client.cpp:1652
void Eject()
Definition: Client.cpp:1133
void Jump(bool showCloak=true)
Definition: Ship.cpp:2553
int32 quantity() const
Definition: InventoryItem.h:97
MACHONETERR_TYPE
Definition: packet_types.h:92
Python long integer.
Definition: PyRep.h:261
int8 m_clientState
Definition: Client.h:402
bool _VerifyFuncResult(CryptoHandshakeResult &result)
Verifies function result.
Definition: Client.cpp:2447
bool m_invul
Definition: Client.h:355
#define sDataMgr
void Start(uint32 setTimerTime=0, bool changeResetTimer=true)
Definition: timer.cpp:81
int32 GetUserID() const
Definition: Client.h:109
static const uint32 PING_INTERVAL_MS
Definition: Client.cpp:57