1
Fork 0
mirror of https://github.com/SapphireServer/Sapphire.git synced 2025-05-05 10:17:46 +00:00

Merge pull request #909 from hkAlice/achievos

[3.x] save achievement to sql db;
This commit is contained in:
Mordred 2023-03-06 10:12:53 +01:00 committed by GitHub
commit aead026960
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 153 additions and 31 deletions

View file

@ -485,7 +485,7 @@ void Mysql::PreparedStatement::setInt( uint32_t parameterIndex, int32_t value )
void Mysql::PreparedStatement::setUInt( uint32_t parameterIndex, uint32_t value ) void Mysql::PreparedStatement::setUInt( uint32_t parameterIndex, uint32_t value )
{ {
if( parameterIndex == 0 || parameterIndex > m_paramCount ) if( parameterIndex == 0 || parameterIndex > m_paramCount )
throw std::runtime_error( "PreparedStatement::setInt: invalid 'parameterIndex'" ); throw std::runtime_error( "PreparedStatement::setUInt: invalid 'parameterIndex'" );
--parameterIndex; --parameterIndex;
{ {
@ -546,7 +546,7 @@ void Mysql::PreparedStatement::setInt64( uint32_t parameterIndex, int64_t value
void Mysql::PreparedStatement::setUInt64( uint32_t parameterIndex, uint64_t value ) void Mysql::PreparedStatement::setUInt64( uint32_t parameterIndex, uint64_t value )
{ {
if( parameterIndex == 0 || parameterIndex > m_paramCount ) if( parameterIndex == 0 || parameterIndex > m_paramCount )
throw std::runtime_error( "PreparedStatement::setInt64: invalid 'parameterIndex'" ); throw std::runtime_error( "PreparedStatement::setUInt64: invalid 'parameterIndex'" );
--parameterIndex; --parameterIndex;
{ {

View file

@ -0,0 +1,10 @@
CREATE TABLE IF NOT EXISTS charainfoachievement (
`CharacterId` BIGINT(20) NOT NULL,
`UnlockList` blob,
`ProgressData` blob,
`HistoryList` blob,
`IS_DELETE` int(3) DEFAULT 0,
`IS_NOT_ACTIVE_FLG` int(3) DEFAULT 0,
`UPDATE_DATE` datetime,
PRIMARY KEY (`CharacterId`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

View file

@ -0,0 +1 @@
ALTER TABLE `charainfo` DROP `Achievement`;

View file

@ -286,6 +286,19 @@ void PlayerMinimal::saveAsNew()
stmtBlacklist->setBinary( 2, blIds ); stmtBlacklist->setBinary( 2, blIds );
g_charaDb.directExecute( stmtBlacklist ); g_charaDb.directExecute( stmtBlacklist );
// Achievement related
auto stmtAchv = g_charaDb.getPreparedStatement( Db::ZoneDbStatements::CHARA_ACHIEV_INS );
std::vector< uint8_t > unlock( 2048 / 8, 0 );
std::vector< uint8_t > progressData( 8, 0 );
std::vector< uint8_t > history( 5 * 4, 0 );
stmtAchv->setUInt64( 1, m_characterId );
stmtAchv->setBinary( 2, unlock );
stmtAchv->setBinary( 3, progressData );
stmtAchv->setBinary( 4, history );
g_charaDb.directExecute( stmtAchv );
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// SET UP INVENTORIES /// SET UP INVENTORIES
createInvDbContainer( InventoryType::Bag0 ); createInvDbContainer( InventoryType::Bag0 );

View file

@ -29,7 +29,7 @@ void Sapphire::Db::ZoneDbConnection::doPrepareStatements()
"IsNewAdventurer, TerritoryType, TerritoryId, PosX, PosY, PosZ, PosR, " "IsNewAdventurer, TerritoryType, TerritoryId, PosX, PosY, PosZ, PosR, "
"OTerritoryType, OTerritoryId, OPosX, OPosY, OPosZ, OPosR, GuardianDeity, " "OTerritoryType, OTerritoryId, OPosX, OPosY, OPosZ, OPosR, GuardianDeity, "
"BirthDay, BirthMonth, Class, Status, TotalPlayTime, FirstClass, HomePoint, " "BirthDay, BirthMonth, Class, Status, TotalPlayTime, FirstClass, HomePoint, "
"FavoritePoint, RestPoint, StartTown, ActiveTitle, TitleList, Achievement, " "FavoritePoint, RestPoint, StartTown, ActiveTitle, TitleList, "
"Aetheryte, HowTo, Minions, Mounts, Orchestrion, EquippedMannequin, ConfigFlags, " "Aetheryte, HowTo, Minions, Mounts, Orchestrion, EquippedMannequin, ConfigFlags, "
"QuestCompleteFlags, OpeningSequence, QuestTracking, GrandCompany, " "QuestCompleteFlags, OpeningSequence, QuestTracking, GrandCompany, "
"GrandCompanyRank, Discovery, GMRank, EquipDisplayFlags, Unlocks, CFPenaltyUntil, " "GrandCompanyRank, Discovery, GMRank, EquipDisplayFlags, Unlocks, CFPenaltyUntil, "
@ -46,7 +46,7 @@ void Sapphire::Db::ZoneDbConnection::doPrepareStatements()
"TerritoryType = ?, TerritoryId = ?, PosX = ?, PosY = ?, PosZ = ?, PosR = ?, " "TerritoryType = ?, TerritoryId = ?, PosX = ?, PosY = ?, PosZ = ?, PosR = ?, "
"OTerritoryType = ?, OTerritoryId = ?, OPosX = ?, OPosY = ?, OPosZ = ?, OPosR = ?, " "OTerritoryType = ?, OTerritoryId = ?, OPosX = ?, OPosY = ?, OPosZ = ?, OPosR = ?, "
"Class = ?, Status = ?, TotalPlayTime = ?, HomePoint = ?, FavoritePoint = ?, RestPoint = ?, " "Class = ?, Status = ?, TotalPlayTime = ?, HomePoint = ?, FavoritePoint = ?, RestPoint = ?, "
"ActiveTitle = ?, TitleList = ?, Achievement = ?, Aetheryte = ?, HowTo = ?, Minions = ?, Mounts = ?, Orchestrion = ?, " "ActiveTitle = ?, TitleList = ?, Aetheryte = ?, HowTo = ?, Minions = ?, Mounts = ?, Orchestrion = ?, "
"EquippedMannequin = ?, ConfigFlags = ?, QuestCompleteFlags = ?, OpeningSequence = ?, " "EquippedMannequin = ?, ConfigFlags = ?, QuestCompleteFlags = ?, OpeningSequence = ?, "
"QuestTracking = ?, GrandCompany = ?, GrandCompanyRank = ?, Discovery = ?, GMRank = ?, EquipDisplayFlags = ?, Unlocks = ?, " "QuestTracking = ?, GrandCompany = ?, GrandCompanyRank = ?, Discovery = ?, GMRank = ?, EquipDisplayFlags = ?, Unlocks = ?, "
"CFPenaltyUntil = ?, Pose = ? WHERE CharacterId = ?;", "CFPenaltyUntil = ?, Pose = ? WHERE CharacterId = ?;",
@ -107,8 +107,6 @@ void Sapphire::Db::ZoneDbConnection::doPrepareStatements()
CONNECTION_ASYNC ); CONNECTION_ASYNC );
prepareStatement( CHARA_UP_TITLE, "UPDATE charainfo SET ActiveTitle = ? WHERE CharacterId = ?;", CONNECTION_ASYNC ); prepareStatement( CHARA_UP_TITLE, "UPDATE charainfo SET ActiveTitle = ? WHERE CharacterId = ?;", CONNECTION_ASYNC );
prepareStatement( CHARA_UP_TITLELIST, "UPDATE charainfo SET TitleList = ? WHERE CharacterId = ?;", CONNECTION_ASYNC ); prepareStatement( CHARA_UP_TITLELIST, "UPDATE charainfo SET TitleList = ? WHERE CharacterId = ?;", CONNECTION_ASYNC );
prepareStatement( CHARA_UP_ACHIEVEMENTS, "UPDATE charainfo SET Achievement = ? WHERE CharacterId = ?;",
CONNECTION_ASYNC );
prepareStatement( CHARA_UP_AETHERYTE, "UPDATE charainfo SET Aetheryte = ? WHERE CharacterId = ?;", CONNECTION_ASYNC ); prepareStatement( CHARA_UP_AETHERYTE, "UPDATE charainfo SET Aetheryte = ? WHERE CharacterId = ?;", CONNECTION_ASYNC );
prepareStatement( CHARA_UP_HOWTO, "UPDATE charainfo SET HowTo = ? WHERE CharacterId = ?;", CONNECTION_ASYNC ); prepareStatement( CHARA_UP_HOWTO, "UPDATE charainfo SET HowTo = ? WHERE CharacterId = ?;", CONNECTION_ASYNC );
prepareStatement( CHARA_UP_MINIONS, "UPDATE charainfo SET Minions = ? WHERE CharacterId = ?;", CONNECTION_ASYNC ); prepareStatement( CHARA_UP_MINIONS, "UPDATE charainfo SET Minions = ? WHERE CharacterId = ?;", CONNECTION_ASYNC );
@ -224,6 +222,24 @@ void Sapphire::Db::ZoneDbConnection::doPrepareStatements()
"WHERE CharacterId = ?;", "WHERE CharacterId = ?;",
CONNECTION_SYNC ); CONNECTION_SYNC );
/// CHARA ACHIEVEMENT
prepareStatement( CHARA_ACHIEV_INS,
"INSERT INTO charainfoachievement ( CharacterId, UnlockList, ProgressData, HistoryList, UPDATE_DATE ) "
" VALUES ( ?, ?, ?, ?, NOW() );",
CONNECTION_SYNC );
prepareStatement( CHARA_ACHIEV_UP, "UPDATE charainfoachievement "
" SET UnlockList = ?,"
" ProgressData = ?,"
" HistoryList = ?"
" WHERE CharacterId = ?;",
CONNECTION_ASYNC );
prepareStatement( CHARA_ACHIEV_SEL, "SELECT UnlockList, ProgressData, HistoryList FROM charainfoachievement "
"WHERE CharacterId = ?;",
CONNECTION_SYNC );
/// CHARA FRIENDLIST /// CHARA FRIENDLIST
prepareStatement( CHARA_FRIENDLIST_INS, prepareStatement( CHARA_FRIENDLIST_INS,
"INSERT INTO charainfofriendlist ( CharacterId, CharacterIdList, InviteDataList, UPDATE_DATE ) " "INSERT INTO charainfofriendlist ( CharacterId, CharacterIdList, InviteDataList, UPDATE_DATE ) "
@ -240,7 +256,7 @@ void Sapphire::Db::ZoneDbConnection::doPrepareStatements()
"WHERE CharacterId = ?;", "WHERE CharacterId = ?;",
CONNECTION_SYNC ); CONNECTION_SYNC );
/// CHARA FRIENDLIST /// CHARA BLACKLIST
prepareStatement( CHARA_BLACKLIST_INS, prepareStatement( CHARA_BLACKLIST_INS,
"INSERT INTO charainfoblacklist ( CharacterId, CharacterIdList, UPDATE_DATE ) " "INSERT INTO charainfoblacklist ( CharacterId, CharacterIdList, UPDATE_DATE ) "
" VALUES ( ?, ?, NOW() );", " VALUES ( ?, ?, NOW() );",

View file

@ -38,7 +38,6 @@ namespace Sapphire::Db
CHARA_UP_FAVOPOINT, CHARA_UP_FAVOPOINT,
CHARA_UP_TITLE, CHARA_UP_TITLE,
CHARA_UP_TITLELIST, CHARA_UP_TITLELIST,
CHARA_UP_ACHIEVEMENTS,
CHARA_UP_AETHERYTE, CHARA_UP_AETHERYTE,
CHARA_UP_HOWTO, CHARA_UP_HOWTO,
CHARA_UP_MINIONS, CHARA_UP_MINIONS,
@ -89,6 +88,10 @@ namespace Sapphire::Db
CHARA_BLACKLIST_UP, CHARA_BLACKLIST_UP,
CHARA_BLACKLIST_SEL, CHARA_BLACKLIST_SEL,
CHARA_ACHIEV_INS,
CHARA_ACHIEV_UP,
CHARA_ACHIEV_SEL,
CHARA_LINKSHELL_INS, CHARA_LINKSHELL_INS,
ZONE_SEL_BNPCS, ZONE_SEL_BNPCS,

View file

@ -545,6 +545,9 @@ namespace Sapphire::Entity
/*! unload player from logout */ /*! unload player from logout */
void unload(); void unload();
/*! load achievement data */
bool loadAchievements();
/*! load active class data */ /*! load active class data */
bool loadClassData(); bool loadClassData();
@ -672,6 +675,8 @@ namespace Sapphire::Entity
void updateDbBlacklist(); void updateDbBlacklist();
void updateDbAchievement();
void updateDbChara() const; void updateDbChara() const;
/////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////

View file

@ -144,7 +144,7 @@ bool Sapphire::Entity::Player::loadFromDb( uint64_t characterId )
res->free(); res->free();
if( !loadActiveQuests() || !loadClassData() || !loadSearchInfo() || !loadHuntingLog() || !loadFriendList() || !loadBlacklist() ) if( !loadActiveQuests() || !loadClassData() || !loadSearchInfo() || !loadHuntingLog() || !loadFriendList() || !loadBlacklist() || !loadAchievements() )
{ {
Logger::error( "chara#{0} data corrupt!", m_characterId ); Logger::error( "chara#{0} data corrupt!", m_characterId );
} }
@ -212,6 +212,49 @@ bool Sapphire::Entity::Player::loadActiveQuests()
} }
bool Sapphire::Entity::Player::loadAchievements()
{
auto& db = Common::Service< Db::DbWorkerPool< Db::ZoneDbConnection > >::ref();
auto stmt = db.getPreparedStatement( Db::ZoneDbStatements::CHARA_ACHIEV_SEL );
stmt->setUInt64( 1, m_characterId );
auto res = db.query( stmt );
while( res->next() )
{
auto unlock = res->getBlobVector( "UnlockList" );
auto progressData = res->getBlobVector( "ProgressData" );
auto history = res->getBlobVector( "HistoryList" );
// todo: throw this in util (used in LS etc)
auto func = []( std::unordered_map< uint32_t, uint32_t >& outData, std::vector< char >& inData )
{
if( !inData.empty() )
{
size_t entryCount = inData.size() / sizeof( uint32_t );
for( auto i = 0; i < entryCount; ++i )
{
auto key = *reinterpret_cast< const uint32_t* >( &inData[ i * 4 ] );
i += 1;
auto val = *reinterpret_cast< const uint32_t* >( &inData[ i * 4 ] );
outData[ key ] = val;
}
}
};
std::unordered_map< uint32_t, uint32_t > progressMap;
func( progressMap, progressData );
memcpy( reinterpret_cast< char* >( m_achievementData.unlockList.data() ), unlock.data(), unlock.size() );
m_achievementData.progressData = progressMap;
memcpy( reinterpret_cast< char* >( m_achievementData.history.data() ), history.data(), history.size() );
}
return true;
}
bool Sapphire::Entity::Player::loadClassData() bool Sapphire::Entity::Player::loadClassData()
{ {
auto& db = Common::Service< Db::DbWorkerPool< Db::ZoneDbConnection > >::ref(); auto& db = Common::Service< Db::DbWorkerPool< Db::ZoneDbConnection > >::ref();
@ -304,6 +347,9 @@ void Sapphire::Entity::Player::updateSql()
////// Blacklist ////// Blacklist
updateDbBlacklist(); updateDbBlacklist();
////// Achievement
updateDbAchievement();
///// Store last write ///// Store last write
syncLastDBWrite(); syncLastDBWrite();
} }
@ -377,63 +423,61 @@ void Sapphire::Entity::Player::updateDbChara() const
std::vector< uint8_t > titleListVec( sizeof( m_titleList ) ); std::vector< uint8_t > titleListVec( sizeof( m_titleList ) );
stmt->setBinary( 37, titleListVec ); stmt->setBinary( 37, titleListVec );
std::vector< uint8_t > achievementVec( 16 );
stmt->setBinary( 38, achievementVec );
std::vector< uint8_t > aetheryteVec( m_aetheryte.size() ); std::vector< uint8_t > aetheryteVec( m_aetheryte.size() );
memcpy( aetheryteVec.data(), m_aetheryte.data(), m_aetheryte.size() ); memcpy( aetheryteVec.data(), m_aetheryte.data(), m_aetheryte.size() );
stmt->setBinary( 39, aetheryteVec ); stmt->setBinary( 38, aetheryteVec );
std::vector< uint8_t > howToVec( sizeof( m_howTo ) ); std::vector< uint8_t > howToVec( sizeof( m_howTo ) );
memcpy( howToVec.data(), m_howTo.data(), m_howTo.size() ); memcpy( howToVec.data(), m_howTo.data(), m_howTo.size() );
stmt->setBinary( 40, howToVec ); stmt->setBinary( 39, howToVec );
std::vector< uint8_t > minionsVec( sizeof( m_minionGuide ) ); std::vector< uint8_t > minionsVec( sizeof( m_minionGuide ) );
memcpy( minionsVec.data(), m_minionGuide.data(), m_minionGuide.size() ); memcpy( minionsVec.data(), m_minionGuide.data(), m_minionGuide.size() );
stmt->setBinary( 41, minionsVec ); stmt->setBinary( 40, minionsVec );
std::vector< uint8_t > mountsVec( sizeof( m_mountGuide ) ); std::vector< uint8_t > mountsVec( sizeof( m_mountGuide ) );
memcpy( mountsVec.data(), m_mountGuide.data(), m_mountGuide.size() ); memcpy( mountsVec.data(), m_mountGuide.data(), m_mountGuide.size() );
stmt->setBinary( 42, mountsVec ); stmt->setBinary( 41, mountsVec );
std::vector< uint8_t > orchestrionVec( m_orchestrion.size() ); std::vector< uint8_t > orchestrionVec( m_orchestrion.size() );
memcpy( orchestrionVec.data(), m_orchestrion.data(), m_orchestrion.size() ); memcpy( orchestrionVec.data(), m_orchestrion.data(), m_orchestrion.size() );
stmt->setBinary( 42, mountsVec ); stmt->setBinary( 42, orchestrionVec );
stmt->setInt( 44, m_equippedMannequin ); // EquippedMannequin stmt->setInt( 43, m_equippedMannequin ); // EquippedMannequin
stmt->setInt( 45, 0 ); // DisplayFlags stmt->setInt( 44, 0 ); // DisplayFlags
std::vector< uint8_t > questCompleteVec( m_questCompleteFlags.size() ); std::vector< uint8_t > questCompleteVec( m_questCompleteFlags.size() );
memcpy( questCompleteVec.data(), m_questCompleteFlags.data(), m_questCompleteFlags.size() ); memcpy( questCompleteVec.data(), m_questCompleteFlags.data(), m_questCompleteFlags.size() );
stmt->setBinary( 46, questCompleteVec ); stmt->setBinary( 45, questCompleteVec );
stmt->setInt( 47, m_openingSequence ); stmt->setInt( 46, m_openingSequence );
std::vector< uint8_t > questTrackerVec( sizeof( m_questTracking ) ); std::vector< uint8_t > questTrackerVec( sizeof( m_questTracking ) );
memcpy( questTrackerVec.data(), m_questTracking.data(), sizeof( m_questTracking ) ); memcpy( questTrackerVec.data(), m_questTracking.data(), sizeof( m_questTracking ) );
stmt->setBinary( 48, questTrackerVec ); stmt->setBinary( 47, questTrackerVec );
stmt->setInt( 49, m_gc ); // DisplayFlags stmt->setInt( 48, m_gc ); // DisplayFlags
stmt->setBinary( 50, { m_gcRank[ 0 ], m_gcRank[ 1 ], m_gcRank[ 2 ] } ); stmt->setBinary( 49, { m_gcRank[ 0 ], m_gcRank[ 1 ], m_gcRank[ 2 ] } );
std::vector< uint8_t > discoveryVec( m_discovery.size() ); std::vector< uint8_t > discoveryVec( m_discovery.size() );
memcpy( discoveryVec.data(), m_discovery.data(), m_discovery.size() ); memcpy( discoveryVec.data(), m_discovery.data(), m_discovery.size() );
stmt->setBinary( 51, discoveryVec ); stmt->setBinary( 50, discoveryVec );
stmt->setInt( 52, m_gmRank ); stmt->setInt( 51, m_gmRank );
stmt->setInt( 53, m_configFlags ); stmt->setInt( 52, m_configFlags );
std::vector< uint8_t > unlockVec( m_unlocks.size() ); std::vector< uint8_t > unlockVec( m_unlocks.size() );
memcpy( unlockVec.data(), m_unlocks.data(), m_unlocks.size() ); memcpy( unlockVec.data(), m_unlocks.data(), m_unlocks.size() );
stmt->setBinary( 54, unlockVec ); stmt->setBinary( 53, unlockVec );
stmt->setInt( 55, m_cfPenaltyUntil ); stmt->setInt( 54, m_cfPenaltyUntil );
stmt->setInt( 56, m_pose ); stmt->setInt( 55, m_pose );
stmt->setUInt64( 57, m_characterId ); stmt->setUInt64( 56, m_characterId );
db.execute( stmt ); db.execute( stmt );
} }
@ -503,6 +547,36 @@ void Sapphire::Entity::Player::updateDbBlacklist()
db.execute( stmt ); db.execute( stmt );
} }
void Sapphire::Entity::Player::updateDbAchievement()
{
auto& db = Common::Service< Db::DbWorkerPool< Db::ZoneDbConnection > >::ref();
auto stmt = db.getPreparedStatement( Db::CHARA_ACHIEV_UP );
std::vector< int > flattenMap( m_achievementData.progressData.size() * 2 );
for( const auto& [ key, val ] : m_achievementData.progressData )
{
flattenMap.push_back( key );
flattenMap.push_back( val );
}
std::vector< uint8_t > unlockList( sizeof( uint8_t ) * m_achievementData.unlockList.size() );
std::vector< uint8_t > progressList( sizeof( uint32_t ) * flattenMap.size() );
std::vector< uint8_t > history( sizeof( uint16_t ) * m_achievementData.history.size() );
memcpy( unlockList.data(), m_achievementData.unlockList.data(), unlockList.size() );
memcpy( progressList.data(), flattenMap.data(), progressList.size() );
memcpy( history.data(), m_achievementData.history.data(), history.size() );
stmt->setBinary( 1, unlockList );
stmt->setBinary( 2, progressList );
stmt->setBinary( 3, history );
stmt->setUInt64( 4, m_characterId );
db.execute( stmt );
}
void Sapphire::Entity::Player::insertDbClass( const uint8_t classJobIndex, uint8_t level ) const void Sapphire::Entity::Player::insertDbClass( const uint8_t classJobIndex, uint8_t level ) const
{ {
auto& db = Common::Service< Db::DbWorkerPool< Db::ZoneDbConnection > >::ref(); auto& db = Common::Service< Db::DbWorkerPool< Db::ZoneDbConnection > >::ref();