2018-03-02 07:22:25 -03:00
|
|
|
#include <set>
|
|
|
|
|
2018-03-06 22:22:19 +01:00
|
|
|
#include <Common.h>
|
|
|
|
#include <Logging/Logger.h>
|
2021-11-27 00:53:57 +01:00
|
|
|
#include <Exd/ExdData.h>
|
2018-03-06 22:22:19 +01:00
|
|
|
#include <Network/PacketContainer.h>
|
|
|
|
#include <Database/DatabaseDef.h>
|
2020-03-01 01:00:57 +11:00
|
|
|
#include <Service.h>
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2019-06-20 14:48:24 +10:00
|
|
|
#include "Network/PacketWrappers/PlayerSetupPacket.h"
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-12-01 00:27:16 +11:00
|
|
|
#include "Manager/TerritoryMgr.h"
|
2019-07-21 22:33:33 +10:00
|
|
|
#include "Territory/Territory.h"
|
2018-07-24 23:58:08 +02:00
|
|
|
#include "Inventory/Item.h"
|
|
|
|
#include "Inventory/ItemContainer.h"
|
2018-12-23 13:26:33 +01:00
|
|
|
#include "Manager/ItemMgr.h"
|
2021-11-27 00:53:57 +01:00
|
|
|
#include "Quest/Quest.h"
|
2017-10-04 23:28:38 +02:00
|
|
|
|
2021-12-02 17:34:27 +01:00
|
|
|
#include "WorldServer.h"
|
|
|
|
|
2018-11-29 16:55:48 +01:00
|
|
|
using namespace Sapphire::Common;
|
|
|
|
using namespace Sapphire::Network::Packets;
|
2021-11-27 00:53:57 +01:00
|
|
|
using namespace Sapphire::Network::Packets::WorldPackets::Server;
|
2018-12-01 00:27:16 +11:00
|
|
|
using namespace Sapphire::World::Manager;
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
bool Sapphire::Entity::Player::loadFromDb( uint64_t characterId )
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2021-11-27 00:53:57 +01:00
|
|
|
m_characterId = characterId;
|
2018-08-29 21:40:59 +02:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
auto& db = Common::Service< Db::DbWorkerPool< Db::ZoneDbConnection > >::ref();
|
|
|
|
auto stmt = db.getPreparedStatement( Db::ZoneDbStatements::CHARA_SEL );
|
2017-10-04 23:28:38 +02:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
stmt->set( 1, characterId );
|
2020-03-01 01:00:57 +11:00
|
|
|
auto res = db.query( stmt );
|
2018-01-28 23:53:58 +11:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
if( !res->next() )
|
|
|
|
return false;
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
m_id = res->getUInt( "EntityId" );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
auto name = res->getString( "Name" );
|
|
|
|
strcpy( m_name, name.c_str() );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-11-05 23:07:39 +01:00
|
|
|
auto zoneId = res->getUInt( "TerritoryType" );
|
2018-11-06 10:36:45 +01:00
|
|
|
m_territoryId = res->getUInt( "TerritoryId" );
|
2018-12-02 15:32:22 +11:00
|
|
|
m_prevTerritoryTypeId = res->getUInt( "OTerritoryType" );
|
|
|
|
m_prevTerritoryId = res->getUInt( "OTerritoryId" );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
// Position
|
|
|
|
m_pos.x = res->getFloat( "PosX" );
|
|
|
|
m_pos.y = res->getFloat( "PosY" );
|
|
|
|
m_pos.z = res->getFloat( "PosZ" );
|
|
|
|
setRot( res->getFloat( "PosR" ) );
|
2018-02-04 17:46:46 +01:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
m_prevPos.x = res->getFloat( "OPosX" );
|
|
|
|
m_prevPos.y = res->getFloat( "OPosY" );
|
|
|
|
m_prevPos.z = res->getFloat( "OPosZ" );
|
|
|
|
m_prevRot = res->getFloat( "OPosR" );
|
2018-02-04 17:46:46 +01:00
|
|
|
|
2018-12-02 15:32:22 +11:00
|
|
|
m_territoryTypeId = zoneId;
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
// Model
|
|
|
|
auto custom = res->getBlobVector( "Customize" );
|
|
|
|
memcpy( reinterpret_cast< char* >( m_customize ), custom.data(), custom.size() );
|
2017-10-04 23:28:38 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
m_modelMainWeapon = res->getUInt64( "ModelMainWeapon" );
|
2017-10-04 23:28:38 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
auto modelEq = res->getBlobVector( "ModelEquip" );
|
|
|
|
memcpy( reinterpret_cast< char* >( m_modelEquip ), modelEq.data(), modelEq.size() );
|
2017-10-04 23:28:38 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
// Minimal info
|
2017-11-02 17:54:10 -02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
m_guardianDeity = res->getUInt8( "GuardianDeity" );
|
|
|
|
m_birthDay = res->getUInt8( "BirthDay" );
|
|
|
|
m_birthMonth = res->getUInt8( "BirthMonth" );
|
|
|
|
m_status = static_cast< ActorStatus >( res->getUInt( "Status" ) );
|
|
|
|
m_emoteMode = res->getUInt( "EmoteModeType" );
|
2018-07-09 22:34:56 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
m_activeTitle = res->getUInt16( "ActiveTitle" );
|
2018-07-09 22:34:56 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
m_class = static_cast< ClassJob >( res->getUInt( "Class" ) );
|
|
|
|
m_homePoint = res->getUInt8( "Homepoint" );
|
2017-10-04 23:28:38 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
// Additional data
|
|
|
|
m_voice = res->getUInt8( "Voice" );
|
|
|
|
m_startTown = res->getUInt8( "StartTown" );
|
|
|
|
m_playTime = res->getUInt( "TotalPlayTime" );
|
2017-11-02 17:54:10 -02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
m_bNewGame = res->getBoolean( "IsNewGame" );
|
|
|
|
m_bNewAdventurer = res->getBoolean( "IsNewAdventurer" );
|
|
|
|
m_openingSequence = res->getUInt8( "OpeningSequence" );
|
2017-11-02 17:54:10 -02:00
|
|
|
|
2021-12-02 17:34:27 +01:00
|
|
|
// check if opening sequence should be skipped
|
|
|
|
auto& server = Common::Service< World::WorldServer >::ref();
|
|
|
|
auto skipOpening = server.getConfig().skipOpening;
|
|
|
|
if( m_openingSequence < 2 && skipOpening )
|
|
|
|
m_openingSequence = 2;
|
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
m_gc = res->getUInt8( "GrandCompany" );
|
|
|
|
m_cfPenaltyUntil = res->getUInt( "CFPenaltyUntil" );
|
|
|
|
m_activeTitle = res->getUInt16( "ActiveTitle" );
|
2017-11-02 17:54:10 -02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
m_gmRank = res->getUInt8( "GMRank" );
|
2017-11-02 17:54:10 -02:00
|
|
|
|
2022-01-14 19:06:23 +01:00
|
|
|
m_equippedMannequin = res->getUInt8( "EquippedMannequin" );
|
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
m_equipDisplayFlags = res->getUInt8( "EquipDisplayFlags" );
|
2018-05-17 20:46:11 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
m_pose = res->getUInt8( "Pose" );
|
2018-07-11 23:52:24 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
// Blobs
|
2017-11-02 17:54:10 -02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
auto howTo = res->getBlobVector( "HowTo" );
|
2021-11-27 00:53:57 +01:00
|
|
|
memcpy( reinterpret_cast< char* >( m_howTo.data() ), howTo.data(), howTo.size() );
|
2017-10-04 23:28:38 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
auto questCompleteFlags = res->getBlobVector( "QuestCompleteFlags" );
|
2021-11-27 00:53:57 +01:00
|
|
|
memcpy( reinterpret_cast< char* >( m_questCompleteFlags.data() ), questCompleteFlags.data(), questCompleteFlags.size() );
|
2017-10-04 23:28:38 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
auto questTracking = res->getBlobVector( "QuestTracking" );
|
2021-11-27 00:53:57 +01:00
|
|
|
memcpy( reinterpret_cast< char* >( m_questTracking.data() ), questTracking.data(), questTracking.size() );
|
2017-10-04 23:28:38 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
auto aetheryte = res->getBlobVector( "Aetheryte" );
|
2021-11-27 00:53:57 +01:00
|
|
|
memcpy( reinterpret_cast< char* >( m_aetheryte.data() ), aetheryte.data(), aetheryte.size() );
|
2017-10-04 23:28:38 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
auto unlocks = res->getBlobVector( "Unlocks" );
|
2021-11-27 00:53:57 +01:00
|
|
|
memcpy( reinterpret_cast< char* >( m_unlocks.data() ), unlocks.data(), unlocks.size() );
|
2017-10-04 23:28:38 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
auto discovery = res->getBlobVector( "Discovery" );
|
2021-11-27 00:53:57 +01:00
|
|
|
memcpy( reinterpret_cast< char* >( m_discovery.data() ), discovery.data(), discovery.size() );
|
2017-10-04 23:28:38 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
auto titleList = res->getBlobVector( "TitleList" );
|
2021-11-27 00:53:57 +01:00
|
|
|
memcpy( reinterpret_cast< char* >( m_titleList.data() ), titleList.data(), titleList.size() );
|
2021-07-27 07:33:55 +09:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
auto mountGuide = res->getBlobVector( "Mounts" );
|
2021-11-27 00:53:57 +01:00
|
|
|
memcpy( reinterpret_cast< char* >( m_mountGuide.data() ), mountGuide.data(), mountGuide.size() );
|
2017-12-03 17:24:11 +01:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
auto orchestrion = res->getBlobVector( "Orchestrion" );
|
2021-11-27 00:53:57 +01:00
|
|
|
memcpy( reinterpret_cast< char* >( m_orchestrion.data() ), orchestrion.data(), orchestrion.size() );
|
2018-01-28 23:53:58 +11:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
auto gcRank = res->getBlobVector( "GrandCompanyRank" );
|
2021-11-27 00:53:57 +01:00
|
|
|
memcpy( m_gcRank.data(), gcRank.data(), gcRank.size() );
|
2017-10-04 23:28:38 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
res->free();
|
2017-09-11 18:59:50 +02:00
|
|
|
|
2021-12-13 22:36:29 -03:00
|
|
|
if( !loadActiveQuests() || !loadClassData() || !loadSearchInfo() || !loadHuntingLog() || !loadFriendList() || !loadBlacklist() )
|
2021-11-27 00:53:57 +01:00
|
|
|
{
|
|
|
|
Logger::error( "chara#{0} data corrupt!", m_characterId );
|
|
|
|
}
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2020-03-17 22:23:26 +09:00
|
|
|
initInventory();
|
|
|
|
|
|
|
|
// Stats
|
|
|
|
m_hp = res->getUInt( "Hp" );
|
|
|
|
m_mp = res->getUInt( "Mp" );
|
|
|
|
m_tp = 0;
|
2018-08-29 21:40:59 +02:00
|
|
|
m_maxHp = getMaxHp();
|
|
|
|
m_maxMp = getMaxMp();
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
m_mount = res->getUInt8( "Mount" );
|
2017-11-21 17:39:10 +11:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
m_modelSubWeapon = 0;
|
2018-08-29 21:40:59 +02:00
|
|
|
m_lastTickTime = 0;
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
calculateStats();
|
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
if( m_bNewGame )
|
|
|
|
{
|
|
|
|
m_bNewGame = false;
|
|
|
|
m_hp = getMaxHp();
|
|
|
|
m_mp = getMaxMp();
|
|
|
|
}
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
if( m_hp == 0 )
|
|
|
|
m_status = ActorStatus::Dead;
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
syncLastDBWrite();
|
2018-02-04 17:46:46 +01:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
return true;
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
|
|
|
|
2018-11-29 16:55:48 +01:00
|
|
|
bool Sapphire::Entity::Player::loadActiveQuests()
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2020-03-01 01:00:57 +11:00
|
|
|
auto& db = Common::Service< Db::DbWorkerPool< Db::ZoneDbConnection > >::ref();
|
|
|
|
auto stmt = db.getPreparedStatement( Db::ZoneDbStatements::CHARA_SEL_QUEST );
|
2017-10-05 22:43:15 +02:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
stmt->setUInt64( 1, m_characterId );
|
2020-03-01 01:00:57 +11:00
|
|
|
auto res = db.query( stmt );
|
2017-10-05 22:43:15 +02:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
for( size_t idx = 0; idx < 30; ++ idx )
|
|
|
|
m_quests[ idx ] = World::Quest();
|
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
while( res->next() )
|
|
|
|
{
|
2017-10-05 22:43:15 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
auto slotId = res->getUInt8( 2 );
|
2017-10-05 22:43:15 +02:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
auto quest = World::Quest( res->getUInt16( 3 ), res->getUInt8( 4 ), res->getUInt8( 5 ) );
|
|
|
|
quest.setUI8A( res->getUInt8( 6 ) );
|
|
|
|
quest.setUI8B( res->getUInt8( 7 ) );
|
|
|
|
quest.setUI8C( res->getUInt8( 8 ) );
|
|
|
|
quest.setUI8D( res->getUInt8( 9 ) );
|
|
|
|
quest.setUI8E( res->getUInt8( 10 ) );
|
|
|
|
quest.setUI8F( res->getUInt8( 11 ) );
|
|
|
|
m_quests[ slotId ] = quest;
|
2017-10-05 22:43:15 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
}
|
2017-10-05 22:43:15 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
return true;
|
2017-10-05 22:43:15 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2018-11-29 16:55:48 +01:00
|
|
|
bool Sapphire::Entity::Player::loadClassData()
|
2017-10-05 22:43:15 +02:00
|
|
|
{
|
2020-03-01 01:00:57 +11:00
|
|
|
auto& db = Common::Service< Db::DbWorkerPool< Db::ZoneDbConnection > >::ref();
|
2018-08-29 21:40:59 +02:00
|
|
|
// ClassIdx, Exp, Lvl
|
2020-03-01 01:00:57 +11:00
|
|
|
auto stmt = db.getPreparedStatement( Db::ZoneDbStatements::CHARA_CLASS_SEL );
|
2021-11-27 00:53:57 +01:00
|
|
|
stmt->setUInt64( 1, m_characterId );
|
2020-03-01 01:00:57 +11:00
|
|
|
auto res = db.query( stmt );
|
2018-08-29 21:40:59 +02:00
|
|
|
|
|
|
|
while( res->next() )
|
|
|
|
{
|
|
|
|
auto index = res->getUInt16( 1 );
|
|
|
|
auto exp = res->getUInt( 2 );
|
|
|
|
auto lvl = res->getUInt8( 3 );
|
|
|
|
|
|
|
|
m_classArray[ index ] = lvl;
|
|
|
|
m_expArray[ index ] = exp;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
|
|
|
|
2018-11-29 16:55:48 +01:00
|
|
|
bool Sapphire::Entity::Player::loadSearchInfo()
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2020-03-01 01:00:57 +11:00
|
|
|
auto& db = Common::Service< Db::DbWorkerPool< Db::ZoneDbConnection > >::ref();
|
|
|
|
auto stmt = db.getPreparedStatement( Db::ZoneDbStatements::CHARA_SEL_SEARCHINFO );
|
2021-11-27 00:53:57 +01:00
|
|
|
stmt->setUInt64( 1, m_characterId );
|
2020-03-01 01:00:57 +11:00
|
|
|
auto res = db.query( stmt );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
if( !res->next() )
|
2019-04-13 22:41:29 +10:00
|
|
|
{
|
2021-11-27 00:53:57 +01:00
|
|
|
Logger::error( "Failed to load search info for character#{}", m_characterId );
|
2018-08-29 21:40:59 +02:00
|
|
|
return false;
|
2019-04-13 22:41:29 +10:00
|
|
|
}
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
m_searchSelectClass = res->getUInt8( 2 );
|
|
|
|
m_searchSelectRegion = res->getUInt8( 3 );
|
2018-02-15 19:44:54 +11:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
// todo: internally use an std::string instead of a char[]
|
|
|
|
auto searchMessage = res->getString( 4 );
|
2018-09-26 03:32:43 -04:00
|
|
|
memset( m_searchMessage, 0, sizeof( m_searchMessage ) );
|
2018-08-29 21:40:59 +02:00
|
|
|
std::copy( searchMessage.begin(), searchMessage.end(), m_searchMessage );
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
return true;
|
2017-08-08 13:53:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-03-26 00:04:27 +01:00
|
|
|
bool Sapphire::Entity::Player::loadHuntingLog()
|
|
|
|
{
|
2020-03-01 01:00:57 +11:00
|
|
|
auto& db = Common::Service< Db::DbWorkerPool< Db::ZoneDbConnection > >::ref();
|
|
|
|
auto stmt = db.getPreparedStatement( Db::ZoneDbStatements::CHARA_MONSTERNOTE_SEL );
|
2021-11-27 00:53:57 +01:00
|
|
|
stmt->setUInt64( 1, m_characterId );
|
2020-03-01 01:00:57 +11:00
|
|
|
auto res = db.query( stmt );
|
2019-03-26 00:04:27 +01:00
|
|
|
|
|
|
|
if( !res->next() )
|
2019-04-13 22:41:29 +10:00
|
|
|
{
|
2021-11-27 00:53:57 +01:00
|
|
|
Logger::error( "Failed to load hunting log data for character#{}", m_characterId );
|
2019-03-26 00:04:27 +01:00
|
|
|
return false;
|
2019-04-13 22:41:29 +10:00
|
|
|
}
|
2019-03-26 00:04:27 +01:00
|
|
|
|
|
|
|
for( auto i = 0; i < 12; ++i )
|
|
|
|
{
|
|
|
|
std::string catStr = fmt::format( "Category_{}", i );
|
|
|
|
auto cat = res->getBlobVector( catStr );
|
|
|
|
m_huntingLogEntries[i].rank = cat[0];
|
|
|
|
memcpy( reinterpret_cast< char* >( m_huntingLogEntries[i].entries ), cat.data() + 1, cat.size() - 1 );
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-11-29 16:55:48 +01:00
|
|
|
void Sapphire::Entity::Player::updateSql()
|
2017-08-08 13:53:47 +02:00
|
|
|
{
|
2021-11-27 00:53:57 +01:00
|
|
|
////// Update player data
|
|
|
|
updateDbChara();
|
|
|
|
|
|
|
|
////// Searchinfo
|
|
|
|
updateDbSearchInfo();
|
|
|
|
|
|
|
|
////// QUESTS
|
|
|
|
updateDbAllQuests();
|
|
|
|
|
|
|
|
////// Class
|
|
|
|
updateDbClass();
|
|
|
|
|
|
|
|
////// MonterNote
|
|
|
|
updateDbMonsterNote();
|
|
|
|
|
|
|
|
////// FriendList
|
|
|
|
updateDbFriendList();
|
|
|
|
|
2021-12-13 22:36:29 -03:00
|
|
|
////// Blacklist
|
|
|
|
updateDbBlacklist();
|
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
///// Store last write
|
|
|
|
syncLastDBWrite();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Sapphire::Entity::Player::updateDbChara() const
|
|
|
|
{
|
|
|
|
auto& db = Service< Db::DbWorkerPool< Db::ZoneDbConnection > >::ref();
|
2018-08-29 21:40:59 +02:00
|
|
|
/*"Hp 1, Mp 2, Tp 3, Gp 4, Mode 5, Mount 6, InvincibleGM 7, Voice 8, "
|
|
|
|
"Customize 9, ModelMainWeapon 10, ModelSubWeapon 11, ModelSystemWeapon 12, "
|
|
|
|
"ModelEquip 13, EmoteModeType 14, Language 15, IsNewGame 16, IsNewAdventurer 17, "
|
|
|
|
"TerritoryType 18, TerritoryId 19, PosX 20, PosY 21, PosZ 22, PosR 23, "
|
|
|
|
"OTerritoryType 24, OTerritoryId 25, OPosX 26, OPosY 27, OPosZ 28, OPosR 29, "
|
|
|
|
"Class 30, Status 31, TotalPlayTime 32, HomePoint 33, FavoritePoint 34, RestPoint 35, "
|
|
|
|
"ActiveTitle 36, TitleList 37, Achievement 38, Aetheryte 39, HowTo 40, Minions 41, Mounts 42, Orchestrion 43, "
|
|
|
|
"EquippedMannequin 44, ConfigFlags 45, QuestCompleteFlags 46, OpeningSequence 47, "
|
|
|
|
"QuestTracking 48, GrandCompany 49, GrandCompanyRank 50, Discovery 51, GMRank 52, Unlocks 53, "
|
|
|
|
"CFPenaltyUntil 54, Pose 55"*/
|
2018-09-17 22:52:57 +02:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
auto stmt = db.getPreparedStatement( Db::CHARA_UP );
|
2018-08-29 21:40:59 +02:00
|
|
|
|
|
|
|
stmt->setInt( 1, getHp() );
|
|
|
|
stmt->setInt( 2, getMp() );
|
|
|
|
stmt->setInt( 3, 0 ); // TP
|
|
|
|
stmt->setInt( 4, 0 ); // GP
|
|
|
|
stmt->setInt( 5, 0 ); // Mode
|
2021-11-27 00:53:57 +01:00
|
|
|
stmt->setUInt( 6, m_mount ); // Mount
|
2018-08-29 21:40:59 +02:00
|
|
|
stmt->setInt( 7, 0 ); // InvicibleGM
|
|
|
|
stmt->setInt( 8, m_voice );
|
2017-10-10 00:03:24 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
std::vector< uint8_t > customVec( sizeof( m_customize ) );
|
|
|
|
memcpy( customVec.data(), m_customize, sizeof( m_customize ) );
|
|
|
|
stmt->setBinary( 9, customVec );
|
2017-10-10 00:03:24 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
stmt->setInt64( 10, m_modelMainWeapon );
|
|
|
|
stmt->setInt64( 11, m_modelSubWeapon );
|
|
|
|
stmt->setInt64( 12, m_modelSystemWeapon );
|
2017-10-10 00:03:24 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
std::vector< uint8_t > modelVec( sizeof( m_modelEquip ) );
|
|
|
|
memcpy( modelVec.data(), m_modelEquip, sizeof( m_modelEquip ) );
|
|
|
|
stmt->setBinary( 13, modelVec );
|
2017-10-10 00:03:24 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
stmt->setInt( 14, m_emoteMode ); // EmodeModeType
|
|
|
|
stmt->setInt( 15, 0 ); // Language
|
2017-10-10 00:03:24 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
stmt->setInt( 16, static_cast< uint32_t >( m_bNewGame ) );
|
|
|
|
stmt->setInt( 17, static_cast< uint32_t >( m_bNewAdventurer ) );
|
2017-10-10 00:03:24 +02:00
|
|
|
|
2018-12-02 15:32:22 +11:00
|
|
|
stmt->setInt( 18, m_territoryTypeId ); // TerritoryType
|
2018-11-06 10:36:45 +01:00
|
|
|
stmt->setInt( 19, m_territoryId ); // TerritoryId
|
2018-08-29 21:40:59 +02:00
|
|
|
stmt->setDouble( 20, m_pos.x );
|
|
|
|
stmt->setDouble( 21, m_pos.y );
|
|
|
|
stmt->setDouble( 22, m_pos.z );
|
|
|
|
stmt->setDouble( 23, getRot() );
|
2017-10-10 00:03:24 +02:00
|
|
|
|
2018-12-02 15:32:22 +11:00
|
|
|
stmt->setInt( 24, m_prevTerritoryTypeId ); // OTerritoryType
|
|
|
|
stmt->setInt( 25, m_prevTerritoryId ); // OTerritoryId
|
2018-08-29 21:40:59 +02:00
|
|
|
stmt->setDouble( 26, m_prevPos.x );
|
|
|
|
stmt->setDouble( 27, m_prevPos.y );
|
|
|
|
stmt->setDouble( 28, m_prevPos.z );
|
|
|
|
stmt->setDouble( 29, m_prevRot );
|
2017-10-10 00:03:24 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
stmt->setInt( 30, static_cast< uint8_t >( getClass() ) );
|
|
|
|
stmt->setInt( 31, static_cast< uint8_t >( getStatus() ) );
|
|
|
|
stmt->setInt( 32, m_playTime );
|
|
|
|
stmt->setInt( 33, m_homePoint );
|
2017-10-10 00:03:24 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
stmt->setBinary( 34, { 0, 0, 0 } ); // FavoritePoint
|
|
|
|
stmt->setInt( 35, 0 ); // RestPoint
|
|
|
|
stmt->setInt( 36, m_activeTitle ); // ActiveTitle
|
2017-10-10 00:03:24 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
std::vector< uint8_t > titleListVec( sizeof( m_titleList ) );
|
|
|
|
stmt->setBinary( 37, titleListVec );
|
2017-10-10 00:03:24 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
std::vector< uint8_t > achievementVec( 16 );
|
|
|
|
stmt->setBinary( 38, achievementVec );
|
2017-10-10 00:03:24 +02:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
std::vector< uint8_t > aetheryteVec( m_aetheryte.size() );
|
|
|
|
memcpy( aetheryteVec.data(), m_aetheryte.data(), m_aetheryte.size() );
|
2018-08-29 21:40:59 +02:00
|
|
|
stmt->setBinary( 39, aetheryteVec );
|
2017-10-10 00:03:24 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
std::vector< uint8_t > howToVec( sizeof( m_howTo ) );
|
2021-11-27 00:53:57 +01:00
|
|
|
memcpy( howToVec.data(), m_howTo.data(), m_howTo.size() );
|
2018-08-29 21:40:59 +02:00
|
|
|
stmt->setBinary( 40, howToVec );
|
2017-10-10 00:03:24 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
std::vector< uint8_t > minionsVec( sizeof( m_minions ) );
|
2021-11-27 00:53:57 +01:00
|
|
|
memcpy( minionsVec.data(), m_minions.data(), m_minions.size() );
|
2018-08-29 21:40:59 +02:00
|
|
|
stmt->setBinary( 41, minionsVec );
|
2017-10-10 00:03:24 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
std::vector< uint8_t > mountsVec( sizeof( m_mountGuide ) );
|
2021-11-27 00:53:57 +01:00
|
|
|
memcpy( mountsVec.data(), m_mountGuide.data(), m_mountGuide.size() );
|
2018-08-29 21:40:59 +02:00
|
|
|
stmt->setBinary( 42, mountsVec );
|
2017-10-10 00:03:24 +02:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
std::vector< uint8_t > orchestrionVec( m_orchestrion.size() );
|
|
|
|
memcpy( orchestrionVec.data(), m_orchestrion.data(), m_orchestrion.size() );
|
2018-08-29 21:40:59 +02:00
|
|
|
stmt->setBinary( 42, mountsVec );
|
2017-10-10 00:03:24 +02:00
|
|
|
|
2022-01-14 19:06:23 +01:00
|
|
|
stmt->setInt( 44, m_equippedMannequin ); // EquippedMannequin
|
2017-12-03 17:24:11 +01:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
stmt->setInt( 45, 0 ); // DisplayFlags
|
2021-11-27 00:53:57 +01:00
|
|
|
std::vector< uint8_t > questCompleteVec( m_questCompleteFlags.size() );
|
|
|
|
memcpy( questCompleteVec.data(), m_questCompleteFlags.data(), m_questCompleteFlags.size() );
|
2018-08-29 21:40:59 +02:00
|
|
|
stmt->setBinary( 46, questCompleteVec );
|
2017-10-10 00:03:24 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
stmt->setInt( 47, m_openingSequence );
|
2017-10-10 00:03:24 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
std::vector< uint8_t > questTrackerVec( sizeof( m_questTracking ) );
|
2021-11-27 00:53:57 +01:00
|
|
|
memcpy( questTrackerVec.data(), m_questTracking.data(), sizeof( m_questTracking ) );
|
2018-08-29 21:40:59 +02:00
|
|
|
stmt->setBinary( 48, questTrackerVec );
|
2017-10-10 00:03:24 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
stmt->setInt( 49, m_gc ); // DisplayFlags
|
2017-10-10 00:03:24 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
stmt->setBinary( 50, { m_gcRank[ 0 ], m_gcRank[ 1 ], m_gcRank[ 2 ] } );
|
2017-10-10 00:03:24 +02:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
std::vector< uint8_t > discoveryVec( m_discovery.size() );
|
|
|
|
memcpy( discoveryVec.data(), m_discovery.data(), m_discovery.size() );
|
2018-08-29 21:40:59 +02:00
|
|
|
stmt->setBinary( 51, discoveryVec );
|
2017-10-10 00:03:24 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
stmt->setInt( 52, m_gmRank );
|
2017-10-10 00:03:24 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
stmt->setInt( 53, m_equipDisplayFlags );
|
2018-05-17 20:46:11 +02:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
std::vector< uint8_t > unlockVec( m_unlocks.size() );
|
|
|
|
memcpy( unlockVec.data(), m_unlocks.data(), m_unlocks.size() );
|
2018-08-29 21:40:59 +02:00
|
|
|
stmt->setBinary( 54, unlockVec );
|
2017-10-10 00:03:24 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
stmt->setInt( 55, m_cfPenaltyUntil );
|
2017-10-10 00:03:24 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
stmt->setInt( 56, m_pose );
|
2018-07-11 23:52:24 +02:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
stmt->setUInt64( 57, m_characterId );
|
2017-10-10 00:03:24 +02:00
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
db.execute( stmt );
|
2017-10-18 20:49:37 +02:00
|
|
|
}
|
|
|
|
|
2018-11-29 16:55:48 +01:00
|
|
|
void Sapphire::Entity::Player::updateDbClass() const
|
2017-10-18 20:49:37 +02:00
|
|
|
{
|
2020-03-01 01:00:57 +11:00
|
|
|
auto& db = Common::Service< Db::DbWorkerPool< Db::ZoneDbConnection > >::ref();
|
2021-11-27 00:53:57 +01:00
|
|
|
auto& exdData = Common::Service< Data::ExdData >::ref();
|
2022-01-27 21:24:54 +01:00
|
|
|
uint8_t classJobIndex = exdData.getRow< Excel::ClassJob >( static_cast<uint8_t>( getClass() ) )->data().WorkIndex;
|
2018-08-29 21:40:59 +02:00
|
|
|
|
|
|
|
//Exp = ?, Lvl = ? WHERE CharacterId = ? AND ClassIdx = ?
|
2020-03-01 01:00:57 +11:00
|
|
|
auto stmtS = db.getPreparedStatement( Db::CHARA_CLASS_UP );
|
2018-08-29 21:40:59 +02:00
|
|
|
stmtS->setInt( 1, getExp() );
|
|
|
|
stmtS->setInt( 2, getLevel() );
|
2021-11-27 00:53:57 +01:00
|
|
|
stmtS->setUInt64( 3, m_characterId );
|
2018-08-29 21:40:59 +02:00
|
|
|
stmtS->setInt( 4, classJobIndex );
|
2020-03-01 01:00:57 +11:00
|
|
|
db.execute( stmtS );
|
2017-10-18 20:49:37 +02:00
|
|
|
}
|
|
|
|
|
2019-03-28 22:58:40 +01:00
|
|
|
void Sapphire::Entity::Player::updateDbMonsterNote()
|
|
|
|
{
|
2020-03-01 01:00:57 +11:00
|
|
|
auto& db = Common::Service< Db::DbWorkerPool< Db::ZoneDbConnection > >::ref();
|
2019-03-28 22:58:40 +01:00
|
|
|
// Category_0-11
|
2020-03-01 01:00:57 +11:00
|
|
|
auto stmt = db.getPreparedStatement( Db::CHARA_MONSTERNOTE_UP );
|
2019-03-28 22:58:40 +01:00
|
|
|
//std::array< std::vector< uint8_t >, 12 > vectors;
|
|
|
|
std::vector< uint8_t > vector( 41 );
|
2021-11-27 00:53:57 +01:00
|
|
|
for( uint8_t i = 0; i < m_huntingLogEntries.size(); ++i )
|
2019-03-28 22:58:40 +01:00
|
|
|
{
|
|
|
|
vector[ 0 ] = m_huntingLogEntries[ i ].rank;
|
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
memcpy( &vector[ 1 ], reinterpret_cast< uint8_t* >( m_huntingLogEntries[ i ].entries ), 40 );
|
2019-03-28 22:58:40 +01:00
|
|
|
stmt->setBinary( i + 1, vector );
|
|
|
|
}
|
2021-11-27 00:53:57 +01:00
|
|
|
stmt->setUInt64( 13, m_characterId );
|
|
|
|
db.execute( stmt );
|
|
|
|
}
|
|
|
|
|
|
|
|
void Sapphire::Entity::Player::updateDbFriendList()
|
|
|
|
{
|
|
|
|
auto& db = Common::Service< Db::DbWorkerPool< Db::ZoneDbConnection > >::ref();
|
|
|
|
|
|
|
|
auto stmt = db.getPreparedStatement( Db::CHARA_FRIENDLIST_UP );
|
|
|
|
|
|
|
|
std::vector< uint8_t > friendIds( 1600 );
|
2021-12-01 21:30:12 -03:00
|
|
|
std::vector< uint8_t > inviteIds( 1600 );
|
2021-11-27 00:53:57 +01:00
|
|
|
|
|
|
|
memcpy( friendIds.data(), m_friendList.data(), 1600 );
|
2021-12-01 21:30:12 -03:00
|
|
|
memcpy( inviteIds.data(), m_friendInviteList.data(), 1600 );
|
2021-11-27 00:53:57 +01:00
|
|
|
stmt->setBinary( 1, friendIds );
|
2021-12-01 21:30:12 -03:00
|
|
|
stmt->setBinary( 2, inviteIds );
|
2021-11-27 00:53:57 +01:00
|
|
|
stmt->setUInt64( 3, m_characterId );
|
2020-03-01 01:00:57 +11:00
|
|
|
db.execute( stmt );
|
2019-03-28 22:58:40 +01:00
|
|
|
}
|
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
|
2021-12-13 22:36:29 -03:00
|
|
|
void Sapphire::Entity::Player::updateDbBlacklist()
|
|
|
|
{
|
|
|
|
auto& db = Common::Service< Db::DbWorkerPool< Db::ZoneDbConnection > >::ref();
|
|
|
|
|
|
|
|
auto stmt = db.getPreparedStatement( Db::CHARA_BLACKLIST_UP );
|
|
|
|
|
|
|
|
std::vector< uint8_t > blIds( 1600 );
|
|
|
|
|
|
|
|
memcpy( blIds.data(), m_blacklist.data(), 1600 );
|
|
|
|
stmt->setBinary( 1, blIds );
|
|
|
|
stmt->setUInt64( 2, m_characterId );
|
|
|
|
db.execute( stmt );
|
|
|
|
}
|
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
void Sapphire::Entity::Player::insertDbClass( const uint8_t classJobIndex, uint8_t level ) const
|
2017-12-16 23:00:04 +11:00
|
|
|
{
|
2020-03-01 01:00:57 +11:00
|
|
|
auto& db = Common::Service< Db::DbWorkerPool< Db::ZoneDbConnection > >::ref();
|
|
|
|
auto stmtClass = db.getPreparedStatement( Db::CHARA_CLASS_INS );
|
2021-11-27 00:53:57 +01:00
|
|
|
stmtClass->setUInt64( 1, m_characterId );
|
2018-08-29 21:40:59 +02:00
|
|
|
stmtClass->setInt( 2, classJobIndex );
|
|
|
|
stmtClass->setInt( 3, 0 );
|
2021-11-27 00:53:57 +01:00
|
|
|
stmtClass->setInt( 4, level );
|
2020-03-01 01:00:57 +11:00
|
|
|
db.directExecute( stmtClass );
|
2017-12-16 23:00:04 +11:00
|
|
|
}
|
|
|
|
|
2018-11-29 16:55:48 +01:00
|
|
|
void Sapphire::Entity::Player::updateDbSearchInfo() const
|
2017-10-18 20:49:37 +02:00
|
|
|
{
|
2020-03-01 01:00:57 +11:00
|
|
|
auto& db = Common::Service< Db::DbWorkerPool< Db::ZoneDbConnection > >::ref();
|
|
|
|
auto stmtS = db.getPreparedStatement( Db::CHARA_SEARCHINFO_UP_SELECTCLASS );
|
2018-08-29 21:40:59 +02:00
|
|
|
stmtS->setInt( 1, m_searchSelectClass );
|
2021-11-27 00:53:57 +01:00
|
|
|
stmtS->setUInt64( 2, m_characterId );
|
2020-03-01 01:00:57 +11:00
|
|
|
db.execute( stmtS );
|
2018-08-29 21:40:59 +02:00
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
auto stmtS1 = db.getPreparedStatement( Db::CHARA_SEARCHINFO_UP_SELECTREGION );
|
2018-08-29 21:40:59 +02:00
|
|
|
stmtS1->setInt( 1, m_searchSelectRegion );
|
2021-11-27 00:53:57 +01:00
|
|
|
stmtS1->setUInt64( 2, m_characterId );
|
2020-03-01 01:00:57 +11:00
|
|
|
db.execute( stmtS1 );
|
2018-08-29 21:40:59 +02:00
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
auto stmtS2 = db.getPreparedStatement( Db::CHARA_SEARCHINFO_UP_SEARCHCOMMENT );
|
2018-09-26 08:47:22 -04:00
|
|
|
stmtS2->setString( 1, std::string( m_searchMessage ) );
|
2021-11-27 00:53:57 +01:00
|
|
|
stmtS2->setUInt64( 2, m_characterId );
|
2020-03-01 01:00:57 +11:00
|
|
|
db.execute( stmtS2 );
|
2017-10-15 01:43:57 +02:00
|
|
|
}
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2018-11-29 16:55:48 +01:00
|
|
|
void Sapphire::Entity::Player::updateDbAllQuests() const
|
2017-10-15 01:43:57 +02:00
|
|
|
{
|
2020-03-01 01:00:57 +11:00
|
|
|
auto& db = Common::Service< Db::DbWorkerPool< Db::ZoneDbConnection > >::ref();
|
2018-08-29 21:40:59 +02:00
|
|
|
for( int32_t i = 0; i < 30; i++ )
|
|
|
|
{
|
2021-11-27 00:53:57 +01:00
|
|
|
if( m_quests[ i ].getId() == 0 )
|
2018-08-29 21:40:59 +02:00
|
|
|
continue;
|
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
auto stmtS3 = db.getPreparedStatement( Db::CHARA_QUEST_UP );
|
2021-11-27 00:53:57 +01:00
|
|
|
stmtS3->setInt( 1, m_quests[ i ].getSeq() );
|
|
|
|
stmtS3->setInt( 2, m_quests[ i ].getFlags() );
|
|
|
|
stmtS3->setInt( 3, m_quests[ i ].getUI8A() );
|
|
|
|
stmtS3->setInt( 4, m_quests[ i ].getUI8B() );
|
|
|
|
stmtS3->setInt( 5, m_quests[ i ].getUI8C() );
|
|
|
|
stmtS3->setInt( 6, m_quests[ i ].getUI8D() );
|
|
|
|
stmtS3->setInt( 7, m_quests[ i ].getUI8E() );
|
|
|
|
stmtS3->setInt( 8, m_quests[ i ].getUI8F() );
|
|
|
|
// todo: do we remove this col from the db? was padding but now unused in 2.x
|
|
|
|
stmtS3->setInt( 9, 0 );
|
|
|
|
stmtS3->setUInt64( 10, m_characterId );
|
|
|
|
stmtS3->setInt( 11, m_quests[ i ].getId() );
|
2020-03-01 01:00:57 +11:00
|
|
|
db.execute( stmtS3 );
|
2018-08-29 21:40:59 +02:00
|
|
|
|
|
|
|
}
|
2017-10-15 01:43:57 +02:00
|
|
|
}
|
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
void Sapphire::Entity::Player::deleteDbQuest( uint16_t questId ) const
|
2017-10-15 01:43:57 +02:00
|
|
|
{
|
2020-03-01 01:00:57 +11:00
|
|
|
auto& db = Common::Service< Db::DbWorkerPool< Db::ZoneDbConnection > >::ref();
|
|
|
|
auto stmt = db.getPreparedStatement( Db::CHARA_QUEST_DEL );
|
2021-11-27 00:53:57 +01:00
|
|
|
stmt->setUInt64( 1, m_characterId );
|
2018-08-29 21:40:59 +02:00
|
|
|
stmt->setInt( 2, questId );
|
2020-03-01 01:00:57 +11:00
|
|
|
db.execute( stmt );
|
2017-10-15 01:43:57 +02:00
|
|
|
}
|
2017-08-08 13:53:47 +02:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
void Sapphire::Entity::Player::insertDbQuest( uint16_t questId, uint8_t index, uint8_t seq ) const
|
2017-10-15 01:43:57 +02:00
|
|
|
{
|
2020-03-01 01:00:57 +11:00
|
|
|
auto& db = Common::Service< Db::DbWorkerPool< Db::ZoneDbConnection > >::ref();
|
|
|
|
auto stmt = db.getPreparedStatement( Db::CHARA_QUEST_INS );
|
2021-11-27 00:53:57 +01:00
|
|
|
stmt->setUInt64( 1, m_characterId );
|
2018-08-29 21:40:59 +02:00
|
|
|
stmt->setInt( 2, index );
|
|
|
|
stmt->setInt( 3, questId );
|
|
|
|
stmt->setInt( 4, seq );
|
|
|
|
stmt->setInt( 5, 0 );
|
|
|
|
stmt->setInt( 6, 0 );
|
|
|
|
stmt->setInt( 7, 0 );
|
|
|
|
stmt->setInt( 8, 0 );
|
|
|
|
stmt->setInt( 9, 0 );
|
|
|
|
stmt->setInt( 10, 0 );
|
|
|
|
stmt->setInt( 11, 0 );
|
|
|
|
stmt->setInt( 12, 0 );
|
2020-03-01 01:00:57 +11:00
|
|
|
db.execute( stmt );
|
2017-12-05 11:21:56 +01:00
|
|
|
}
|
2018-07-24 23:58:08 +02:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
void Sapphire::Entity::Player::insertDbQuest( const World::Quest& quest, uint8_t index ) const
|
|
|
|
{
|
|
|
|
auto& db = Common::Service< Db::DbWorkerPool< Db::ZoneDbConnection > >::ref();
|
|
|
|
auto stmt = db.getPreparedStatement( Db::CHARA_QUEST_INS );
|
|
|
|
stmt->setUInt64( 1, m_characterId );
|
|
|
|
stmt->setInt( 2, index );
|
|
|
|
stmt->setInt( 3, quest.getId() );
|
|
|
|
stmt->setInt( 4, quest.getSeq() );
|
|
|
|
stmt->setInt( 5, quest.getFlags() );
|
|
|
|
stmt->setInt( 6, quest.getUI8A() );
|
|
|
|
stmt->setInt( 7, quest.getUI8B() );
|
|
|
|
stmt->setInt( 8, quest.getUI8C() );
|
|
|
|
stmt->setInt( 9, quest.getUI8D() );
|
|
|
|
stmt->setInt( 10, quest.getUI8E() );
|
|
|
|
stmt->setInt( 11, quest.getUI8F() );
|
|
|
|
stmt->setInt( 12, 0 );
|
|
|
|
db.execute( stmt );
|
|
|
|
}
|
|
|
|
|
|
|
|
Sapphire::ItemPtr Sapphire::Entity::Player::createItem( uint32_t catalogId, uint32_t quantity )
|
2018-07-24 23:58:08 +02:00
|
|
|
{
|
2021-11-27 00:53:57 +01:00
|
|
|
auto& exdData = Common::Service< Data::ExdData >::ref();
|
|
|
|
auto& db = Common::Service< Db::DbWorkerPool< Db::ZoneDbConnection > >::ref();
|
|
|
|
auto& itemMgr = Common::Service< World::Manager::ItemMgr >::ref();
|
2020-03-01 01:00:57 +11:00
|
|
|
|
2022-01-27 21:24:54 +01:00
|
|
|
auto itemInfo = exdData.getRow< Excel::Item >( catalogId );
|
2018-07-24 23:58:08 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
if( !itemInfo )
|
|
|
|
return nullptr;
|
2018-07-24 23:58:08 +02:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
uint8_t flags = 0;
|
2018-07-24 23:58:08 +02:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
ItemPtr pItem = make_Item( itemMgr.getNextUId(), catalogId );
|
2018-07-24 23:58:08 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
pItem->setStackSize( quantity );
|
2018-07-24 23:58:08 +02:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
db.execute( "INSERT INTO charaglobalitem ( CharacterId, itemId, catalogId, stack, flags ) VALUES ( " +
|
|
|
|
std::to_string( m_characterId ) + ", " +
|
|
|
|
std::to_string( pItem->getUId() ) + ", " +
|
|
|
|
std::to_string( pItem->getId() ) + ", " +
|
|
|
|
std::to_string( quantity ) + ", " +
|
|
|
|
std::to_string( flags ) + ");" );
|
2018-07-24 23:58:08 +02:00
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
return pItem;
|
2020-06-28 09:27:00 +09:00
|
|
|
}
|
|
|
|
|
2018-11-29 16:55:48 +01:00
|
|
|
bool Sapphire::Entity::Player::loadInventory()
|
2018-07-24 23:58:08 +02:00
|
|
|
{
|
2020-03-01 01:00:57 +11:00
|
|
|
auto& itemMgr = Common::Service< World::Manager::ItemMgr >::ref();
|
|
|
|
auto& db = Common::Service< Db::DbWorkerPool< Db::ZoneDbConnection > >::ref();
|
2018-08-29 21:40:59 +02:00
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// load active gearset
|
2020-03-01 01:00:57 +11:00
|
|
|
auto res = db.query( "SELECT storageId, container_0, container_1, container_2, container_3, "
|
2018-08-29 21:40:59 +02:00
|
|
|
"container_4, container_5, container_6, container_7, "
|
|
|
|
"container_8, container_9, container_10, container_11, "
|
|
|
|
"container_12, container_13 "
|
|
|
|
"FROM charaitemgearset " \
|
2021-11-27 00:53:57 +01:00
|
|
|
"WHERE CharacterId = " + std::to_string( m_characterId ) + " " \
|
2018-07-24 23:58:08 +02:00
|
|
|
"ORDER BY storageId ASC;" );
|
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
while( res->next() )
|
|
|
|
{
|
|
|
|
uint16_t storageId = res->getUInt16( 1 );
|
|
|
|
|
2018-10-15 21:38:39 +03:00
|
|
|
for( uint32_t i = 1; i <= 14; i++ )
|
2018-08-29 21:40:59 +02:00
|
|
|
{
|
|
|
|
uint64_t uItemId = res->getUInt64( i + 1 );
|
|
|
|
if( uItemId == 0 )
|
|
|
|
continue;
|
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
ItemPtr pItem = itemMgr.loadItem( uItemId );
|
2018-08-29 21:40:59 +02:00
|
|
|
|
|
|
|
if( pItem == nullptr )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
m_storageMap[ storageId ]->getItemMap()[ i - 1 ] = pItem;
|
2021-11-27 00:53:57 +01:00
|
|
|
//equipItem( static_cast< GearSetSlot >( i - 1 ), pItem, false );
|
2018-08-29 21:40:59 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Load everything
|
2020-03-01 01:00:57 +11:00
|
|
|
auto bagRes = db.query( "SELECT storageId, "
|
2018-08-29 21:40:59 +02:00
|
|
|
"container_0, container_1, container_2, container_3, container_4, "
|
|
|
|
"container_5, container_6, container_7, container_8, container_9, "
|
|
|
|
"container_10, container_11, container_12, container_13, container_14, "
|
|
|
|
"container_15, container_16, container_17, container_18, container_19, "
|
|
|
|
"container_20, container_21, container_22, container_23, container_24, "
|
|
|
|
"container_25, container_26, container_27, container_28, container_29, "
|
|
|
|
"container_30, container_31, container_32, container_33, container_34 "
|
|
|
|
"FROM charaiteminventory " \
|
2021-11-27 00:53:57 +01:00
|
|
|
"WHERE CharacterId = " + std::to_string( m_characterId ) + " " \
|
2018-07-24 23:58:08 +02:00
|
|
|
"ORDER BY storageId ASC;" );
|
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
while( bagRes->next() )
|
|
|
|
{
|
|
|
|
uint16_t storageId = bagRes->getUInt16( 1 );
|
|
|
|
for( uint32_t i = 1; i <= m_storageMap[ storageId ]->getMaxSize(); i++ )
|
|
|
|
{
|
|
|
|
uint64_t uItemId = bagRes->getUInt64( i + 1 );
|
|
|
|
if( uItemId == 0 )
|
|
|
|
continue;
|
2018-07-24 23:58:08 +02:00
|
|
|
|
2020-03-01 01:00:57 +11:00
|
|
|
ItemPtr pItem = itemMgr.loadItem( uItemId );
|
2018-07-24 23:58:08 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
if( pItem == nullptr )
|
|
|
|
continue;
|
2018-07-24 23:58:08 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
m_storageMap[ storageId ]->getItemMap()[ i - 1 ] = pItem;
|
|
|
|
}
|
|
|
|
}
|
2018-07-24 23:58:08 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
return true;
|
2018-07-24 23:58:08 +02:00
|
|
|
}
|
2021-11-27 00:53:57 +01:00
|
|
|
|
2021-12-13 22:36:29 -03:00
|
|
|
bool Sapphire::Entity::Player::loadFriendList()
|
2021-11-27 00:53:57 +01:00
|
|
|
{
|
|
|
|
auto& db = Common::Service< Db::DbWorkerPool< Db::ZoneDbConnection > >::ref();
|
|
|
|
auto stmt = db.getPreparedStatement( Db::ZoneDbStatements::CHARA_FRIENDLIST_SEL );
|
|
|
|
stmt->setUInt64( 1, m_characterId );
|
|
|
|
auto res = db.query( stmt );
|
|
|
|
|
|
|
|
if( !res->next() )
|
|
|
|
{
|
|
|
|
Logger::error( "Failed to load friendlist data for character#{}", m_characterId );
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto friendList = res->getBlobVector( "CharacterIdList" );
|
|
|
|
auto friendInviteList = res->getBlobVector( "InviteDataList" );
|
|
|
|
|
|
|
|
if( !friendList.empty() )
|
|
|
|
std::memcpy( m_friendList.data(), friendList.data(), friendList.size() );
|
|
|
|
|
|
|
|
if( !friendInviteList.empty() )
|
|
|
|
std::memcpy( m_friendInviteList.data(), friendInviteList.data(), friendInviteList.size() );
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-12-13 22:36:29 -03:00
|
|
|
bool Sapphire::Entity::Player::loadBlacklist()
|
|
|
|
{
|
|
|
|
auto& db = Common::Service< Db::DbWorkerPool< Db::ZoneDbConnection > >::ref();
|
|
|
|
auto stmt = db.getPreparedStatement( Db::ZoneDbStatements::CHARA_BLACKLIST_SEL );
|
|
|
|
stmt->setUInt64( 1, m_characterId );
|
|
|
|
auto res = db.query( stmt );
|
|
|
|
|
|
|
|
if( !res->next() )
|
|
|
|
{
|
|
|
|
Logger::error( "Failed to load blacklist data for character#{}", m_characterId );
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto blacklist = res->getBlobVector( "CharacterIdList" );
|
|
|
|
|
|
|
|
if( !blacklist.empty() )
|
|
|
|
std::memcpy( m_blacklist.data(), blacklist.data(), blacklist.size() );
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-11-27 00:53:57 +01:00
|
|
|
bool Sapphire::Entity::Player::syncLastDBWrite()
|
|
|
|
{
|
|
|
|
auto& db = Common::Service< Db::DbWorkerPool< Db::ZoneDbConnection > >::ref();
|
|
|
|
auto res = db.query( "SELECT UNIX_TIMESTAMP(UPDATE_DATE) FROM charainfo WHERE characterid = " + std::to_string( m_characterId ) );
|
|
|
|
|
|
|
|
if( !res->next() )
|
|
|
|
{
|
|
|
|
Logger::error( "Failed to load update date for character#{}", m_characterId );
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto lastWrite = res->getUInt64( 1 );
|
|
|
|
|
|
|
|
m_lastDBWrite = lastWrite;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|