EvEmu  0.8.4
11 September 2021
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
CharUnboundMgrService.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: caytchen, Zhur
24  Updates: Allan
25 */
26 
27 #include "eve-server.h"
28 
29 #include "EntityList.h"
30 #include "EVEServerConfig.h"
31 #include "PyServiceCD.h"
32 #include "account/AccountService.h"
33 #include "cache/ObjCacheService.h"
36 #include "station/StationDataMgr.h"
37 
39 
41 : PyService(mgr, "charUnboundMgr"),
42  m_dispatch(new Dispatcher(this))
43 {
44  _SetCallDispatcher(m_dispatch);
45 
46  PyCallable_REG_CALL(CharUnboundMgrService, SelectCharacterID);
47  PyCallable_REG_CALL(CharUnboundMgrService, GetCharacterToSelect);
48  PyCallable_REG_CALL(CharUnboundMgrService, GetCharactersToSelect);
49  PyCallable_REG_CALL(CharUnboundMgrService, GetCharacterInfo);
50  PyCallable_REG_CALL(CharUnboundMgrService, IsUserReceivingCharacter);
52  PyCallable_REG_CALL(CharUnboundMgrService, PrepareCharacterForDelete);
53  PyCallable_REG_CALL(CharUnboundMgrService, CancelCharacterDeletePrepare);
55  PyCallable_REG_CALL(CharUnboundMgrService, GetCharCreationInfo);
56  PyCallable_REG_CALL(CharUnboundMgrService, GetCharNewExtraCreationInfo);
57  PyCallable_REG_CALL(CharUnboundMgrService, CreateCharacterWithDoll);
58 }
59 
61  delete m_dispatch;
62 }
63 
64 void CharUnboundMgrService::GetCharacterData(uint32 characterID, std::map< std::string, int64 >& characterDataMap)
65 {
66  m_db.GetCharacterData(characterID, characterDataMap);
67 }
68 
69 PyResult CharUnboundMgrService::Handle_ValidateNameEx(PyCallArgs &call)
70 {
72 }
73 
74 PyResult CharUnboundMgrService::Handle_GetCharacterToSelect(PyCallArgs &call)
75 {
77 }
78 
79 PyResult CharUnboundMgrService::Handle_GetCharactersToSelect(PyCallArgs &call)
80 {
81  return m_db.GetCharacterList(call.client->GetUserID());
82 }
83 
84 PyResult CharUnboundMgrService::Handle_DeleteCharacter(PyCallArgs &call)
85 {
87  return nullptr;
88 }
89 
90 PyResult CharUnboundMgrService::Handle_PrepareCharacterForDelete(PyCallArgs &call)
91 {
93 }
94 
95 PyResult CharUnboundMgrService::Handle_CancelCharacterDeletePrepare(PyCallArgs &call)
96 {
98  return nullptr;
99 }
100 
101 PyResult CharUnboundMgrService::Handle_IsUserReceivingCharacter(PyCallArgs &call) {
102  /* this is called when selecting the 3ed slot when there are 2 chars on account already.
103  * returning true will disable creating a 3ed character.
104  * returning false will allow creating a 3ed character.
105  */
106  if (sConfig.character.allow3edChar)
107  return PyStatic.NewFalse();
108  return PyStatic.NewTrue();
109 }
110 
111 // called from petitioner (but only when session.characterID is None)
112 PyResult CharUnboundMgrService::Handle_GetCharacterInfo(PyCallArgs &call) {
113  // chars = sm.RemoteSvc('charUnboundMgr').GetCharacterInfo()
114  _log(CLIENT__ERROR, "Called GetCharacterInfo");
115  // characterID, characterName
116 
117  return nullptr;
118 }
119 
120 PyResult CharUnboundMgrService::Handle_GetCharCreationInfo(PyCallArgs &call) {
121  PyDict *result = new PyDict();
122  //send all the cache hints needed for char creation.
124  _log(CLIENT__MESSAGE, "Sending char creation info reply");
125  return result;
126 }
127 
128 PyResult CharUnboundMgrService::Handle_GetCharNewExtraCreationInfo(PyCallArgs &call) {
129  PyDict *result = new PyDict();
131  _log(CLIENT__MESSAGE, "Sending char new extra creation info reply");
132  return result;
133 }
134 
135 PyResult CharUnboundMgrService::Handle_SelectCharacterID(PyCallArgs &call)
136 {
137  CallSelectCharacterID arg;
138  if (!arg.Decode(&call.tuple)) {
139  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
140  return nullptr;
141  }
142 
143  if (!IsCharacterID(arg.charID)) {
144  sLog.Error("Client::SelectCharacter()", "CharacterID %u invalid.", arg.charID);
145  call.client->SendErrorMsg("Character ID %u invalid. Ref: ServerError 00522", arg.charID);
146  return nullptr;
147  }
148 
149  call.client->SelectCharacter(arg.charID);
150  return nullptr;
151 }
152 
153 PyResult CharUnboundMgrService::Handle_CreateCharacterWithDoll(PyCallArgs &call) {
154  // charID = sm.RemoteSvc('charUnboundMgr').CreateCharacterWithDoll(charactername, bloodlineID, genderID, ancestryID, charInfo, portraitInfo, schoolID)
155  CallCreateCharacterWithDoll arg;
156  if (!arg.Decode(&call.tuple)) {
157  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
158  return PyStatic.NewZero();
159  }
160 
161  // check name and throw on failure before we get too far in this
162  m_db.ValidateCharName(PyRep::StringContent(arg.charactername));
163 
164  Client* pClient = call.client;
165  pClient->CreateChar(true);
166 
167  if (!pClient->RecPic())
168  pClient->SendInfoModalMsg("The Portrait for this character was not received. Your character will still be created, but the server will not have their picture.");
169 
170  _log(CLIENT__MESSAGE, "Calling CreateCharacterWithDoll with schoolID: %i bloodlineID: %i gender: %s ancestryID: %i", \
171  arg.schoolID, arg.bloodlineID, arg.genderID == 1 ? "male" : "female", arg.ancestryID);
172 
173  // obtain character type
174  const CharacterType *char_type = sItemFactory.GetCharacterTypeByBloodline(arg.bloodlineID);
175  if (char_type == nullptr)
176  return PyStatic.NewZero();
177 
178  // we need to fill these to successfully create character item
179  CharacterData cdata = CharacterData();
180  cdata.accountID = pClient->GetUserID();
181  cdata.gender = arg.genderID;
182  cdata.ancestryID = arg.ancestryID;
183  cdata.bloodlineID = arg.bloodlineID;
184  cdata.schoolID = arg.schoolID;
185  cdata.description = "Character Created on ";
186  cdata.description += currentDateTime();
187  cdata.securityRating = sConfig.character.startSecRating;
188  cdata.title = "No Title";
190 
191  //Set the character's career and race based on the school they picked.
192  if (m_db.GetCareerBySchool(cdata.schoolID, cdata.raceID, cdata.careerID)) {
193  // The Specialization has been taken out in Crucible. set to same as Career (default)
194  cdata.careerSpecialityID = cdata.careerID;
195  } else {
196  _log(CLIENT__MESSAGE, "Could not find default School ID %u. Using Caldari Military.", cdata.schoolID);
197  cdata.raceID = 1;
198  cdata.careerID = 11;
199  cdata.careerSpecialityID = 11;
200  }
201 
202  // Variables for storing attribute bonuses
203  uint8 intelligence = char_type->intelligence();
204  uint8 charisma = char_type->charisma();
205  uint8 perception = char_type->perception();
206  uint8 memory = char_type->memory();
207  uint8 willpower = char_type->willpower();
208 
209  CorpData corpData = CorpData();
210  corpData.startDateTime = cdata.createDateTime;
211  corpData.corpRole = Corp::Role::Member;
213  corpData.rolesAtAll = Corp::Role::Member;
214  corpData.rolesAtBase = Corp::Role::Member;
215  corpData.rolesAtHQ = Corp::Role::Member;
216  corpData.rolesAtOther = Corp::Role::Member;
221 
222  bool defCorp = true;
223  if (sConfig.character.startCorporation) { // Skip if 0
224  if( m_db.DoesCorporationExist( sConfig.character.startCorporation ) ) {
225  corpData.corporationID = sConfig.character.startCorporation;
226  defCorp = false;
227  } else {
228  _log(CLIENT__MESSAGE, "Could not find default Corporation ID %u. Using Career Defaults instead.", sConfig.character.startCorporation);
229  }
230  }
231  if (defCorp) {
232  if (!m_db.GetCorporationBySchool(cdata.schoolID, corpData.corporationID))
233  _log(CLIENT__MESSAGE, "Could not place character in default corporation for school.");
234  }
235 
236  // Setting character's default starting position, and getting the location...
237  // this also sets schoolID and corporationID based on career
239 
240  if (sDataMgr.IsStation(sConfig.character.startStation)) { // Skip if 0
241  cdata.stationID = sConfig.character.startStation;
242  StationData sData = StationData();
243  stDataMgr.GetStationData(cdata.stationID, sData);
244  cdata.solarSystemID = sData.systemID;
245  cdata.constellationID = sData.constellationID;
246  cdata.regionID = sData.regionID;
247  }
248 
249  corpData.baseID = cdata.stationID;
250 
251  cdata.typeID = char_type->id();
252  cdata.name = PyRep::StringContent(arg.charactername);
253  cdata.locationID = cdata.stationID;
254  cdata.logonMinutes = 2;
255 
256  sItemFactory.SetUsingClient( pClient );
257 
258  CharacterRef charRef = sItemFactory.SpawnCharacter(cdata, corpData);
259  if (charRef.get() == nullptr) {
260  //a return to the client of 0 seems to be the only means of marking failure
261  _log(CLIENT__ERROR, "Failed to create character '%s'", cdata.name.c_str());
262  sItemFactory.UnsetUsingClient();
263  return PyStatic.NewZero();
264  }
265  charRef->SetClient(pClient); // set client in char
266 
267  // add call to JoinCorp here, and remove corp shit from charDB
268 
269  //this builds and saves appearance data from charInfo dict
270  CharacterAppearance capp;
271  capp.Build(charRef->itemID(), arg.charInfo);
272 
273  //this builds and saves portrait data from portraitInfo dict
274  CharacterPortrait cpor;
275  cpor.Build(charRef->itemID(), arg.portraitInfo);
276 
277  // query attribute bonuses from ancestry
278  if (!m_db.GetAttributesFromAncestry(cdata.ancestryID, intelligence, charisma, perception, memory, willpower)) {
279  _log(CLIENT__ERROR, "Failed to load char create details. Bloodline %u, ancestry %u.", char_type->bloodlineID(), cdata.ancestryID);
280  sItemFactory.UnsetUsingClient();
281  return PyStatic.NewZero();
282  }
283  // triple attributes and save
284  uint8 multiplier = sConfig.character.statMultiplier;
285  charRef->SetAttribute(AttrIntelligence, intelligence * multiplier, false);
286  charRef->SetAttribute(AttrCharisma, charisma * multiplier, false);
287  charRef->SetAttribute(AttrPerception, perception * multiplier, false);
288  charRef->SetAttribute(AttrMemory, memory * multiplier, false);
289  charRef->SetAttribute(AttrWillpower, willpower * multiplier, false);
290 
291  //load skills
292  std::map<uint32, uint8> startingSkills;
293  startingSkills.clear();
294  // Base Skills
295  if (!m_db.GetBaseSkills(startingSkills)) {
296  _log(CLIENT__ERROR, "Failed to load char Base skills. Bloodline %u, Ancestry %u.",
297  char_type->bloodlineID(), cdata.ancestryID);
298  // dont really care if this fails. not enough to deny creation ...maybe make error?
299  }
300  // Race Skills
301  if (!m_db.GetSkillsByRace(char_type->race(), startingSkills)) {
302  _log(CLIENT__ERROR, "Failed to load char Race skills. Bloodline %u, Ancestry %u.",
303  char_type->bloodlineID(), cdata.ancestryID);
304  // dont really care if this fails. not enough to deny creation ...maybe make error?
305  }
306  // Career Skills
307  if (!m_db.GetSkillsByCareer(cdata.careerID, startingSkills)) {
308  _log(CLIENT__ERROR, "Failed to load char Career skills for %u.", cdata.careerSpecialityID);
309  // dont really care if this fails. not enough to deny creation ...maybe make error?
310  }
311 
312  //spawn all the skills
313  uint8 skillLevel = 0;
314  uint32 skillPoints = 0;
315  for (auto cur : startingSkills) {
316  ItemData skillItem( cur.first, charRef->itemID(), charRef->itemID(), flagSkill );
317  SkillRef skill = sItemFactory.SpawnSkill( skillItem );
318  if (skill.get() == nullptr) {
319  _log(CLIENT__ERROR, "Failed to add skill %u to char %s(%u) during create.",
320  cur.first, charRef->name(), charRef->itemID());
321  // missed a skill...whatever.
322  continue;
323  }
324 
325  skillLevel = cur.second;
326  skill->SetAttribute(AttrSkillLevel, skillLevel, false);
327  skillPoints = skill->GetSPForLevel(skillLevel);
328  skill->SetAttribute(AttrSkillPoints, skillPoints, false);
329  skill->SaveItem();
330  cdata.skillPoints += skillPoints;
331  charRef->SaveSkillHistory(EvESkill::Event::SkillPointsApplied/*EvESkill::Event::CharCreation*/, // 'CharCreation' shows as "Unknown" in PD>Skill>History
332  GetFileTimeNow(),
333  charRef->itemID(),
334  cur.first,
335  skillLevel,
336  skillPoints);
337  }
338 
339  //now set up some initial inventory:
342  // add client to EntityList for subsequent calls that need Client* (AttributeMap changes)
343  pClient->SetChar(charRef); // AddPlayer() needs charRef
344  sEntityList.AddPlayer(pClient);
345 
346  // need system loaded for proper ship creation/loading and subsquent character login
347  sEntityList.FindOrBootSystem(cdata.solarSystemID);
348 
349  // create alpha-level clone
350  ItemData iData( itemCloneAlpha, charRef->itemID(), cdata.locationID, flagClone, 1 );
351  iData.customInfo="Active: ";
352  iData.customInfo += charRef->itemName();
353  iData.customInfo += "(";
354  iData.customInfo += std::to_string(charRef->itemID());
355  iData.customInfo += ")";
356  sItemFactory.SpawnItem( iData )->SaveItem();
357 
358  // give the player their pod and set in system (NOT hangar)
359  pClient->CreateNewPod();
360  pClient->GetPod()->Move(cdata.solarSystemID, flagCapsule, false);
361 
362  ShipItemRef sRef = pClient->SpawnNewRookieShip(cdata.locationID);
363  // set shipID in client and char objects and save (shipID error fix)
364  pClient->SetShip(sRef);
365  charRef->SaveFullCharacter();
366 
367  // Release the item factory now that the character is finished being accessed:
368  sItemFactory.UnsetUsingClient();
369 
370  // we need to report the charID to the ImageServer so it can correctly assign a previously received image
371  sImageServer.ReportNewCharacter(pClient->GetUserID(), charRef->itemID());
372 
373  // add charID to staticOwners
374  m_db.addOwnerCache(charRef->itemID(), charRef->itemName(), char_type->id());
375 
376  std::string reason = "DESC: Inheritance Payment to ";
377  reason += charRef->itemName();
378  AccountService::TranserFunds(corpSCC, charRef->itemID(), sConfig.character.startBalance, reason, Journal::EntryType::Inheritance);
379  AccountService::TranserFunds(corpSCC, charRef->itemID(), sConfig.character.startAurBalance, reason, \
381 
382  charRef->LogOut();
383  sRef->LogOut();
384 
385  sEntityList.RemovePlayer(pClient);
386 
387  pClient->CreateChar(false);
388 
389  _log( CLIENT__MESSAGE, "Created New Character - Sending charID %u as reply", charRef->itemID() );
390 
391  return new PyInt(charRef->itemID());
392 }
#define sConfig
A macro for easier access to the singleton.
Dispatcher *const m_dispatch
unsigned __int8 uint8
Definition: eve-compat.h:46
static std::string StringContent(PyRep *pRep)
Definition: PyRep.cpp:103
ShipItemRef GetPod() const
Definition: Client.h:169
void SendErrorMsg(const char *fmt,...)
Definition: Client.cpp:2719
#define _log(type, fmt,...)
Definition: logsys.h:124
int64 grantableRolesAtHQ
#define stDataMgr
uint16 id() const
Definition: ItemType.h:63
void InsertCacheHints(hintSet hset, PyDict *into)
PyRep * GetItem(size_t index) const
Returns Python object.
Definition: PyRep.h:602
#define sImageServer
Definition: ImageServer.h:93
PyRep * GetCharSelectInfo(uint32 charID)
bool RecPic()
Definition: Client.h:318
Python's dictionary.
Definition: PyRep.h:719
int64 startDateTime
PyRep * GetCharacterList(uint32 accountID)
void SaveSkillHistory(uint16 eventID, double logDate, uint32 characterID, uint16 skillTypeID, uint8 skillLevel, uint32 absolutePoints)
Definition: Character.cpp:689
int64 rolesAtHQ
int64 rolesAtBase
uint8 perception() const
Definition: Character.h:101
Dispatcher *const m_dispatch
uint32 skillPoints
void SendInfoModalMsg(const char *fmt,...)
Definition: Client.cpp:2756
bool SelectCharacter(int32 char_id=0)
Definition: Client.cpp:316
#define sEntityList
Definition: EntityList.h:208
bool DoesCorporationExist(uint32 corpID)
const char * name()
const char * GetName() const
Definition: PyService.h:54
int64 rolesAtOther
void Move(uint32 new_location=locTemp, EVEItemFlags flag=flagNone, bool notify=false)
int64 createDateTime
uint8 charisma() const
Definition: Character.h:103
void CancelCharacterDeletePrepare(uint32 accountID, uint32 charID)
std::string customInfo
Definition: ItemType.h:194
void DeleteCharacter(uint32 charID)
void addOwnerCache(uint32 ownerID, std::string ownerName, uint32 typeID)
void LogOut()
Definition: Ship.cpp:84
#define sLog
Evaluates to a NewLog instance.
Definition: LogNew.h:250
bool GetAttributesFromAncestry(uint32 ancestryID, uint8 &intelligence, uint8 &charisma, uint8 &perception, uint8 &memory, uint8 &willpower)
int64 PrepareCharacterForDelete(uint32 accountID, uint32 charID)
std::string name
void SaveFullCharacter()
Definition: Character.cpp:1266
const std::string currentDateTime()
Definition: utils_time.cpp:125
#define codelog(type, fmt,...)
Definition: logsys.h:128
uint32 solarSystemID
void SetShip(ShipItemRef shipRef)
Definition: Client.cpp:1278
void CreateChar(bool set)
Definition: Client.h:434
std::string description
static void TranserFunds(uint32 fromID, uint32 toID, double amount, std::string reason="", uint8 entryTypeID=Journal::EntryType::Undefined, uint32 referenceID=0, uint16 fromKey=Account::KeyType::Cash, uint16 toKey=Account::KeyType::Cash, Client *pClient=nullptr)
int64 rolesAtAll
Python integer.
Definition: PyRep.h:231
void SetChar(CharacterRef charRef)
Definition: Client.h:163
uint8 bloodlineID() const
Definition: Character.h:93
float securityRating
void SetAttribute(uint16 attrID, int num, bool notify=true)
PyServiceMgr *const m_manager
Definition: PyService.h:91
bool GetCareerBySchool(uint32 schoolID, uint8 &raceID, uint32 &careerID)
#define PyStatic
Definition: PyRep.h:1209
X * get() const
Definition: RefPtr.h:213
void LogOut()
Definition: Character.cpp:336
uint32 constellationID
int64 corpRole
Client *const client
Definition: PyCallable.h:49
#define IsCharacterID(itemID)
Definition: EVE_Defines.h:206
#define PyCallable_REG_CALL(c, m)
Definition: PyServiceCD.h:78
Definition: Client.h:66
unsigned __int32 uint32
Definition: eve-compat.h:50
uint32 baseID
bool GetSkillsByRace(uint32 raceID, std::map< uint32, uint8 > &into)
PyCallable_Make_InnerDispatcher(CharUnboundMgrService) CharUnboundMgrService
void Build(uint32 charID, PyDict *data)
Definition: Character.cpp:172
uint32 logonMinutes
uint32 corporationID
double GetFileTimeNow()
Definition: utils_time.cpp:84
static void GetCharacterData(uint32 charID, std::map< std::string, int64 > &characterDataMap)
signed __int64 int64
Definition: eve-compat.h:51
const std::string & itemName() const
int16 corpAccountKey
void Build(uint32 ownerID, PyDict *data)
Definition: Character.cpp:94
void GetCharacterData(uint32 characterID, std::map< std::string, int64 > &characterDataMap)
bool GetBaseSkills(std::map< uint32, uint8 > &into)
Handles everything related to creating, deleting and selecting a character.
ObjCacheService * cache_service
Definition: PyServiceMgr.h:78
uint8 race() const
Definition: ItemType.h:72
ShipItemRef SpawnNewRookieShip(uint32 stationID)
Definition: Client.cpp:1314
PyRep * ValidateCharNameRep(std::string name)
bool GetSkillsByCareer(uint32 careerID, std::map< uint32, uint8 > &into)
bool GetCorporationBySchool(uint32 schoolID, uint32 &corporationID)
#define sItemFactory
Definition: ItemFactory.h:165
uint8 memory() const
Definition: Character.h:104
static int64 IntegerValue(PyRep *pRep)
Definition: PyRep.cpp:118
int64 grantableRoles
std::string title
int64 grantableRolesAtBase
void CreateNewPod()
Definition: Client.cpp:1303
int64 grantableRolesAtOther
uint8 intelligence() const
Definition: Character.h:105
uint32 constellationID
uint8 willpower() const
Definition: Character.h:102
void SetClient(Client *pClient)
Definition: Character.h:231
bool GetLocationCorporationByCareer(CharacterData &cdata, uint32 &corporationID)
uint32 itemID() const
Definition: InventoryItem.h:98
uint32 careerSpecialityID
void ValidateCharName(std::string name)
Python long integer.
Definition: PyRep.h:261
PyTuple * tuple
Definition: PyCallable.h:50
#define sDataMgr
int32 GetUserID() const
Definition: Client.h:109