Skip to content

Commit

Permalink
Merge pull request #909 from hkAlice/achievos
Browse files Browse the repository at this point in the history
[3.x] save achievement to sql db;
  • Loading branch information
SapphireMordred authored Mar 6, 2023
2 parents f4ab4ab + 78766f9 commit aead026
Show file tree
Hide file tree
Showing 10 changed files with 153 additions and 31 deletions.
6 changes: 3 additions & 3 deletions deps/mysqlConnector/PreparedStatement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,7 @@ bool Mysql::PreparedStatement::execute()

bool Mysql::PreparedStatement::execute( const std::string &sql )
{
throw std::runtime_error("PreparedStatement::execute( const std::string &sql ) Not implemented");
throw std::runtime_error( "PreparedStatement::execute( const std::string &sql ) Not implemented" );
return false;
}

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

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

{
Expand Down
10 changes: 10 additions & 0 deletions sql/migrations/20230305161241_AddAchievement.sql
Original file line number Diff line number Diff line change
@@ -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;
1 change: 1 addition & 0 deletions sql/migrations/20230305162627_RemovePlayerAchievement.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE `charainfo` DROP `Achievement`;
13 changes: 13 additions & 0 deletions src/api/PlayerMinimal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,19 @@ void PlayerMinimal::saveAsNew()
stmtBlacklist->setBinary( 2, blIds );
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
createInvDbContainer( InventoryType::Bag0 );
Expand Down
26 changes: 21 additions & 5 deletions src/common/Database/ZoneDbConnection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ void Sapphire::Db::ZoneDbConnection::doPrepareStatements()
"IsNewAdventurer, TerritoryType, TerritoryId, PosX, PosY, PosZ, PosR, "
"OTerritoryType, OTerritoryId, OPosX, OPosY, OPosZ, OPosR, GuardianDeity, "
"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, "
"QuestCompleteFlags, OpeningSequence, QuestTracking, GrandCompany, "
"GrandCompanyRank, Discovery, GMRank, EquipDisplayFlags, Unlocks, CFPenaltyUntil, "
Expand All @@ -46,7 +46,7 @@ void Sapphire::Db::ZoneDbConnection::doPrepareStatements()
"TerritoryType = ?, TerritoryId = ?, PosX = ?, PosY = ?, PosZ = ?, PosR = ?, "
"OTerritoryType = ?, OTerritoryId = ?, OPosX = ?, OPosY = ?, OPosZ = ?, OPosR = ?, "
"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 = ?, "
"QuestTracking = ?, GrandCompany = ?, GrandCompanyRank = ?, Discovery = ?, GMRank = ?, EquipDisplayFlags = ?, Unlocks = ?, "
"CFPenaltyUntil = ?, Pose = ? WHERE CharacterId = ?;",
Expand Down Expand Up @@ -107,8 +107,6 @@ void Sapphire::Db::ZoneDbConnection::doPrepareStatements()
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_ACHIEVEMENTS, "UPDATE charainfo SET Achievement = ? 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_MINIONS, "UPDATE charainfo SET Minions = ? WHERE CharacterId = ?;", CONNECTION_ASYNC );
Expand Down Expand Up @@ -224,6 +222,24 @@ void Sapphire::Db::ZoneDbConnection::doPrepareStatements()
"WHERE CharacterId = ?;",
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
prepareStatement( CHARA_FRIENDLIST_INS,
"INSERT INTO charainfofriendlist ( CharacterId, CharacterIdList, InviteDataList, UPDATE_DATE ) "
Expand All @@ -240,7 +256,7 @@ void Sapphire::Db::ZoneDbConnection::doPrepareStatements()
"WHERE CharacterId = ?;",
CONNECTION_SYNC );

/// CHARA FRIENDLIST
/// CHARA BLACKLIST
prepareStatement( CHARA_BLACKLIST_INS,
"INSERT INTO charainfoblacklist ( CharacterId, CharacterIdList, UPDATE_DATE ) "
" VALUES ( ?, ?, NOW() );",
Expand Down
5 changes: 4 additions & 1 deletion src/common/Database/ZoneDbConnection.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ namespace Sapphire::Db
CHARA_UP_FAVOPOINT,
CHARA_UP_TITLE,
CHARA_UP_TITLELIST,
CHARA_UP_ACHIEVEMENTS,
CHARA_UP_AETHERYTE,
CHARA_UP_HOWTO,
CHARA_UP_MINIONS,
Expand Down Expand Up @@ -89,6 +88,10 @@ namespace Sapphire::Db
CHARA_BLACKLIST_UP,
CHARA_BLACKLIST_SEL,

CHARA_ACHIEV_INS,
CHARA_ACHIEV_UP,
CHARA_ACHIEV_SEL,

CHARA_LINKSHELL_INS,

ZONE_SEL_BNPCS,
Expand Down
5 changes: 5 additions & 0 deletions src/world/Actor/Player.h
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,9 @@ namespace Sapphire::Entity
/*! unload player from logout */
void unload();

/*! load achievement data */
bool loadAchievements();

/*! load active class data */
bool loadClassData();

Expand Down Expand Up @@ -672,6 +675,8 @@ namespace Sapphire::Entity

void updateDbBlacklist();

void updateDbAchievement();

void updateDbChara() const;

///////////////////////////////////////////////////////////////////////////////////////////////////
Expand Down
118 changes: 96 additions & 22 deletions src/world/Actor/PlayerSql.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ bool Sapphire::Entity::Player::loadFromDb( uint64_t characterId )

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 );
}
Expand Down Expand Up @@ -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()
{
auto& db = Common::Service< Db::DbWorkerPool< Db::ZoneDbConnection > >::ref();
Expand Down Expand Up @@ -304,6 +347,9 @@ void Sapphire::Entity::Player::updateSql()
////// Blacklist
updateDbBlacklist();

////// Achievement
updateDbAchievement();

///// Store last write
syncLastDBWrite();
}
Expand Down Expand Up @@ -377,63 +423,61 @@ void Sapphire::Entity::Player::updateDbChara() const
std::vector< uint8_t > titleListVec( sizeof( m_titleList ) );
stmt->setBinary( 37, titleListVec );

std::vector< uint8_t > achievementVec( 16 );
stmt->setBinary( 38, achievementVec );

std::vector< uint8_t > aetheryteVec( 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 ) );
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 ) );
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 ) );
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() );
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() );
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 ) );
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() );
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() );
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 );
}
Expand Down Expand Up @@ -503,6 +547,36 @@ void Sapphire::Entity::Player::updateDbBlacklist()
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
{
auto& db = Common::Service< Db::DbWorkerPool< Db::ZoneDbConnection > >::ref();
Expand Down

0 comments on commit aead026

Please sign in to comment.