EvEmu  0.8.4
11 September 2021
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
CharacterDB.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
25 */
26 
27 #include "eve-server.h"
28 
29 #include "EVEServerConfig.h"
30 #include "character/Character.h"
31 #include "character/CharacterDB.h"
32 
33 uint32 CharacterDB::NewCharacter(const CharacterData& data, const CorpData& corpData) {
34  DBerror err;
35  std::string nameEsc, titleEsc, descriptionEsc;
36  sDatabase.DoEscapeString(nameEsc, data.name);
37  sDatabase.DoEscapeString(titleEsc, data.title);
38  sDatabase.DoEscapeString(descriptionEsc, data.description);
39 
40  uint32 charID = 0;
41  if (!sDatabase.RunQueryLID(err, charID,
42  "INSERT INTO chrCharacters"
43  " (accountID, characterName, typeID, locationID, description, balance, aurBalance,"
44  " logonDateTime, baseID, corpAccountKey, createDateTime, title,"
45  " ancestryID, bloodlineID, raceID, careerID, schoolID, careerSpecialityID, gender,"
46  " stationID, solarSystemID, constellationID, regionID, freeRespecs)"
47  " VALUES"
48  " (%u,'%s', %u, %u, '%s', %f, %f,"
49  " %f, %u, %u, %f, '%s',"
50  " %u, %u, %u, %u, %u, %u, %u,"
51  " %u, %u, %u, %u, 2)",
52  data.accountID, nameEsc.c_str(), data.typeID, data.locationID, descriptionEsc.c_str(), data.balance, data.aurBalance,
53  GetFileTimeNow(), corpData.baseID, corpData.corpAccountKey, GetFileTimeNow(), titleEsc.c_str(),
54  data.ancestryID, data.bloodlineID, data.raceID, data.careerID, data.schoolID, data.careerSpecialityID, data.gender,
55  data.stationID, data.solarSystemID, data.constellationID, data.regionID))
56  {
57  codelog(DATABASE__ERROR, "Failed to insert character %s.", err.c_str());
58  return 0;
59  }
60 
61  AddEmployment(charID, corpData.corporationID);
62 
63  return charID;
64 }
65 
66 bool CharacterDB::SaveCharacter(uint32 characterID, const CharacterData &data) {
67  DBerror err;
68 
69  std::string titleEsc, descriptionEsc;
70  sDatabase.DoEscapeString(titleEsc, data.title);
71  sDatabase.DoEscapeString(descriptionEsc, data.description);
72 
73  if (!sDatabase.RunQuery(err,
74  "UPDATE chrCharacters"
75  " SET"
76  " title = '%s',"
77  " description = '%s',"
78  " bounty = %f,"
79  " balance = %f,"
80  " aurBalance = %f,"
81  " securityRating = %f,"
82  " logonMinutes = %u,"
83  " skillPoints = %u,"
84  " locationID = %u,"
85  " stationID = %u,"
86  " solarSystemID = %u,"
87  " constellationID = %u,"
88  " regionID = %u"
89  " WHERE characterID = %u",
90  titleEsc.c_str(), descriptionEsc.c_str(), data.bounty, data.balance, data.aurBalance, data.securityRating, data.logonMinutes,
91  data.skillPoints, data.locationID, data.stationID, data.solarSystemID, data.constellationID, data.regionID, characterID))
92  {
93  codelog(DATABASE__ERROR, "Failed to save character %u: %s.", characterID, err.c_str());
94  return false;
95  }
96 
97  return true;
98 }
99 
100 bool CharacterDB::SaveCorpData(uint32 characterID, const CorpData &data) {
101  DBerror err;
102 
103  if (!sDatabase.RunQuery(err,
104  "UPDATE chrCharacters"
105  " SET"
106  " corporationID = %u, "
107  " baseID = %u,"
108  " corpRole = %li,"
109  " corpAccountKey = %i,"
110  " rolesAtAll = %li,"
111  " rolesAtBase = %li,"
112  " rolesAtHQ = %li,"
113  " rolesAtOther = %li,"
114  " grantableRoles = %li,"
115  " grantableRolesAtBase = %li,"
116  " grantableRolesAtHQ = %li,"
117  " grantableRolesAtOther = %" PRIi64
118  " WHERE characterID = %u",
119  data.corporationID, data.baseID, data.corpRole, data.corpAccountKey, data.rolesAtAll, data.rolesAtBase, data.rolesAtHQ, data.rolesAtOther,
121  {
122  codelog(DATABASE__ERROR, "Failed to update corp member info of character %u: %s.", characterID, err.c_str());
123  return false;
124  }
125 
126  return true;
127 }
128 
137  DBerror err;
138  sDatabase.RunQuery(err, "DELETE FROM eveMailDetails"
139  " USING eveMail, eveMailDetails"
140  " WHERE eveMail.messageID = eveMailDetails.messageID"
141  " AND (senderID = %u OR channelID = %u)", characterID, characterID);
142  sDatabase.RunQuery(err, "DELETE FROM eveMail WHERE (senderID = %u OR channelID = %u)", characterID, characterID);
143  sDatabase.RunQuery(err, "DELETE FROM bookmarks WHERE ownerID = %u", characterID);
144  sDatabase.RunQuery(err, "DELETE FROM bookmarkFolders WHERE ownerID = %u", characterID);
145  //sDatabase.RunQuery(err, "DELETE FROM bookmarkVouchers WHERE ownerID = %u", characterID);
146  sDatabase.RunQuery(err, "DELETE FROM mktOrders WHERE ownerID = %u", characterID);
147  sDatabase.RunQuery(err, "DELETE FROM mktTransactions WHERE clientID = %u", characterID);
148  sDatabase.RunQuery(err, "DELETE FROM repStandings WHERE (fromID = %u OR toID = %u)", characterID, characterID);
149  sDatabase.RunQuery(err, "DELETE FROM repStandingChanges WHERE (fromID = %u OR toID = %u)", characterID, characterID);
150  sDatabase.RunQuery(err, "DELETE FROM chrCertificates WHERE characterID=%u", characterID);
151  sDatabase.RunQuery(err, "DELETE FROM chrCharacters WHERE characterID=%u", characterID);
152  sDatabase.RunQuery(err, "DELETE FROM chrEmployment WHERE characterID=%u", characterID);
153  sDatabase.RunQuery(err, "DELETE FROM jnlCharacters WHERE ownerID=%u", characterID);
154  sDatabase.RunQuery(err, "DELETE FROM crpShares WHERE shareholderID=%u", characterID);
155  sDatabase.RunQuery(err, "DELETE FROM chrSkillHistory WHERE characterID=%u", characterID);
156  sDatabase.RunQuery(err, "DELETE FROM chrSkillQueue WHERE characterID=%u", characterID);
157  sDatabase.RunQuery(err, "DELETE FROM crpApplications WHERE characterID=%u", characterID);
158  sDatabase.RunQuery(err, "DELETE FROM chrCharacterAttributes WHERE charID = %u", characterID);
159  sDatabase.RunQuery(err, "DELETE FROM chrPausedSkillQueue WHERE characterID = %u", characterID);
160  sDatabase.RunQuery(err, "DELETE FROM entity_attributes"
161  " WHERE itemID IN (SELECT itemID FROM entity WHERE ownerID = %u)", characterID);
162  sDatabase.RunQuery(err, "DELETE FROM entity WHERE ownerID = %u", characterID);
163  sDatabase.RunQuery(err, "DELETE FROM avatar_colors WHERE charID = %u", characterID);
164  sDatabase.RunQuery(err, "DELETE FROM avatar_modifiers WHERE charID = %u", characterID);
165  sDatabase.RunQuery(err, "DELETE FROM avatar_sculpts WHERE charID = %u", characterID);
166  sDatabase.RunQuery(err, "DELETE FROM avatars WHERE charID = %u", characterID);
167 }
168 
170 {
171  DBerror error;
172  if (!sDatabase.RunQuery(error, "UPDATE chrCharacters SET freeRespecs = freeRespecs - 1, lastRespecDateTime = %f, nextRespecDateTime = %li WHERE characterId = %u",
173  GetFileTimeNow(), (GetFileTimeNow() + EvE::Time::Month *3), characterId))
174  return false;
175  return true;
176 }
177 
179 {
180  DBQueryResult res;
181  if (!sDatabase.RunQuery(res, "SELECT freeRespecs, lastRespecDateTime, nextRespecDateTime FROM chrCharacters WHERE characterID = %u", characterId))
182  return nullptr;
183  DBResultRow row;
184  if (!res.GetRow(row))
185  return nullptr;
186 
187  PyDict* result = new PyDict();
188  result->SetItemString( "freeRespecs", new PyInt( row.GetInt(0) ) );
189  result->SetItemString( "lastRespecDate", new PyLong( row.GetInt64(1) ) );
190  result->SetItemString( "nextTimedRespec", new PyLong( row.GetInt64(2) ) );
191 
192  return result;
193 }
194 
196 {
197  // calculate the point in time from which this character may be deleted
198  int64 deleteTime = GetFileTimeNow() + (EvE::Time::Second * sConfig.character.terminationDelay);
199 
200  // note: the queries relating to character deletion have been specifically designed to avoid wreaking havoc when used by a malicious client
201  // the client can't lie to us about accountID, only charID
202 
203  DBerror error;
204  uint32 affectedRows;
205  sDatabase.RunQuery(error, affectedRows, "UPDATE chrCharacters SET deletePrepareDateTime = %li WHERE accountID = %u AND characterID = %u", deleteTime, accountID, charID);
206  if (affectedRows != 1)
207  return 0;
208 
209  return deleteTime;
210 }
211 
213 {
214  DBerror error;
215  uint32 affectedRows;
216  sDatabase.RunQuery(error, affectedRows, "UPDATE chrCharacters SET deletePrepareDateTime = 0 WHERE accountID = %u AND characterID = %u", accountID, charID);
217  if (affectedRows != 1)
218  _log(CLIENT__ERROR, "Failed to cancel character deletion, affected rows: %u", affectedRows);
219 }
220 
222  DBQueryResult res;
223  if (!sDatabase.RunQuery(res,
224  "SELECT"
225  " characterID,"
226  " characterName,"
227  " deletePrepareDateTime,"
228  " gender,"
229  " typeID"
230  " FROM chrCharacters"
231  " WHERE accountID=%u", accountID))
232  {
233  codelog(DATABASE__ERROR, "Error in query: %s", res.error.c_str());
234  return nullptr;
235  }
236 
237  return DBResultToCRowset(res);
238 }
239 
241 {
251  // *name is sent from client WITHOUT leading space, if there is one, and will not allow more than one space.
252 
253  if (name.empty())
254  return new PyInt(-1);
255  if (name.length() < 3)
256  return new PyInt(-1);
257  if (name.length() > 37) //client caps at 24
258  return new PyInt(-2);
259 
260  if (!sDatabase.IsSafeString(name.c_str()))
261  return new PyInt(-5);
262 
263  for (const auto cur : badWords)
264  if (EvE::icontains(name, cur))
265  return new PyInt(-5);
266 
267  for (const auto cur : badChars)
268  if (EvE::icontains(name, cur))
269  return new PyInt(-5);
270 
271  // check for consecutive spaces
272  if (EvE::icontains(name, " "))
273  return new PyInt(-7);
274 
275  // check for multiple spaces
276  int found = name.find(" ");
277  if (found != name.npos) {
278  found = name.find(" ", found + 1, 1);
279  if (found != name.npos)
280  return new PyInt(-6);
281  }
282 
283  std::string eName;
284  sDatabase.DoEscapeString(eName, name.c_str());
285  DBQueryResult res;
286  sDatabase.RunQuery(res, "SELECT characterID FROM chrCharacters WHERE characterName LIKE '%s' ", eName.c_str() );
287  if (res.GetRowCount() > 0) // name exists
288  return new PyInt(-101);
289 
290  /* if we got here the name is "new" */
291  return PyStatic.NewOne();
292 }
293 
296 {
297  /* {'messageKey': 'CharNameInvalid', 'dataID': 17885077, 'suppressable': False, 'bodyID': 260107, 'messageType': 'notify', 'urlAudio': '', 'urlIcon': '', 'titleID': None, 'messageID': 471}
298  * {'messageKey': 'CharNameInvalidBannedWord', 'dataID': 17884963, 'suppressable': False, 'bodyID': 260067, 'messageType': 'notify', 'urlAudio': '', 'urlIcon': '', 'titleID': None, 'messageID': 472}
299  * {'messageKey': 'CharNameInvalidFirstChar', 'dataID': 17884966, 'suppressable': False, 'bodyID': 260068, 'messageType': 'notify', 'urlAudio': '', 'urlIcon': '', 'titleID': None, 'messageID': 473}
300  * {'messageKey': 'CharNameInvalidLastChar', 'dataID': 17884969, 'suppressable': False, 'bodyID': 260069, 'messageType': 'notify', 'urlAudio': '', 'urlIcon': '', 'titleID': None, 'messageID': 474}
301  * {'messageKey': 'CharNameInvalidMaxLength', 'dataID': 17885083, 'suppressable': False, 'bodyID': 260109, 'messageType': 'notify', 'urlAudio': '', 'urlIcon': '', 'titleID': None, 'messageID': 475}
302  * {'messageKey': 'CharNameInvalidMaxSpaces', 'dataID': 17884972, 'suppressable': False, 'bodyID': 260070, 'messageType': 'notify', 'urlAudio': '', 'urlIcon': '', 'titleID': None, 'messageID': 476}
303  * {'messageKey': 'CharNameInvalidMinLength', 'dataID': 17884975, 'suppressable': False, 'bodyID': 260071, 'messageType': 'notify', 'urlAudio': '', 'urlIcon': '', 'titleID': None, 'messageID': 477}
304  * {'messageKey': 'CharNameInvalidSomeChar', 'dataID': 17884978, 'suppressable': False, 'bodyID': 260072, 'messageType': 'notify', 'urlAudio': '', 'urlIcon': '', 'titleID': None, 'messageID': 478}
305  * {'messageKey': 'CharNameInvalidTaken', 'dataID': 17884981, 'suppressable': False, 'bodyID': 260073, 'messageType': 'notify', 'urlAudio': '', 'urlIcon': '', 'titleID': None, 'messageID': 479}
306  * {'messageKey': 'CharNameTooShort', 'dataID': 17884986, 'suppressable': False, 'bodyID': 260075, 'messageType': 'info', 'urlAudio': '', 'urlIcon': '', 'titleID': 260074, 'messageID': 482}
307  */
308  /* {'FullPath': u'UI/Messages', 'messageID': 260067, 'label': u'CharNameInvalidBannedWordBody'}(u'Character name contains a banned word.', None, None)
309  * {'FullPath': u'UI/Messages', 'messageID': 260068, 'label': u'CharNameInvalidFirstCharBody'}(u'First character in character name is illegal.', None, None)
310  * {'FullPath': u'UI/Messages', 'messageID': 260069, 'label': u'CharNameInvalidLastCharBody'}(u'Last character in character name is illegal.', None, None)
311  * {'FullPath': u'UI/Messages', 'messageID': 260070, 'label': u'CharNameInvalidMaxSpacesBody'}(u'Character name can only include 1 space.', None, None)
312  * {'FullPath': u'UI/Messages', 'messageID': 260071, 'label': u'CharNameInvalidMinLengthBody'}(u'Minimum length for a character name is 4 characters.', None, None)
313  * {'FullPath': u'UI/Messages', 'messageID': 260072, 'label': u'CharNameInvalidSomeCharBody'}(u'Character name contains an illegal character.', None, None)
314  * {'FullPath': u'UI/Messages', 'messageID': 260073, 'label': u'CharNameInvalidTakenBody'}(u'Character name is already taken.', None, None)
315  * {'FullPath': u'UI/Messages', 'messageID': 260074, 'label': u'CharNameTooShortTitle'}(u'Name Too Short', None, None)
316  * {'FullPath': u'UI/Messages', 'messageID': 260075, 'label': u'CharNameTooShortBody'}(u'The name must be at least 3 characters long.', None, None)
317  * {'FullPath': u'UI/Messages', 'messageID': 260107, 'label': u'CharNameInvalidBody'}(u'The name you have selected for your character is not valid', None, None)
318  * {'FullPath': u'UI/Messages', 'messageID': 260109, 'label': u'CharNameInvalidMaxLengthBody'}(u'Maximum length for a character name is 37 characters. The first and second name must be less than 24 character combined, and the third name must be less than 12 characters.', None, None)
319  * {'FullPath': u'UI/CharacterCreation/InvalidName', 'messageID': 233748, 'label': u'IllegalCharacter'}(u'Name contains illegal characters.', None, None)
320  * {'FullPath': u'UI/CharacterCreation/InvalidName', 'messageID': 233749, 'label': u'TooShort'}(u'Name is too short.', None, None)
321  * {'FullPath': u'UI/CharacterCreation/InvalidName', 'messageID': 233750, 'label': u'Unavailable'}(u'Name is unavailable.', None, None)
322  *
323  * {'FullPath': u'UI/Messages', 'messageID': 258506, 'label': u'CharCreationNameError1Title'}(u'Information', None, None)
324  * {'FullPath': u'UI/Messages', 'messageID': 258507, 'label': u'CharCreationNameError1Body'}(u'You have to type some name to be able to proceed.', None, None)
325  * {'FullPath': u'UI/Messages', 'messageID': 258508, 'label': u'CharCreationNameError3Title'}(u'Information', None, None)
326  * {'FullPath': u'UI/Messages', 'messageID': 258509, 'label': u'CharCreationNameError3Body'}(u'The name contains either illegal characters, is already taken or is not allowed.', None, None)
327  *
328  */
329 
330  // *name is sent from client WITHOUT leading space, if there is one, and will not allow more than one space.
331 
332  if (name.empty())
333  throw UserError ("CharNameInvalid");
334  if (name.length() < 3)
335  throw UserError ("CharNameTooShort");
336  //if (name.length() < 4)
337  // throw UserError ("CharNameInvalidMinLength");
338  if (name.length() > 37) //client caps at 24
339  throw UserError ("CharNameInvalidMaxLength");
340 
341  //if (!sDatabase.IsSafeString(name.c_str()))
342  // throw UserError ("CharNameInvalidSomeChar");
343 
344  //if (name.at(0) == "+")
345  // throw UserError ("CharNameInvalidFirstChar");
346 
347  // check for banned words in char name
348  for (const auto cur : badWords)
349  if (EvE::icontains(name, cur))
350  throw UserError ("CharNameInvalidBannedWord");
351  for (const auto cur : badChars)
352  if (EvE::icontains(name, cur))
353  throw UserError ("CharNameInvalidSomeChar");
354 
355  // check for multiple spaces
356  int found = name.find(" ");
357  if (found != name.npos) {
358  found = name.find(" ", found + 1, 1);
359  if (found != name.npos)
360  throw UserError ("CharNameInvalidMaxSpaces");
361  }
362 
363  std::string eName;
364  sDatabase.DoEscapeString(eName, name.c_str());
365  DBQueryResult res;
366  sDatabase.RunQuery(res, "SELECT characterID FROM chrCharacters WHERE characterName LIKE '%s' ", eName.c_str() );
367  if (res.GetRowCount() > 0) // name exists
368  throw UserError ("CharNameInvalidTaken");
369 
370  /* if we got here, the name is good */
371 }
372 
373 void CharacterDB::AddEmployment(uint32 charID, uint32 corpID, uint32 oldCorpID/*0*/) {
374  // Add new employment history record and update character's corp and start date -allan 25Mar14
375  DBerror err;
376  if (!sDatabase.RunQuery(err,
377  "INSERT INTO chrEmployment"
378  " (characterID, corporationID, startDate, deleted)"
379  " VALUES (%u, %u, %f, 0)", charID, corpID, GetFileTimeNow()))
380  {
381  codelog(DATABASE__ERROR, "Error in employment insert query: %s", err.c_str());
382  }
383 
384  if (!sDatabase.RunQuery(err, "UPDATE chrCharacters SET startDateTime = %f, corporationID = %u WHERE characterID = %u", GetFileTimeNow(), corpID, charID))
385  codelog(DATABASE__ERROR, "Error in character insert query: %s", err.c_str());
386 
387  // Decrease previous corp's member count
388  if (IsCorp(oldCorpID))
389  if (!sDatabase.RunQuery(err, "UPDATE crpCorporation SET memberCount = memberCount-1 WHERE corporationID = %u", oldCorpID))
390  codelog(CORP__DB_ERROR, "Error in prev corp member decrease query: %s", err.c_str());
391 
392  // Increase new corp's member number...
393  if (!sDatabase.RunQuery(err, "UPDATE crpCorporation SET memberCount = memberCount+1 WHERE corporationID = %u", corpID))
394  codelog(CORP__DB_ERROR, "Error in new corp member increase query: %s", err.c_str());
395 }
396 
398  // this shows char on select screen....fixed/updated -allan 20Jan15
399  std::string shipName = "My Ship";
400  uint32 shipTypeID = 606; //arbitrary default.
401 
402  DBQueryResult res;
403  if (!sDatabase.RunQuery(res, "SELECT itemName, typeID FROM entity WHERE itemID = (SELECT shipID FROM chrCharacters WHERE characterID = %u)", characterID)) {
404  _log(CHARACTER__WARNING, "Unable to get current ship: %s", res.error.c_str());
405  } else {
406  DBResultRow row;
408  // this causes blanks on char sel screen if there is no ship, or shipID is wrong.
409  if (!res.GetRow(row))
410  return PyStatic.NewNone();
411 
412  sDatabase.DoEscapeString(shipName, row.GetText(0));
413  shipTypeID = row.GetUInt(1);
414  }
415 
417  // these show on char portrait at top left on sel screen
418  uint32 unreadMailCount = 0;
419  uint32 upcomingEventCount = 0;
420  uint32 unprocessedNotifications = 0;
421 
422  //res.Reset();
423  if (!sDatabase.RunQuery(res,
424  "SELECT " // fixed DB query per client code -allan 18Jan15
425  " %u AS unreadMailCount,"
426  " %u AS upcomingEventCount, "
427  " %u AS unprocessedNotifications, "
428  " characterID,"
429  " petitionMessage, "
430  " gender, "
431  " bloodlineID, "
432  " createDateTime, " //this is char create date
433  " startDateTime, " //this is char joined corp date
434  " corporationID, "
435  " 0 AS worldSpaceID, " /* this gives "walking around in [station xxxx]" msgs on login screen when !=0 */
436  " stationID, "
437  " solarSystemID, "
438  " constellationID, "
439  " regionID, "
440  " 0 AS allianceID, "
441  " 0 AS allianceMemberStartDate,"
442  " 'none' AS shortName, "
443  " bounty, "
444  " skillQueueEndTime, "
445  " skillPoints, "
446  " %u AS shipTypeID, "
447  " '%s' AS shipName, "
448  " securityRating, "
449  " title, "
450  " balance, "
451  " aurBalance, "
452  " 15 AS daysLeft, " /* this calls a subscription renewal warning on char select screen (see pic in gallery) when <= 10 */
453  " 30 AS userType," /* 23 is trial acct. 30 is normal */
454  " paperDollState" // used for re-customization. see paperDollState:: in packet_types.h
455  " FROM chrCharacters"
456  " WHERE characterID=%u",
457  unreadMailCount, upcomingEventCount, unprocessedNotifications,
458  shipTypeID, shipName.c_str(), characterID))
459  {
460  codelog(DATABASE__ERROR, "Error in query: %s", res.error.c_str());
461  return nullptr;
462  }
463  return DBResultToCRowset(res);
464 }
465 
467  if (IsAgent(characterID)) {
468  sLog.Error("CharacterDB::GetCharPublicInfo()", "Character %u is NPC.", characterID);
469  return nullptr;
470  }
471  DBQueryResult res;
472 
473  if (!sDatabase.RunQuery(res,
474  "SELECT " // fixed DB Query -allan 11Jan14 -update 20April16
475  " ch.typeID,"
476  " ch.characterName,"
477  " ch.corporationID,"
478  " ch.raceID,"
479  " ch.bloodlineID,"
480  " ch.ancestryID,"
481  " ch.careerID,"
482  " ch.schoolID,"
483  " cs.schoolNameID, "
484  " ch.careerSpecialityID,"
485  " ch.age,"
486  " ch.createDateTime,"
487  " ch.gender,"
488  " ch.characterID,"
489  " ch.description,"
490  " ch.startDateTime"
491  " FROM chrCharacters AS ch"
492  " LEFT JOIN chrSchools AS cs USING (schoolID) "
493  " WHERE ch.characterID=%u", characterID))
494  {
495  codelog(DATABASE__ERROR, "Error in query: %s", res.error.c_str());
496  return nullptr;
497  }
498 
499  DBResultRow row;
500  if (!res.GetRow(row)) {
501  codelog(DATABASE__ERROR, "Error in GetCharPublicInfo query: no data for char %d", characterID);
502  return nullptr;
503  }
504 
505  return(DBRowToKeyVal(row));
506 }
507 
508 void CharacterDB::GetCharacterData(uint32 charID, std::map<std::string, int64> &characterDataMap) {
509 
510  DBQueryResult res;
511  DBResultRow row;
512 
513  if (!sDatabase.RunQuery(res,
514  "SELECT " // fixed DB Query -allan 11Jan14 UD: 04Dec17
515  " ch.corporationID, "
516  " ch.stationID, "
517  " ch.solarSystemID, "
518  " ch.constellationID, "
519  " ch.regionID, "
520  " co.stationID, " //5
521  " ch.corpRole, "
522  " ch.corpAccountKey, "
523  " ch.rolesAtAll, "
524  " ch.rolesAtBase, "
525  " ch.rolesAtHQ, " //10
526  " ch.rolesAtOther, "
527  " ch.shipID, "
528  " ch.gender, "
529  " ch.bloodlineID, "
530  " ch.raceID, " //15
531  " ch.locationID, "
532  " ch.baseID,"
533  " co.allianceID,"
534  " co.warFactionID,"
535  " ch.characterName" //20
536  " FROM chrCharacters AS ch"
537  " LEFT JOIN crpCorporation AS co USING (corporationID) "
538  " WHERE characterID = %u", charID))
539  {
540  sLog.Error("CharacterDB::GetCharacterData()", "Failed to query HQ of character's %u corporation: %s.", charID, res.error.c_str());
541  }
542 
543  if (!res.GetRow(row))
544  {
545  sLog.Error("CharacterDB::GetCharacterData()", "No valid rows were returned by the database query.");
546  return;
547  }
548 
549  characterDataMap["corporationID"] = row.GetUInt(0);
550  characterDataMap["stationID"] = row.GetUInt(1);
551  characterDataMap["solarSystemID"] = row.GetUInt(2);
552  characterDataMap["constellationID"] = row.GetUInt(3);
553  characterDataMap["regionID"] = row.GetUInt(4);
554  characterDataMap["corporationHQ"] = row.GetUInt(5);
555  characterDataMap["corpRole"] = row.GetInt64(6);
556  characterDataMap["corpAccountKey"] = row.GetInt(7);
557  characterDataMap["rolesAtAll"] = row.GetInt64(8);
558  characterDataMap["rolesAtBase"] = row.GetInt64(9);
559  characterDataMap["rolesAtHQ"] = row.GetInt64(10);
560  characterDataMap["rolesAtOther"] = row.GetInt64(11);
561  characterDataMap["shipID"] = row.GetUInt(12);
562  characterDataMap["gender"] = row.GetInt(13);
563  characterDataMap["bloodlineID"] = row.GetUInt(14);
564  characterDataMap["raceID"] = row.GetUInt(15);
565  characterDataMap["locationID"] = row.GetUInt(16);
566  characterDataMap["baseID"] = row.GetInt(17);
567  characterDataMap["allianceID"] = row.GetInt(18);
568  characterDataMap["warFactionID"] = row.GetInt(19);
569 
570  uint32 stationID = row.GetInt(17);
571  if (!CharacterDB::GetCharHomeStation(charID, stationID)) {
572  ItemData iData( itemCloneAlpha, charID, stationID, flagClone, 1 );
573  iData.customInfo="Active: ";
574  iData.customInfo += row.GetText(20);
575  iData.customInfo += "(";
576  iData.customInfo += std::to_string(charID);
577  iData.customInfo += ") {ud}";
578  sItemFactory.SpawnItem( iData )->SaveItem();
579  }
580  characterDataMap["cloneStationID"] = stationID;
581 }
582 
584  // bounty, title, startDateTime, description, corporationID
585  DBQueryResult res;
586  if (!sDatabase.RunQuery(res,
587  "SELECT "
588  " bounty,"
589  " title,"
590  " startDateTime,"
591  " description,"
592  " corporationID"
593  " FROM chrCharacters "
594  " WHERE characterID=%u", charID))
595  {
596  codelog(DATABASE__ERROR, "Error in query: %s", res.error.c_str());
597  return nullptr;
598  }
599 
600  return DBResultToCRowset(res);
601 }
602 
604  // characterID, gender, raceID, bloodlineID, createDateTime
605  DBQueryResult res;
606  if (!sDatabase.RunQuery(res,
607  "SELECT"
608  " gender,"
609  " createDateTime,"
610  " raceID,"
611  " bloodlineID"
612  " FROM chrCharacters "
613  " WHERE characterID=%u", charID))
614  {
615  codelog(DATABASE__ERROR, "Error in query: %s", res.error.c_str());
616  return nullptr;
617  }
618 
619  DBResultRow row;
620  if (!res.GetRow(row))
621  return nullptr;
622  return DBRowToPackedRow(row);
623 }
624 
626  //corpID, allianceID, title
627  DBQueryResult res;
628  if (!sDatabase.RunQuery(res,
629  "SELECT "
630  " ch.corporationID AS corpID,"
631  " co.allianceID,"
632  " ch.title"
633  " FROM chrCharacters AS ch"
634  " LEFT JOIN crpCorporation AS co USING (corporationID)"
635  " WHERE characterID=%u", characterID))
636  {
637  codelog(DATABASE__ERROR, "Error in query: %s", res.error.c_str());
638  return nullptr;
639  }
640 
641  DBResultRow row;
642  if (!res.GetRow(row)) {
643  codelog(DATABASE__ERROR, "Expected at least one row when getting character corp info\n");
644  return nullptr;
645  }
646 
647  return DBRowToKeyVal(row);
648 }
649 
650 std::string CharacterDB::GetCharName(uint32 characterID)
651 {
652  DBQueryResult res;
653  if (!sDatabase.RunQuery(res, "SELECT characterName FROM chrCharacters WHERE characterID=%u", characterID)) {
654  codelog(DATABASE__ERROR, "Error in query: %s", res.error.c_str());
655  return "";
656  }
657 
658  DBResultRow row;
659  if (!res.GetRow(row)) {
660  _log(DATABASE__MESSAGE, "Name not found for CharacterID %u.", characterID);
661  return "";
662  }
663 
664  return row.GetText(0);
665 
666 }
667 
668 PyRep* CharacterDB::GetContacts(uint32 charID, bool blocked)
669 {
670  DBQueryResult res;
671  if (!sDatabase.RunQuery( res,
672  "SELECT contactID, inWatchlist, relationshipID, labelMask"
673  " FROM chrContacts WHERE ownerID = %u and blocked = %u", charID, blocked))
674  {
675  codelog(CORP__DB_ERROR, "Error in query: %s", res.error.c_str());
676  return nullptr;
677  }
678 
679  return DBResultToIndexRowset(res, "contactID");
680 }
681 
682 void CharacterDB::AddContact(uint32 ownerID, uint32 charID, int32 standing, bool inWatchlist)
683 {
684  DBerror err;
685  sDatabase.RunQuery(err,
686  "INSERT INTO chrContacts (ownerID, contactID, relationshipID, "
687  " inWatchlist, labelMask, blocked) VALUES "
688  " (%u, %u, %i, %i, 0, 0) ",
689  ownerID, charID, standing, inWatchlist);
690 }
691 
693 {
694  DBerror err;
695  sDatabase.RunQuery(err,
696  "UPDATE chrContacts SET relationshipID=%i "
697  " WHERE contactID=%u AND ownerID=%u ",
698  standing, charID, ownerID);
699 }
700 
702 {
703  DBerror err;
704  sDatabase.RunQuery(err,
705  "UPDATE chrContacts SET blocked=%u "
706  " WHERE contactID=%u AND ownerID=%u ",
707  blocked, charID, ownerID);
708 }
709 
711 {
712  DBerror err;
713  sDatabase.RunQuery(err,
714  "DELETE from chrContacts "
715  " WHERE contactID=%u AND ownerID=%u ",
716  charID, ownerID);
717 }
718 
719 //just return all itemIDs which has ownerID set to characterID
720 bool CharacterDB::GetCharItems(uint32 characterID, std::vector<uint32> &into) {
721  DBQueryResult res;
722 
723  if (!sDatabase.RunQuery(res,
724  "SELECT"
725  " itemID"
726  " FROM entity"
727  " WHERE ownerID = %u",
728  characterID))
729  {
730  _log(DATABASE__ERROR, "Failed to query items of char %u: %s.", characterID, res.error.c_str());
731  return false;
732  }
733 
734  DBResultRow row;
735  while(res.GetRow(row))
736  into.push_back(row.GetUInt(0));
737 
738  return true;
739 }
740 
742 { // this picks first ship that db finds belonging to charID in locationID
743  DBQueryResult res;
744  sDatabase.RunQuery(res,
745  "SELECT e.itemID"
746  " FROM entity AS e"
747  " LEFT JOIN invTypes USING (typeID)"
748  " LEFT JOIN invGroups USING (groupID)"
749  " WHERE e.ownerID = %u"
750  " AND locationID = %u"
751  " AND categoryID = %u"
752  " LIMIT 1", charID, locationID, EVEDB::invCategories::Ship);
753 
754  DBResultRow row;
755  if (res.GetRow(row)) {
756  return row.GetUInt(0);
757  } else {
758  return 0;
759  }
760 }
761 
763 {
764  DBerror err;
765  if (!sDatabase.RunQuery(err, "UPDATE chrCharacters SET shipID = %u WHERE characterID = %u", shipID, charID))
766  _log(DATABASE__ERROR, "Failed to save ship %u for character %u: %s.", shipID, charID, err.c_str());
767 }
768 
770 {
771  DBerror err;
772  if (!sDatabase.RunQuery(err, "UPDATE chrCharacters SET capsuleID = %u WHERE characterID = %u", podID, charID))
773  _log(DATABASE__ERROR, "Failed to save pod %u for character %u: %s.", podID, charID, err.c_str());
774 }
775 
776 //returns a list of the itemID for all the clones belonging to the character
777 bool CharacterDB::GetCharClones(uint32 characterID, std::vector<uint32> &into) {
778  DBQueryResult res;
779  if (!sDatabase.RunQuery(res, "SELECT itemID FROM entity WHERE ownerID = %u AND flag='400'", characterID)) {
780  _log(DATABASE__ERROR, "Failed to query clones of char %u: %s.", characterID, res.error.c_str());
781  return false;
782  }
783 
784  DBResultRow row;
785  while(res.GetRow(row))
786  into.push_back(row.GetUInt(0));
787 
788  return true;
789 }
790 
791 //returns the itemID of the active clone
793  DBQueryResult res;
794 
795  if (!sDatabase.RunQuery(res,
796  "SELECT itemID"
797  " FROM entity"
798  " WHERE ownerID = %u"
799  " AND flag=400",
800  characterID))
801  {
802  _log(DATABASE__ERROR, "Failed to query active clone of char %u: %s.", characterID, res.error.c_str());
803  return false;
804  }
805 
806  DBResultRow row;
807  if (res.GetRow(row)) {
808  itemID=row.GetUInt(0);
809  } else {
810  return false;
811  }
812  return true;
813 }
814 
815 //we use this function because, when we change the clone type,
816 //the cached item type doesn't change, so we need to read it
817 //directly from the db
819  DBQueryResult res;
820 
821  if (!sDatabase.RunQuery(res,
822  "SELECT typeID"
823  " FROM entity"
824  " WHERE ownerID = %u"
825  " AND flag=400",
826  characterID))
827  {
828  _log(DATABASE__ERROR, "Failed to query active clone of char %u: %s.", characterID, res.error.c_str());
829  return false;
830  }
831 
832  DBResultRow row;
833  if (res.GetRow(row)) {
834  typeID=row.GetUInt(0);
835  return true;
836  }
837 
838  typeID = 0;
839  return false;
840 }
841 
842 // Return the Home station of the char based on the active clone
843 bool CharacterDB::GetCharHomeStation(uint32 characterID, uint32 &stationID) {
844  DBQueryResult res;
845  if ( !sDatabase.RunQuery(res,
846  "SELECT locationID "
847  " FROM entity"
848  " WHERE ownerID = %u"
849  " AND flag=400",
850  characterID ))
851  {
852  _log(CHARACTER__ERROR, "Could't get clone location for char %u", characterID );
853  return false;
854  }
855 
856  DBResultRow row;
857  if (res.GetRow(row))
858  stationID = row.GetUInt(0);
859  return true;
860 }
861 
862 //replace all the typeID of the character's clones
864 {
865  DBQueryResult res;
866 
867  if (!sDatabase.RunQuery(res,
868  "SELECT "
869  " typeName "
870  "FROM invTypes "
871  "WHERE typeID = %u",
872  typeID))
873  {
874  _log(DATABASE__ERROR, "Failed to change clone type of char %u: %s.", characterID, res.error.c_str());
875  return false;
876  }
877 
878  DBResultRow row;
879  if (!res.GetRow(row))
880  {
881  sLog.Error( "CharacterDB::ChangeCloneType()", "Could not find Clone typeID = %u in invTypes table.", typeID );
882  return false;
883  }
884  std::string typeNameString = row.GetText(0);
885 
886  if (!sDatabase.RunQuery(res.error,
887  "UPDATE "
888  "entity "
889  "SET typeID=%u, itemName='%s' "
890  "WHERE ownerID=%u "
891  "AND flag=400",
892  typeID,
893  typeNameString.c_str(),
894  characterID))
895  {
896  _log(DATABASE__ERROR, "Failed to change clone type of char %u: %s.", characterID, res.error.c_str());
897  return false;
898  }
899  sLog.Debug( "CharacterDB", "Clone upgrade successful" );
900  return true;
901 }
902 
904 {
905  DBQueryResult res;
906  if (!sDatabase.RunQuery(res.error, "UPDATE entity SET locationID=%u WHERE ownerID=%u AND flag=400", locationID, characterID)) {
907  _log(DATABASE__ERROR, "Failed to change location of clone %u: %s.", characterID, res.error.c_str());
908  return false;
909  }
910 
911  return true;
912 }
913 
914 bool CharacterDB::GetAttributesFromAncestry(uint32 ancestryID, uint8 &intelligence, uint8 &charisma, uint8 &perception, uint8 &memory, uint8 &willpower) {
915  DBQueryResult res;
916 
917  if (!sDatabase.RunQuery(res,
918  " SELECT "
919  " intelligence, charisma, perception, memory, willpower "
920  " FROM chrAncestries "
921  " WHERE ancestryID = %u ", ancestryID))
922  {
923  codelog(DATABASE__ERROR, "Error in query: %s", res.error.c_str());
924  return (false);
925  }
926 
927  DBResultRow row;
928  if (!res.GetRow(row)) {
929  codelog(DATABASE__ERROR, "Failed to find ancestry information for ancestry %u", ancestryID);
930  return false;
931  }
932 
933  intelligence += row.GetUInt(0);
934  charisma += row.GetUInt(1);
935  perception += row.GetUInt(2);
936  memory += row.GetUInt(3);
937  willpower += row.GetUInt(4);
938 
939  return (true);
940 }
941 
942 bool CharacterDB::GetCareerBySchool(uint32 schoolID, uint8 &raceID, uint32 &careerID) {
943  DBQueryResult res;
944  if (!sDatabase.RunQuery(res,
945  "SELECT raceID, careerID FROM careers WHERE schoolID = %u", schoolID)) {
946  codelog(DATABASE__ERROR, "Error in query: %s", res.error.c_str());
947  return false;
948  }
949 
950  DBResultRow row;
951  if (!res.GetRow(row)) {
952  codelog(DATABASE__ERROR, "Failed to find matching career for school %u", schoolID);
953  return false;
954  }
955  raceID = row.GetInt(0);
956  careerID = row.GetInt(1);
957  return true;
958 }
959 
960 bool CharacterDB::GetCorporationBySchool(uint32 schoolID, uint32 &corporationID) {
961  DBQueryResult res;
962 
963  if (!sDatabase.RunQuery(res, "SELECT corporationID FROM chrSchools WHERE schoolID = %u", schoolID)) {
964  codelog(DATABASE__ERROR, "Error in query: %S", res.error.c_str());
965  return false;
966  }
967 
968  DBResultRow row;
969  if (!res.GetRow(row)) {
970  codelog(DATABASE__ERROR, "Failed to find matching corporation for school %u", schoolID);
971  return false;
972  }
973  corporationID = row.GetInt(0);
974  return true;
975 }
976 
981  DBQueryResult res;
982  if (!sDatabase.RunQuery(res,
983  "SELECT " // fixed DB Query -allan 01/02/14 -UD 9Jul19
984  " cs.corporationID, "
985  " cs.schoolID, "
986  " co.stationID, "
987  " st.solarSystemID, "
988  " st.constellationID, "
989  " st.regionID "
990  " FROM careers AS c"
991  " LEFT JOIN chrSchools AS cs USING (schoolID)"
992  " LEFT JOIN crpCorporation AS co ON cs.corporationID = co.corporationID"
993  " LEFT JOIN staStations AS st USING (stationID)"
994  " WHERE c.careerID = %u", cdata.careerID))
995  {
996  codelog(DATABASE__ERROR, "Error in query: %s", res.error.c_str());
997  return false;
998  }
999 
1000  DBResultRow row;
1001  if (!res.GetRow(row)) {
1002  codelog(DATABASE__ERROR, "Failed to find career %u", cdata.careerID);
1003  return false;
1004  }
1005 
1006  corporationID = row.GetUInt(0);
1007  cdata.schoolID = row.GetUInt(1);
1008  cdata.stationID = row.GetUInt(2);
1009  cdata.solarSystemID = row.GetUInt(3);
1010  cdata.constellationID = row.GetUInt(4);
1011  cdata.regionID = row.GetUInt(5);
1012 
1013  return true;
1014 }
1015 
1017 {
1018  DBQueryResult res;
1019  if (!sDatabase.RunQuery(res,
1020  "SELECT "
1021  " co.stationID"
1022  " FROM careers AS c"
1023  " LEFT JOIN chrSchools AS cs USING (schoolID)"
1024  " LEFT JOIN crpCorporation AS co ON cs.corporationID = co.corporationID"
1025  " WHERE c.careerID = %u", careerID))
1026  {
1027  codelog(DATABASE__ERROR, "Error in query: %s", res.error.c_str());
1028  return 0;
1029  }
1030 
1031  DBResultRow row;
1032  if (!res.GetRow(row)) {
1033  codelog(DATABASE__ERROR, "Failed to find station for career %u", careerID);
1034  return 0;
1035  }
1036 
1037  return row.GetUInt(0);
1038 }
1039 
1041  DBQueryResult res;
1042  if (!sDatabase.RunQuery(res,
1043  "SELECT "
1044  " corporationID"
1045  " FROM crpCorporation"
1046  " WHERE corporationID = %u", corpID))
1047  {
1048  codelog(DATABASE__ERROR, "Error in query: %s", res.error.c_str());
1049  return false;
1050  }
1051 
1052  return (res.GetRowCount() != 0);
1053 }
1054 
1055 void CharacterDB::SetAvatar(uint32 charID, PyRep* hairDarkness) {
1056  //populate the DB with avatar information
1057  DBerror err;
1058  if (!sDatabase.RunQuery(err,
1059  "INSERT INTO avatars (charID, hairDarkness)"
1060  " VALUES (%u, %f)",
1061  charID, hairDarkness->AsFloat()->value()))
1062  {
1063  codelog(DATABASE__ERROR, "Error in query: %s", err.c_str());
1064  }
1065 }
1066 
1067 void CharacterDB::SetAvatarColors(uint32 charID, uint32 colorID, uint32 colorNameA, uint32 colorNameBC, double weight, double gloss) {
1068  //add avatar colors to the DB
1069  DBerror err;
1070  if (!sDatabase.RunQuery(err,
1071  "INSERT INTO avatar_colors (charID, colorID, colorNameA, colorNameBC, weight, gloss)"
1072  " VALUES (%u, %u, %u, %u, %f, %f)",
1073  charID, colorID, colorNameA, colorNameBC, weight, gloss))
1074  {
1075  codelog(DATABASE__ERROR, "Error in query: %s", err.c_str());
1076  }
1077 }
1078 
1079 void CharacterDB::SetAvatarModifiers(uint32 charID, PyRep* modifierLocationID, PyRep* paperdollResourceID, PyRep* paperdollResourceVariation) {
1080  //add avatar modifiers to the DB
1081  DBerror err;
1082  if (!sDatabase.RunQuery(err,
1083  "INSERT INTO avatar_modifiers (charID, modifierLocationID, paperdollResourceID, paperdollResourceVariation)"
1084  " VALUES (%u, %u, %u, %u)",
1085  charID,
1086  modifierLocationID->AsInt()->value(),
1087  paperdollResourceID->AsInt()->value(),
1088  paperdollResourceVariation->IsInt() ? paperdollResourceVariation->AsInt()->value() : 0 ))
1089  {
1090  codelog(DATABASE__ERROR, "Error in query: %s", err.c_str());
1091  }
1092 }
1093 
1094 void CharacterDB::SetAvatarSculpts(uint32 charID, PyRep* sculptLocationID, PyRep* weightUpDown, PyRep* weightLeftRight, PyRep* weightForwardBack) {
1095  //add avatar sculpts to the DB
1096  DBerror err;
1097  if (!sDatabase.RunQuery(err,
1098  "INSERT INTO avatar_sculpts (charID, sculptLocationID, weightUpDown, weightLeftRight, weightForwardBack)"
1099  " VALUES (%u, %u, %f, %f, %f)",
1100  charID,
1101  sculptLocationID->AsInt()->value(),
1102  weightUpDown->IsFloat() ? weightUpDown->AsFloat()->value() : 0.0,
1103  weightLeftRight->IsFloat() ? weightLeftRight->AsFloat()->value() : 0.0,
1104  weightForwardBack->IsFloat() ? weightForwardBack->AsFloat()->value() : 0.0))
1105  {
1106  codelog(DATABASE__ERROR, "Error in query: %s", err.c_str());
1107  }
1108 }
1109 
1111 {
1112  DBerror err;
1113  if (!sDatabase.RunQuery(err,
1114  "INSERT INTO chrPortraitData "
1115  " (charID, backgroundID, lightID, lightColorID, cameraX, cameraY, cameraZ, cameraPoiX, cameraPoiY, cameraPoiZ,"
1116  " headLookTargetX, headLookTargetY, headLookTargetZ, lightIntensity, headTilt, orientChar, browLeftCurl, browLeftTighten,"
1117  " browLeftUpDown, browRightCurl, browRightTighten, browRightUpDown, eyeClose, eyesLookVertical, eyesLookHorizontal,"
1118  " squintLeft, squintRight, jawSideways, jawUp, puckerLips, frownLeft, frownRight, smileLeft, smileRight, "
1119  " cameraFieldOfView, portraitPoseNumber) VALUES"
1120  " (%u,%u,%u,%u,%f,%f,%f,%f,%f,%f,"
1121  " %f,%f,%f,%f,%f,%f,%f,%f,"
1122  " %f,%f,%f,%f,%f,%f,%f,"
1123  " %f,%f,%f,%f,%f,%f,%f,%f,%f,"
1124  " %f,%f)",
1125  charID, data.backgroundID, data.lightID, data.lightColorID, data.cameraX, data.cameraY, data.cameraZ, data.cameraPoiX, data.cameraPoiY, data.cameraPoiZ,
1128  data.squintLeft, data.squintRight, data.jawSideways, data.jawUp, data.puckerLips, data.frownLeft, data.frownRight, data.smileLeft, data.smileRight,
1130  {
1131  codelog(DATABASE__ERROR, "Error in query: %s", err.c_str());
1132  }
1133 }
1134 
1135 bool CharacterDB::GetBaseSkills(std::map<uint32, uint8> &into) {
1136  DBQueryResult res;
1137  if (!sDatabase.RunQuery(res, "SELECT skillTypeID, level FROM sklBaseSkills")) {
1138  codelog(DATABASE__ERROR, "Error in query: %s", res.error.c_str());
1139  return false;
1140  }
1141 
1142  DBResultRow row;
1143  while (res.GetRow(row))
1144  into[row.GetUInt(0)] = row.GetUInt(1);
1145 
1146  return true;
1147 }
1148 
1149 bool CharacterDB::GetSkillsByRace(uint32 raceID, std::map<uint32, uint8> &into) {
1150  DBQueryResult res;
1151  if (!sDatabase.RunQuery(res, "SELECT skillTypeID, level FROM sklRaceSkills WHERE raceID = %u ", raceID)) {
1152  codelog(DATABASE__ERROR, "Error in query: %s", res.error.c_str());
1153  return false;
1154  }
1155 
1156  DBResultRow row;
1157  while (res.GetRow(row)) {
1158  if (into.find(row.GetUInt(0)) == into.end()) {
1159  into[row.GetUInt(0)] = row.GetUInt(1);
1160  } else {
1161  into[row.GetUInt(0)] += row.GetUInt(1);
1162  }
1163  //check to avoid more than 5 levels of a skill
1164  if (into[row.GetUInt(0)] > 5)
1165  into[row.GetUInt(0)] = 5;
1166  }
1167 
1168  return true;
1169 }
1170 
1171 bool CharacterDB::GetSkillsByCareer(uint32 careerID, std::map<uint32, uint8> &into) {
1172  DBQueryResult res;
1173  if (!sDatabase.RunQuery(res,
1174  "SELECT "
1175  " skillTypeID, level"
1176  " FROM sklCareerSkills"
1177  " WHERE careerID = %u", careerID))
1178  {
1179  codelog(DATABASE__ERROR, "Error in query: %s", res.error.c_str());
1180  return false;
1181  }
1182 
1183  DBResultRow row;
1184  while (res.GetRow(row)) {
1185  if (into.find(row.GetUInt(0)) == into.end()) {
1186  into[row.GetUInt(0)] = row.GetUInt(1);
1187  } else {
1188  into[row.GetUInt(0)] += row.GetUInt(1);
1189  }
1190  //check to avoid more than 5 levels of a skill
1191  if (into[row.GetUInt(0)] > 5)
1192  into[row.GetUInt(0)] = 5;
1193  }
1194 
1195  return true;
1196 }
1197 
1199  DBQueryResult res;
1200  if (!sDatabase.RunQuery(res, "SELECT note FROM chrNotes WHERE ownerID = %u AND itemID = %u", ownerID, itemID)) {
1201  codelog(DATABASE__ERROR, "Error on query: %s", res.error.c_str());
1202  return nullptr;
1203  }
1204  DBResultRow row;
1205  if (!res.GetRow(row))
1206  return nullptr;
1207 
1208  return (new PyString(row.GetText(0)));
1209 }
1210 
1212  DBerror err;
1213  if (str[0] == '\0') {
1214  // str is empty
1215  if (!sDatabase.RunQuery(err,
1216  "DELETE FROM chrNotes "
1217  " WHERE itemID = %u AND ownerID = %u LIMIT 1",
1218  itemID, ownerID)
1219  )
1220  {
1221  codelog(DATABASE__ERROR, "Error on query: %s", err.c_str());
1222  return false;
1223  }
1224  } else {
1225  // escape it before insertion
1226  std::string escaped;
1227  sDatabase.DoEscapeString(escaped, str);
1228 
1229  if (!sDatabase.RunQuery(err,
1230  "REPLACE INTO chrNotes ( ownerID, itemID, note)"
1231  " VALUES (%u, %u, '%s')",
1232  ownerID, itemID, escaped.c_str())
1233  )
1234  {
1235  codelog(DATABASE__ERROR, "Error on query: %s", err.c_str());
1236  return false;
1237  }
1238  }
1239 
1240  return true;
1241 }
1242 
1243 uint32 CharacterDB::AddOwnerNote(uint32 charID, const std::string & label, const std::string & content) {
1244  DBerror err;
1245  uint32 id;
1246  std::string lblS;
1247  sDatabase.DoEscapeString(lblS, label);
1248 
1249  std::string contS;
1250  sDatabase.DoEscapeString(contS, content);
1251 
1252  if (!sDatabase.RunQueryLID(err, id,
1253  "INSERT INTO chrOwnerNote (ownerID, label, note) VALUES (%u, '%s', '%s');",
1254  charID, lblS.c_str(), contS.c_str()))
1255  {
1256  codelog(DATABASE__ERROR, "Error on query: %s", err.c_str());
1257  return 0;
1258  }
1259 
1260  return id;
1261 }
1262 
1263 bool CharacterDB::EditOwnerNote(uint32 charID, uint32 noteID, const std::string & label, const std::string & content) {
1264  DBerror err;
1265  std::string contS;
1266  sDatabase.DoEscapeString(contS, content);
1267 
1268  if (!sDatabase.RunQuery(err,
1269  "UPDATE chrOwnerNote SET note = '%s' WHERE ownerID = %u AND noteID = %u;",
1270  contS.c_str(), charID, noteID))
1271  {
1272  codelog(DATABASE__ERROR, "Error on query: %s", err.c_str());
1273  return false;
1274  }
1275 
1276  return true;
1277 }
1278 
1280  DBQueryResult res;
1281  if (!sDatabase.RunQuery(res, "SELECT noteID, label FROM chrOwnerNote WHERE ownerID = %u", charID))
1282  {
1283  codelog(DATABASE__ERROR, "Error on query: %s", res.error.c_str());
1284  return nullptr;
1285  }
1286 
1287  return DBResultToCRowset(res);
1288 }
1289 
1291  /*
1292  [PyTuple 6 items]
1293  [PyTuple 2 items]
1294  [PyString "noteDate"]
1295  [PyInt 64]
1296  [PyTuple 2 items]
1297  [PyString "typeID"]
1298  [PyInt 2]
1299  [PyTuple 2 items]
1300  [PyString "referenceID"]
1301  [PyInt 3]
1302  [PyTuple 2 items]
1303  [PyString "note"]
1304  [PyInt 130]
1305  [PyTuple 2 items]
1306  [PyString "userID"]
1307  [PyInt 3]
1308  [PyTuple 2 items]
1309  [PyString "label"]
1310  [PyInt 130]
1311  [PyPackedRow 19 bytes]
1312  ["noteDate" => <129041092800000000> [FileTime]]
1313  ["typeID" => <1> [I2]]
1314  ["referenceID" => <1661059544> [I4]]
1315  ["note" => <1::F::0::Main|> [WStr]]
1316  ["userID" => <0> [I4]]
1317  ["label" => <S:Folders> [WStr]]
1318  */
1319  DBQueryResult res;
1320 
1321  if (!sDatabase.RunQuery(res, "SELECT note FROM chrOwnerNote WHERE ownerID = %u AND noteID = %u", charID, noteID))
1322  {
1323  codelog(DATABASE__ERROR, "Error on query: %s", res.error.c_str());
1324  return nullptr;
1325  }
1326 
1327  return DBResultToCRowset(res);
1328 }
1329 
1330 void CharacterDB::EditLabel(uint32 charID, uint32 labelID, uint32 color, std::string name)
1331 {
1332  std::string eName;
1333  sDatabase.DoEscapeString(eName, name);
1334 
1335  DBQueryResult res;
1336  sDatabase.RunQuery(res, "UPDATE chrLabels SET color = %u, name = '%s' WHERE ownerID = %u AND labelID = %u", color, eName.c_str(), charID, labelID);
1337 }
1338 
1340 {
1341  DBQueryResult res;
1342  if (!sDatabase.RunQuery(res, "SELECT labelID, color, name FROM chrLabels WHERE ownerID = %u", charID)) {
1343  codelog(DATABASE__ERROR, "Error on query: %s", res.error.c_str());
1344  return nullptr;
1345  }
1346 
1347  return DBResultToCIndexedRowset(res, "labelID");
1348 }
1349 
1350 void CharacterDB::SetLabel(uint32 charID, uint32 color, std::string name)
1351 {
1352  std::string eName;
1353  sDatabase.DoEscapeString(eName, name);
1354 
1355  DBQueryResult res;
1356  sDatabase.RunQuery(res, "INSERT INTO chrLabels (color, name, ownerID) VALUES (%u, '%s', %u)", color, eName.c_str(), charID);
1357 }
1358 
1360 {
1361  DBerror err;
1362  sDatabase.RunQuery(err,"DELETE FROM chrLabels WHERE ownerID = %u AND labelID = %u", charID, labelID);
1363 }
1364 
1366  DBQueryResult res;
1367  if (!sDatabase.RunQuery( res, "SELECT typeID, level, startTime, endTime FROM chrSkillQueue WHERE characterID = %u ORDER BY orderIndex ASC", characterID)) {
1368  _log(DATABASE__ERROR, "Failed to query skill queue of character %u: %s.", characterID, res.error.c_str());
1369  return false;
1370  }
1371 
1372  DBResultRow row;
1373  while (res.GetRow(row)) {
1374  QueuedSkill qs = QueuedSkill();
1375  qs.typeID = row.GetUInt(0);
1376  qs.level = row.GetUInt(1);
1377  qs.startTime = row.GetInt64(2);
1378  qs.endTime = row.GetInt64(3);
1379  into.push_back( qs );
1380  }
1381 
1382  return true;
1383 }
1384 
1386  DBQueryResult res;
1387  if (!sDatabase.RunQuery( res, "SELECT typeID, level FROM chrPausedSkillQueue WHERE characterID = %u ORDER BY orderIndex ASC", characterID)) {
1388  _log(DATABASE__ERROR, "Failed to query paused skill queue of character %u: %s.", characterID, res.error.c_str());
1389  return false;
1390  }
1391 
1392  DBResultRow row;
1393  while (res.GetRow(row)) {
1394  QueuedSkill qs = QueuedSkill();
1395  qs.typeID = row.GetUInt( 0 );
1396  qs.level = row.GetUInt( 1 );
1397  into.push_back( qs );
1398  }
1399 
1400  // delete paused queue, as subsequent presses of 'apply' button will add paused queue again, and again, etc...
1401  DBerror err;
1402  if (!sDatabase.RunQuery(err,"DELETE FROM chrPausedSkillQueue WHERE characterID = %u", characterID)) {
1403  _log(DATABASE__ERROR, "Failed to delete skill queue of character %u: %s.", characterID, err.c_str());
1404  return false;
1405  }
1406 
1407  return true;
1408 }
1409 
1411  DBerror err;
1412  if (!sDatabase.RunQuery(err, "DELETE FROM chrSkillQueue WHERE characterID = %u", characterID)) {
1413  _log(DATABASE__ERROR, "Failed to delete skill queue of character %u: %s.", characterID, err.c_str());
1414  return false;
1415  }
1416 
1417  if (data.empty())
1418  return true;
1419 
1420  std::string query;
1421 
1422  for (uint8 i = 0; i < data.size(); i++) {
1423  const QueuedSkill &qs = data[ i ];
1424  char buf[ 80 ];
1425  snprintf( buf, sizeof(buf), "(%u, %u, %u, %u, %li, %li)", characterID, i, qs.typeID, qs.level, qs.startTime, qs.endTime );
1426 
1427  if (i > 0)
1428  query += ',';
1429  query += buf;
1430  }
1431 
1432  if ( !sDatabase.RunQuery( err,
1433  "INSERT INTO chrSkillQueue (characterID, orderIndex, typeID, level, startTime, endTime)"
1434  " VALUES %s",query.c_str()))
1435  {
1436  _log(DATABASE__ERROR, "SaveSkillQueue - unable to save data - %s", err.c_str());
1437  return false;
1438  }
1439  return true;
1440 }
1441 
1443  DBerror err;
1444  if (!sDatabase.RunQuery(err, "DELETE FROM chrPausedSkillQueue WHERE characterID = %u", characterID)) {
1445  _log(DATABASE__ERROR, "Failed to delete paused skill queue of character %u: %s.", characterID, err.c_str());
1446  return false;
1447  }
1448 
1449  if (data.empty())
1450  return true;
1451 
1452  std::string query;
1453 
1454  for (uint8 i = 0; i < data.size(); i++) {
1455  const QueuedSkill &qs = data[ i ];
1456  char buf[ 30 ];
1457  snprintf( buf, sizeof(buf), "(%u, %u, %u, %u)", characterID, i, qs.typeID, qs.level );
1458 
1459  if (i > 0)
1460  query += ',';
1461  query += buf;
1462  }
1463 
1464  if ( !sDatabase.RunQuery( err,
1465  "INSERT INTO chrPausedSkillQueue (characterID, orderIndex, typeID, level)"
1466  " VALUES %s",query.c_str()))
1467  {
1468  _log(DATABASE__ERROR, "SavePausedSkillQueue - unable to save data - %s", err.c_str());
1469  return false;
1470  }
1471 
1472  return true;
1473 }
1474 
1475 void CharacterDB::SaveSkillHistory(uint16 eventID, double logDate, uint32 characterID, uint32 skillTypeID, uint8 skillLevel, uint32 absolutePoints) {
1476  DBerror err;
1477  if ( !sDatabase.RunQuery( err,
1478  "INSERT INTO chrSkillHistory (eventTypeID, logDate, characterID, skillTypeID, skillLevel, absolutePoints)"
1479  " VALUES (%u, %f, %u, %u, %u, %u)", eventID, logDate, characterID, skillTypeID, skillLevel, absolutePoints ))
1480  _log(DATABASE__ERROR, "Failed to set chrSkillHistory for character %u: %s", characterID, err.c_str());
1481 }
1482 
1484  DBQueryResult res;
1485  if (!sDatabase.RunQuery(res,
1486  "SELECT logDate, eventTypeID, skillTypeID, absolutePoints"
1487  " FROM chrSkillHistory"
1488  " WHERE characterID = %u"
1489  " ORDER BY logDate DESC"
1490  " LIMIT 50",
1491  characterID )) {
1492  codelog(DATABASE__ERROR, "Error in query: %s", res.error.c_str());
1493  return nullptr;
1494  }
1495 
1496  return DBResultToRowset(res);
1497 }
1498 
1500  DBerror err;
1501  sDatabase.RunQuery( err, "UPDATE chrCharacters SET skillQueueEndTime = %li WHERE characterID = %u ", endtime, charID );
1502 }
1503 
1505 {
1506  DBerror err;
1507  sDatabase.RunQuery(err, "UPDATE chrCharacters SET logonDateTime = %f WHERE characterID = %u", GetFileTimeNow(), charID );
1508 }
1509 
1511 {
1512  DBerror err;
1513  sDatabase.RunQuery(err, "UPDATE chrCharacters SET logoffDateTime = %f WHERE characterID = %u", GetFileTimeNow(), charID );
1514 }
1515 
1516 void CharacterDB::addOwnerCache(uint32 ownerID, std::string ownerName, uint32 typeID) {
1517  DBerror err;
1518  sDatabase.RunQuery(err,
1519  "INSERT INTO cacheOwners(ownerID, ownerName, typeID)"
1520  " VALUES (%u, '%s', %u)",
1521  ownerID, ownerName.c_str(), typeID);
1522 }
1523 
1525  DBQueryResult res;
1526  sDatabase.RunQuery(res, "SELECT characterID, bounty FROM webBounties WHERE characterID = %u OR ownerID = %u", charID, ownerID);
1527  return DBResultToRowset(res);
1528 }
1529 
1531  DBQueryResult res;
1532  sDatabase.RunQuery(res,
1533  "SELECT c.characterID, c.bounty, c.online, o.characterName AS ownerName"
1534  " FROM webBounties AS b"
1535  " LEFT JOIN chrCharacters AS c ON c.characterID = b.characterID"
1536  " LEFT JOIN chrCharacters AS o ON o.characterID = b.ownerID"
1537  " ORDER BY c.bounty DESC"
1538  " LIMIT 10");
1539  return DBResultToRowset(res);
1540 }
1541 
1543  DBerror err;
1544  sDatabase.RunQuery(err, "UPDATE chrCharacters SET bounty = bounty + %u WHERE characterID = %u", amount, charID);
1545  sDatabase.RunQuery(err,
1546  "INSERT INTO webBounties(characterID, ownerID, bounty, timePlaced)"
1547  " VALUES (%u, %u, %u, UNIX_TIMESTAMP(CURRENT_TIMESTAMP) )",
1548  charID, ownerID, amount );
1549 }
1550 
1552  /*
1553  * def GetKillsRecentKills(self, num, startIndex):
1554  * shipKills = sm.RemoteSvc('charMgr').GetRecentShipKillsAndLosses(num, startIndex)
1555  * return [ k for k in shipKills if k.finalCharacterID == eve.session.charid ]
1556  *
1557  * def GetKillsRecentLosses(self, num, startIndex):
1558  * shipKills = sm.RemoteSvc('charMgr').GetRecentShipKillsAndLosses(num, startIndex)
1559  * return [ k for k in shipKills if k.victimCharacterID == eve.session.charid ]
1560  */
1561  DBQueryResult res;
1562  if (!sDatabase.RunQuery(res,
1563  "SELECT"
1564  " killID,"
1565  " solarSystemID,"
1566  " victimCharacterID,"
1567  " victimCorporationID,"
1568  " victimAllianceID,"
1569  " victimFactionID,"
1570  " victimShipTypeID,"
1571  " finalCharacterID,"
1572  " finalCorporationID,"
1573  " finalAllianceID,"
1574  " finalFactionID,"
1575  " finalShipTypeID,"
1576  " finalWeaponTypeID,"
1577  " killBlob,"
1578  " killTime,"
1579  " victimDamageTaken,"
1580  " finalSecurityStatus,"
1581  " finalDamageDone,"
1582  " moonID"
1583  " FROM chrKillTable"
1584  " WHERE ((victimCharacterID = %u) OR (finalCharacterID = %u))", charID, charID))
1585  /* should we limit this? */
1586  {
1587  codelog(DATABASE__ERROR, "Error on query: %s", res.error.c_str());
1588  return nullptr;
1589  }
1590 
1591  _log(DATABASE__RESULTS, "GetKillOrLoss for %u returned %u items", charID, res.GetRowCount());
1592 
1593  return DBResultToCRowset(res);
1594 }
1595 
1597 {
1598  DBerror err;
1599  sDatabase.RunQuery(err, "UPDATE chrCharacters SET corpRole = %li WHERE characterID = %u", role, charID);
1600 }
1601 
1603 {
1604  DBQueryResult res;
1605  if (!sDatabase.RunQuery(res, "SELECT corpRole FROM chrCharacters WHERE characterID = %u", charID)) {
1606  sLog.Error("CharacterDB::GetCorpRole()", "Failed to query role of character %u: %s.", charID, res.error.c_str());
1607  return 0;
1608  }
1609 
1610  DBResultRow row;
1611  if (!res.GetRow(row)) {
1612  sLog.Error("CharacterDB::GetCorpRole()", "No valid rows were returned by the database query.");
1613  return 0;
1614  }
1615 
1616  return row.GetUInt(0);
1617 }
1618 
1620 {
1621  DBQueryResult res;
1622  if (!sDatabase.RunQuery(res, "SELECT corporationID FROM chrCharacters WHERE characterID = %u", charID)) {
1623  sLog.Error("CharacterDB::GetCorpID()", "Failed to query corpID of character %u: %s.", charID, res.error.c_str());
1624  return 0;
1625  }
1626 
1627  DBResultRow row;
1628  if (!res.GetRow(row)) {
1629  sLog.Error("CharacterDB::GetCorpID()", "No valid rows were returned by the database query.");
1630  return 0;
1631  }
1632 
1633  return row.GetUInt(0);
1634 }
1635 
1637 {
1638  DBQueryResult res;
1639  if (!sDatabase.RunQuery(res,
1640  "SELECT taxRate FROM crpCorporation WHERE corporationID = (SELECT corporationID FROM chrCharacters WHERE characterID = %u)", charID))
1641  {
1642  codelog(DATABASE__ERROR, "Error in query: %s", res.error.c_str());
1643  return false;
1644  }
1645 
1646  DBResultRow row;
1647  if (!res.GetRow(row))
1648  return 0.0f;
1649 
1650  return row.GetFloat(0);
1651 }
1652 
1654 {
1655  DBQueryResult res;
1656  if (!sDatabase.RunQuery(res, "SELECT solarSystemID AS locationID, characterID FROM chrCharacters WHERE corporationID = %u", corpID)) {
1657  sLog.Error("CharacterDB::GetMyCorpMates()", "Failed to query corpMates for corpID %u: %s.", corpID, res.error.c_str());
1658  return nullptr;
1659  }
1660 
1661  return DBResultToCRowset(res);
1662 }
1663 
1664 void CharacterDB::VisitSystem(uint32 solarSystemID, uint32 charID) {
1665  DBerror err;
1666  sDatabase.RunQuery(err,
1667  "INSERT INTO chrVisitedSystems (characterID, solarSystemID, visits, lastDateTime)"
1668  "VALUES (%u, %u, 1, %f)"
1669  " ON DUPLICATE KEY UPDATE"
1670  " visits = visits +1,"
1671  " lastDateTime = %f", charID, solarSystemID, GetFileTimeNow(), GetFileTimeNow());
1672 }
1673 
1675 {
1676 
1677  // maybe get all items owned by calling character?
1678 
1679  DBQueryResult res;
1680  if(!sDatabase.RunQuery(res,
1681  "SELECT "
1682  " e.itemID, "
1683  " e.itemName, "
1684  " e.typeID, "
1685  " e.ownerID, "
1686  " e.locationID, "
1687  " e.flag AS flagID, "
1688  " e.quantity AS stacksize, "
1689  " e.customInfo, "
1690  " e.singleton, "
1691  " g.categoryID, "
1692  " g.groupID "
1693  "FROM entity AS e"
1694  " LEFT JOIN invTypes USING (typeID)"
1695  " LEFT JOIN invGroups AS g USING (groupID)"
1696  "WHERE e.ownerID=%u AND e.locationID < %u", ownerID, maxStation))
1697  {
1698  codelog(SERVICE__ERROR, "Error in query: %s", res.error.c_str());
1699  return nullptr;
1700  }
1701 
1702  return DBResultToCRowset(res);
1703 }
1704 
1705 PyRep* CharacterDB::ListStations(uint32 ownerID, std::ostringstream& flagIDs, bool forCorp/*false*/, bool bpOnly/*false*/)
1706 {
1707 
1713  DBQueryResult res;
1715  if (bpOnly) {
1716  if (forCorp) {
1717  // this is some funky shit to get correct stationID for corp bps in hangar, as their location is officeID, but we need stationID for this call
1718  if (!sDatabase.RunQuery(res,
1719  "SELECT o.stationID, COUNT(e.itemID) as blueprintCount"
1720  " FROM entity AS e"
1721  " LEFT JOIN invTypes USING (typeID)"
1722  " LEFT JOIN invGroups AS g USING (groupID)"
1723  " LEFT JOIN staOffices as o ON o.itemID = e.locationID"
1724  " WHERE e.ownerID=%u AND e.flag IN (%s) AND g.categoryID = %u AND (e.locationID >= %u AND e.locationID <= %u)"
1725  " GROUP BY locationID", ownerID, flagIDs.str().c_str(), EVEDB::invCategories::Blueprint, minOffice, maxOffice))
1726  {
1727  codelog(SERVICE__ERROR, "Error in ListStations query: %s", res.error.c_str());
1728  return nullptr;
1729  }
1730  } else {
1731  if (!sDatabase.RunQuery(res,
1732  "SELECT e.locationID AS stationID, COUNT(e.itemID) as blueprintCount"
1733  " FROM entity AS e"
1734  " LEFT JOIN invTypes USING (typeID)"
1735  " LEFT JOIN invGroups AS g USING (groupID)"
1736  " WHERE e.ownerID=%u AND e.flag IN (%s) AND g.categoryID = %u AND e.locationID <= %u"
1737  " GROUP BY locationID", ownerID, flagIDs.str().c_str(), EVEDB::invCategories::Blueprint, maxStation))
1738  {
1739  codelog(SERVICE__ERROR, "Error in ListStations query: %s", res.error.c_str());
1740  return nullptr;
1741  }
1742  }
1743  } else {
1744  if (forCorp) {
1745  // this is some funky shit to get correct stationID for corp bps in hangar, as their location is officeID, but we need stationID for this call
1746  if (!sDatabase.RunQuery(res,
1747  "SELECT o.stationID, COUNT(e.itemID) as itemCount"
1748  " FROM entity AS e"
1749  " LEFT JOIN staOffices as o ON o.itemID = e.locationID"
1750  " WHERE e.ownerID=%u AND e.flag IN (%s) AND (e.locationID >= %u AND e.locationID <= %u)"
1751  " GROUP BY locationID", ownerID, flagIDs.str().c_str(), minOffice, maxOffice))
1752  {
1753  codelog(SERVICE__ERROR, "Error in ListStations query: %s", res.error.c_str());
1754  return nullptr;
1755  }
1756  } else {
1757  if (!sDatabase.RunQuery(res,
1758  "SELECT locationID AS stationID, COUNT(itemID) as itemCount"
1759  " FROM entity WHERE ownerID=%u AND flag IN (%s) AND locationID <= %u"
1760  " GROUP BY locationID", ownerID, flagIDs.str().c_str(), maxStation))
1761  {
1762  codelog(SERVICE__ERROR, "Error in ListStations query: %s", res.error.c_str());
1763  return nullptr;
1764  }
1765  }
1766  }
1767  PyRep* rsp = DBResultToCRowset(res);
1768  if (is_log_enabled(CLIENT__RSP_DUMP))
1769  rsp->Dump(CLIENT__RSP_DUMP, " ");
1770  return rsp;
1771 }
1772 
1774 {
1776  // some code shows 'copy' field here (for corp bp)
1777  DBQueryResult res;
1778  if(!sDatabase.RunQuery(res,
1779  "SELECT "
1780  " e.itemID, "
1781  " e.itemName, "
1782  " e.typeID, "
1783  " e.ownerID, "
1784  " e.locationID, "
1785  " e.flag AS flagID, "
1786  " e.quantity AS stacksize, "
1787  " e.customInfo, "
1788  " e.singleton, "
1789  " g.categoryID, "
1790  " g.groupID "
1791  "FROM entity AS e"
1792  " LEFT JOIN invTypes USING (typeID)"
1793  " LEFT JOIN invGroups AS g USING (groupID)"
1794  "WHERE e.ownerID=%u AND e.locationID=%u AND e.flag=4",
1795  ownerID, stationID))
1796  {
1797  codelog(SERVICE__ERROR, "Error in query: %s", res.error.c_str());
1798  return nullptr;
1799  }
1800  PyRep* rsp = DBResultToCRowset(res);
1801  if (is_log_enabled(CLIENT__RSP_DUMP))
1802  rsp->Dump(CLIENT__RSP_DUMP, " ");
1803  return rsp;
1804 }
1805 
1807 {
1809  DBQueryResult res;
1810  if (forCorp) {
1811  // do crazy shit here to get actual stationID/locationID of bp items in corp hangar
1812  if(!sDatabase.RunQuery(res,
1813  "SELECT "
1814  " e.itemID, "
1815  " e.itemName, "
1816  " e.typeID, "
1817  " e.ownerID, "
1818  " o.stationID AS locationID, "
1819  " e.flag AS flagID, "
1820  " e.quantity AS stacksize, "
1821  //" e.customInfo, "
1822  " e.singleton, "
1823  //" g.groupID, "
1824  //" g.categoryID, "
1825  " b.pLevel AS productivityLevel,"
1826  " b.mLevel AS materialLevel,"
1827  " b.copy,"
1828  " b.runs AS licensedProductionRunsRemaining"
1829  " FROM entity AS e"
1830  " LEFT JOIN invTypes USING (typeID)"
1831  " LEFT JOIN invGroups AS g USING (groupID)"
1832  " LEFT JOIN invBlueprints AS b USING (itemID)"
1833  " LEFT JOIN staOffices as o ON e.locationID = o.itemID"
1834  " WHERE e.ownerID=%u AND o.stationID=%u AND g.categoryID = %u",
1835  ownerID, stationID, EVEDB::invCategories::Blueprint))
1836  {
1837  codelog(SERVICE__ERROR, "Error in query: %s", res.error.c_str());
1838  return nullptr;
1839  }
1840  } else {
1841  if(!sDatabase.RunQuery(res,
1842  "SELECT"
1843  " e.itemID,"
1844  " e.itemName,"
1845  " e.typeID,"
1846  " e.ownerID,"
1847  " e.locationID,"
1848  " e.flag AS flagID,"
1849  " e.quantity AS stacksize,"
1850  " e.customInfo,"
1851  " e.singleton,"
1852  " g.groupID,"
1853  " g.categoryID,"
1854  " b.pLevel AS productivityLevel,"
1855  " b.mLevel AS materialLevel,"
1856  " b.copy,"
1857  " b.runs AS licensedProductionRunsRemaining"
1858  " FROM entity AS e"
1859  " LEFT JOIN invTypes USING (typeID)"
1860  " LEFT JOIN invGroups AS g USING (groupID)"
1861  " LEFT JOIN invBlueprints AS b USING (itemID)"
1862  " WHERE e.ownerID=%u AND e.locationID=%u AND e.flag=4 AND g.categoryID = %u",
1863  ownerID, stationID, EVEDB::invCategories::Blueprint))
1864  {
1865  codelog(SERVICE__ERROR, "Error in query: %s", res.error.c_str());
1866  return nullptr;
1867  }
1868 
1869  }
1870  PyRep* rsp = DBResultToCRowset(res);
1871  if (is_log_enabled(CLIENT__RSP_DUMP))
1872  rsp->Dump(CLIENT__RSP_DUMP, " ");
1873  return rsp;
1874 
1875 }
1876 
1878 {
1879  DBQueryResult res;
1880  if (!sDatabase.RunQuery(res,
1881  "SELECT valueInt FROM entity_attributes WHERE attributeID= %u AND itemID= "
1882  "(SELECT itemID FROM entity WHERE locationID = %u AND typeID = %u)",
1883  AttrSkillLevel, charID, skillTypeID))
1884  {
1885  codelog(SERVICE__ERROR, "Error in query: %s", res.error.c_str());
1886  return 0;
1887  }
1888 
1889  DBResultRow row;
1890  if (res.GetRow(row))
1891  return row.GetUInt(0);
1892  return 0;
1893 }
float cameraZ
Definition: CharacterDB.h:39
Base Python wire object.
Definition: PyRep.h:66
PyRep * GetCharPrivateInfo(uint32 charID)
#define sConfig
A macro for easier access to the singleton.
float jawSideways
Definition: CharacterDB.h:62
unsigned __int8 uint8
Definition: eve-compat.h:46
bool LoadSkillQueue(uint32 charID, SkillQueue &into)
bool GetCharClones(uint32 charID, std::vector< uint32 > &into)
double value() const
Definition: PyRep.h:309
#define sDatabase
Definition: dbcore.h:199
bool SetNote(uint32 ownerID, uint32 itemID, const char *str)
static bool ChangeCloneLocation(uint32 charID, uint32 locationID)
const char * GetText(uint32 index) const
Definition: dbcore.h:104
static float GetCorpTaxRate(uint32 charID)
#define _log(type, fmt,...)
Definition: logsys.h:124
int64 grantableRolesAtHQ
static bool SaveCorpData(uint32 charID, const CorpData &data)
float GetFloat(uint32 index) const
Definition: dbcore.cpp:682
void SetAvatarColors(uint32 charID, uint32 colorID, uint32 colorNameA, uint32 colorNameBC, double weight, double gloss)
bool SaveSkillQueue(uint32 charID, SkillQueue &queue)
float smileLeft
Definition: CharacterDB.h:67
PyObjectEx * DBResultToCRowset(DBQueryResult &result)
Definition: EVEDBUtils.cpp:402
uint32 PickAlternateShip(uint32 charID, uint32 locationID)
Python string.
Definition: PyRep.h:430
PyRep * GetCharSelectInfo(uint32 charID)
int32 value() const
Definition: PyRep.h:247
int32 GetInt(uint32 index) const
Definition: dbcore.cpp:635
void SetAvatarModifiers(uint32 charID, PyRep *modifierLocationID, PyRep *paperdollResourceID, PyRep *paperdollResourceVariation)
PyRep * GetRespecInfo(uint32 characterId)
float puckerLips
Definition: CharacterDB.h:64
float browRightTighten
Definition: CharacterDB.h:55
Python's dictionary.
Definition: PyRep.h:719
static bool SaveCharacter(uint32 charID, const CharacterData &data)
Definition: CharacterDB.cpp:66
uint32 ownerID() const
Definition: InventoryItem.h:99
bool EditOwnerNote(uint32 charID, uint32 noteID, const std::string &label, const std::string &content)
uint32 GetUInt(uint32 index) const
Definition: dbcore.cpp:658
float frownLeft
Definition: CharacterDB.h:65
float eyeClose
Definition: CharacterDB.h:57
static bool GetCharHomeStation(uint32 charID, uint32 &stationID)
PyRep * GetCharacterList(uint32 accountID)
float browRightUpDown
Definition: CharacterDB.h:56
int64 rolesAtHQ
PyRep * GetOwnerNoteLabels(uint32 charID)
static const std::array< std::string, 18 > badChars
Definition: EVE_Consts.h:87
#define IsAgent(itemID)
Definition: EVE_Defines.h:247
bool GetCharItems(uint32 charID, std::vector< uint32 > &into)
int64 rolesAtBase
uint8 level
Definition: CharacterDB.h:73
static PyRep * GetMyCorpMates(uint32 corpID)
PyRep * GetBounty(uint32 charID, uint32 ownerID)
void UpdateContact(int32 standing, uint32 charID, uint32 ownerID)
uint32 skillPoints
float browRightCurl
Definition: CharacterDB.h:54
bool DoesCorporationExist(uint32 corpID)
void UpdateSkillQueueEndTime(int64 endtime, uint32 charID)
void SetLogOffTime(uint32 charID)
const char * name()
PyRep * GetSkillHistory(uint32 charID)
PyObjectEx * DBResultToCIndexedRowset(DBQueryResult &result, const char *key)
Definition: EVEDBUtils.cpp:419
float headTilt
Definition: CharacterDB.h:49
void Dump(FILE *into, const char *pfx) const
Dumps object to file.
Definition: PyRep.cpp:84
int64 rolesAtOther
PyRep * GetKillOrLoss(uint32 charID)
float eyesLookHorizontal
Definition: CharacterDB.h:59
void AddContact(uint32 ownerID, uint32 charID, int32 standing, bool inWatchlist)
PyRep * GetCharPublicInfo(uint32 charID)
void CancelCharacterDeletePrepare(uint32 accountID, uint32 charID)
std::string customInfo
Definition: ItemType.h:194
signed __int32 int32
Definition: eve-compat.h:49
static PyRep * ListStations(uint32 ownerID, std::ostringstream &flagIDs, bool forCorp=false, bool bpOnly=false)
void DeleteCharacter(uint32 charID)
bool GetRow(DBResultRow &into)
Definition: dbcore.cpp:552
void addOwnerCache(uint32 ownerID, std::string ownerName, uint32 typeID)
static uint32 GetStartingStationByCareer(uint32 careerID)
#define is_log_enabled(type)
Definition: logsys.h:78
#define sLog
Evaluates to a NewLog instance.
Definition: LogNew.h:250
static PyRep * GetInfoWindowDataForChar(uint32 charID)
bool GetAttributesFromAncestry(uint32 ancestryID, uint8 &intelligence, uint8 &charisma, uint8 &perception, uint8 &memory, uint8 &willpower)
float browLeftCurl
Definition: CharacterDB.h:51
int64 PrepareCharacterForDelete(uint32 accountID, uint32 charID)
int64 endTime
Definition: CharacterDB.h:75
std::string name
static const std::array< std::string, 28 > badWords
Definition: EVE_Consts.h:55
void SetCurrentShip(uint32 charID, uint32 shipID)
bool SavePausedSkillQueue(uint32 charID, SkillQueue &queue)
float squintLeft
Definition: CharacterDB.h:60
const char * c_str() const
Definition: dbcore.h:48
void VisitSystem(uint32 solarSystemID, uint32 charID)
#define codelog(type, fmt,...)
Definition: logsys.h:128
uint32 solarSystemID
float browLeftTighten
Definition: CharacterDB.h:52
static uint8 GetSkillLevel(uint32 charID, uint16 skillTypeID)
uint32 lightID
Definition: CharacterDB.h:35
#define snprintf
Definition: eve-compat.h:184
void SetBlockContact(uint32 charID, uint32 ownerID, bool blocked)
PyObject * DBResultToRowset(DBQueryResult &result)
Definition: EVEDBUtils.cpp:81
static PyRep * ListStationBlueprintItems(uint32 ownerID, uint32 stationID, bool forCorp=false)
std::string description
float portraitPoseNumber
Definition: CharacterDB.h:48
int64 rolesAtAll
uint32 locationID() const
Python integer.
Definition: PyRep.h:231
float securityRating
float cameraFieldOfView
Definition: CharacterDB.h:40
float frownRight
Definition: CharacterDB.h:66
bool GetCareerBySchool(uint32 schoolID, uint8 &raceID, uint32 &careerID)
#define maxStation
Definition: EVE_Defines.h:128
#define PyStatic
Definition: PyRep.h:1209
float orientChar
Definition: CharacterDB.h:50
static bool GetActiveCloneID(uint32 charID, uint32 &itemID)
static uint32 GetCorpID(uint32 charID)
uint32 constellationID
int64 corpRole
Python object "ccp_exceptions.UserError".
Definition: PyExceptions.h:121
uint32 lightColorID
Definition: CharacterDB.h:36
int64 startTime
Definition: CharacterDB.h:76
PyRep * GetLabels(uint32 charID)
unsigned __int32 uint32
Definition: eve-compat.h:50
void AddBounty(uint32 charID, uint32 ownerID, uint32 amount)
uint32 baseID
bool GetSkillsByRace(uint32 raceID, std::map< uint32, uint8 > &into)
void EditLabel(uint32 charID, uint32 labelID, uint32 color, std::string name)
float headLookTargetY
Definition: CharacterDB.h:45
PyRep * GetContacts(uint32 charID, bool blocked)
PyRep * GetOwnerNote(uint32 charID, uint32 noteID)
#define IsCorp(itemID)
Definition: EVE_Defines.h:234
bool LoadPausedSkillQueue(uint32 charID, SkillQueue &into)
PyRep * GetCharPublicInfo3(uint32 charID)
PyObject * DBResultToIndexRowset(DBQueryResult &result, const char *key)
Definition: EVEDBUtils.cpp:144
uint32 AddOwnerNote(uint32 charID, const std::string &label, const std::string &content)
static int64 GetCorpRole(uint32 charID)
uint32 logonMinutes
uint32 backgroundID
Definition: CharacterDB.h:34
uint32 corporationID
bool GetActiveCloneType(uint32 charID, uint32 &typeID)
float smileRight
Definition: CharacterDB.h:68
double GetFileTimeNow()
Definition: utils_time.cpp:84
void SetAvatarSculpts(uint32 charID, PyRep *sculptLocationID, PyRep *weightUpDown, PyRep *weightLeftRight, PyRep *weightForwardBack)
void SetPortraitInfo(uint32 charID, PortraitInfo &data)
static PyRep * ListStationItems(uint32 ownerID, uint32 stationID)
void SetLogInTime(uint32 charID)
float cameraPoiX
Definition: CharacterDB.h:41
std::string GetCharName(uint32 charID)
static void GetCharacterData(uint32 charID, std::map< std::string, int64 > &characterDataMap)
float browLeftUpDown
Definition: CharacterDB.h:53
DBerror error
Definition: dbcore.h:69
signed __int64 int64
Definition: eve-compat.h:51
void SetLabel(uint32 charID, uint32 color, std::string name)
int16 corpAccountKey
void RemoveContact(uint32 charID, uint32 ownerID)
#define PRIi64
Definition: eve-compat.h:83
void SetAvatar(uint32 charID, PyRep *hairDarkness)
bool GetBaseSkills(std::map< uint32, uint8 > &into)
float cameraPoiZ
Definition: CharacterDB.h:43
static uint32 NewCharacter(const CharacterData &data, const CorpData &corpData)
Definition: CharacterDB.cpp:33
uint16 typeID
Definition: CharacterDB.h:74
std::vector< QueuedSkill > SkillQueue
Definition: CharacterDB.h:78
float headLookTargetZ
Definition: CharacterDB.h:46
bool IsFloat() const
Definition: PyRep.h:102
bool ReportRespec(uint32 characterId)
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
static void AddEmployment(uint32 charID, uint32 corpID, uint32 oldCorpID=0)
float cameraX
Definition: CharacterDB.h:37
PyRep * ValidateCharNameRep(std::string name)
bool GetSkillsByCareer(uint32 careerID, std::map< uint32, uint8 > &into)
float lightIntensity
Definition: CharacterDB.h:47
size_t GetRowCount()
Definition: dbcore.h:72
PyPackedRow * DBRowToPackedRow(DBResultRow &row)
Definition: EVEDBUtils.cpp:453
bool GetCorporationBySchool(uint32 schoolID, uint32 &corporationID)
#define sItemFactory
Definition: ItemFactory.h:165
bool IsInt() const
Definition: PyRep.h:100
#define maxOffice
Definition: EVE_Defines.h:145
PyObject * DBRowToKeyVal(DBResultRow &row)
Definition: EVEDBUtils.cpp:199
float headLookTargetX
Definition: CharacterDB.h:44
float eyesLookVertical
Definition: CharacterDB.h:58
int64 grantableRoles
PyFloat * AsFloat()
Definition: PyRep.h:126
PyInt * AsInt()
Definition: PyRep.h:122
std::string title
int64 grantableRolesAtBase
void SetCurrentPod(uint32 charID, uint32 podID)
int64 GetInt64(uint32 index) const
Definition: dbcore.cpp:670
int64 grantableRolesAtOther
static void SetCorpRole(uint32 charID, int64 role)
static PyRep * List(uint32 ownerID)
unsigned __int16 uint16
Definition: eve-compat.h:48
void DeleteLabel(uint32 charID, uint32 labelID)
float cameraPoiY
Definition: CharacterDB.h:42
PyRep * GetTopBounties()
uint16 typeID() const
bool GetLocationCorporationByCareer(CharacterData &cdata, uint32 &corporationID)
PyString * GetNote(uint32 ownerID, uint32 itemID)
Definition: dbcore.h:39
float cameraY
Definition: CharacterDB.h:38
void SetItemString(const char *key, PyRep *value)
SetItemString adds or sets a database entry.
Definition: PyRep.h:812
float squintRight
Definition: CharacterDB.h:61
uint32 careerSpecialityID
bool ChangeCloneType(uint32 charID, uint32 typeID)
#define minOffice
Definition: EVE_Defines.h:144
bool icontains(std::string data, std::string toSearch, size_t pos=0)
Definition: misc.cpp:194
void ValidateCharName(std::string name)
Python long integer.
Definition: PyRep.h:261
void SaveSkillHistory(uint16 eventID, double logDate, uint32 characterID, uint32 skillTypeID, uint8 skillLevel, uint32 absolutePoints)