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

Persistence for cross-class skills

This commit is contained in:
Lucy 2023-03-09 17:17:27 +01:00
parent cf32d4fe4d
commit f4a3c9493b
9 changed files with 54 additions and 8 deletions

View file

@ -0,0 +1 @@
ALTER TABLE `characlass` ADD `BorrowAction` binary(40) DEFAULT NULL NULL AFTER `Lvl`;

View file

@ -256,12 +256,14 @@ void PlayerMinimal::saveAsNew()
break; break;
} }
// CharacterId, ClassIdx, Exp, Lvl // CharacterId, ClassIdx, Exp, Lvl, BorrowAction
auto stmtClass = g_charaDb.getPreparedStatement( Db::ZoneDbStatements::CHARA_CLASS_INS ); auto stmtClass = g_charaDb.getPreparedStatement( Db::ZoneDbStatements::CHARA_CLASS_INS );
stmtClass->setUInt64( 1, m_characterId ); stmtClass->setUInt64( 1, m_characterId );
stmtClass->setInt( 2, g_exdData.getRow< Excel::ClassJob >( m_class )->data().WorkIndex ); stmtClass->setInt( 2, g_exdData.getRow< Excel::ClassJob >( m_class )->data().WorkIndex );
stmtClass->setInt( 3, 0 ); stmtClass->setInt( 3, 0 );
stmtClass->setInt( 4, 1 ); stmtClass->setInt( 4, 1 );
std::vector< uint8_t > borrowActionVec( Common::ARRSIZE_BORROWACTION * 4 );
stmtClass->setBinary( 5, borrowActionVec );
g_charaDb.directExecute( stmtClass ); g_charaDb.directExecute( stmtClass );
auto stmtSearchInfo = g_charaDb.getPreparedStatement( Db::ZoneDbStatements::CHARA_SEARCHINFO_INS ); auto stmtSearchInfo = g_charaDb.getPreparedStatement( Db::ZoneDbStatements::CHARA_SEARCHINFO_INS );

View file

@ -37,6 +37,7 @@ namespace Sapphire::Common
const uint16_t ARRSIZE_UNLOCKS = 64u; const uint16_t ARRSIZE_UNLOCKS = 64u;
const uint16_t ARRSIZE_ORCHESTRION = 40u; const uint16_t ARRSIZE_ORCHESTRION = 40u;
const uint16_t ARRSIZE_MONSTERNOTE = 12u; const uint16_t ARRSIZE_MONSTERNOTE = 12u;
const uint16_t ARRSIZE_BORROWACTION = 10u;
const uint8_t TOWN_COUNT = 6; const uint8_t TOWN_COUNT = 6;

View file

@ -161,11 +161,11 @@ void Sapphire::Db::ZoneDbConnection::doPrepareStatements()
prepareStatement( CHARA_SEL_QUEST, "SELECT * FROM charaquest WHERE CharacterId = ?;", CONNECTION_SYNC ); prepareStatement( CHARA_SEL_QUEST, "SELECT * FROM charaquest WHERE CharacterId = ?;", CONNECTION_SYNC );
/// CLASS INFO /// CLASS INFO
prepareStatement( CHARA_CLASS_SEL, "SELECT ClassIdx, Exp, Lvl FROM characlass WHERE CharacterId = ?;", prepareStatement( CHARA_CLASS_SEL, "SELECT ClassIdx, Exp, Lvl, BorrowAction FROM characlass WHERE CharacterId = ?;",
CONNECTION_SYNC ); CONNECTION_SYNC );
prepareStatement( CHARA_CLASS_INS, "INSERT INTO characlass ( CharacterId, ClassIdx, Exp, Lvl ) VALUES( ?,?,?,? );", prepareStatement( CHARA_CLASS_INS, "INSERT INTO characlass ( CharacterId, ClassIdx, Exp, Lvl, BorrowAction ) VALUES( ?,?,?,?,? );",
CONNECTION_BOTH ); CONNECTION_BOTH );
prepareStatement( CHARA_CLASS_UP, "UPDATE characlass SET Exp = ?, Lvl = ? WHERE CharacterId = ? AND ClassIdx = ?;", prepareStatement( CHARA_CLASS_UP, "UPDATE characlass SET Exp = ?, Lvl = ?, BorrowAction = ? WHERE CharacterId = ? AND ClassIdx = ?;",
CONNECTION_ASYNC ); CONNECTION_ASYNC );
prepareStatement( CHARA_CLASS_DEL, "DELETE FROM characlass WHERE CharacterId = ?;", CONNECTION_ASYNC ); prepareStatement( CHARA_CLASS_DEL, "DELETE FROM characlass WHERE CharacterId = ?;", CONNECTION_ASYNC );

View file

@ -563,6 +563,22 @@ void Player::setRewardFlag( Common::UnlockEntry unlockId )
Network::Util::Player::sendActorControlSelf( *this, SetRewardFlag, unlock, 1 ); Network::Util::Player::sendActorControlSelf( *this, SetRewardFlag, unlock, 1 );
} }
void Player::setBorrowAction( uint8_t slot, uint32_t action )
{
if( slot > Common::ARRSIZE_BORROWACTION )
return;
auto& borrowAction = getBorrowAction();
borrowAction[ slot ] = action;
}
Player::BorrowAction& Player::getBorrowAction()
{
auto& exdData = Common::Service< Data::ExdData >::ref();
uint8_t classJobIndex = exdData.getRow< Excel::ClassJob >( static_cast<uint8_t>( getClass() ) )->data().WorkIndex;
return m_borrowActions[ classJobIndex ];
}
void Player::learnSong( uint8_t songId, uint32_t itemId ) void Player::learnSong( uint8_t songId, uint32_t itemId )
{ {
uint16_t index; uint16_t index;

View file

@ -38,6 +38,7 @@ namespace Sapphire::Entity
using ClassList = std::array< uint16_t, Common::ARRSIZE_CLASSJOB >; using ClassList = std::array< uint16_t, Common::ARRSIZE_CLASSJOB >;
using ExpList = std::array< uint32_t, Common::ARRSIZE_CLASSJOB >; using ExpList = std::array< uint32_t, Common::ARRSIZE_CLASSJOB >;
using BorrowAction = std::array< uint32_t, Common::ARRSIZE_BORROWACTION >;
struct AchievementData { struct AchievementData {
std::array< uint8_t, 2048 / 8 > unlockList; std::array< uint8_t, 2048 / 8 > unlockList;
@ -446,6 +447,10 @@ namespace Sapphire::Entity
/*! learn an action / update the unlock bitmask. */ /*! learn an action / update the unlock bitmask. */
void setRewardFlag( Common::UnlockEntry unlockId ); void setRewardFlag( Common::UnlockEntry unlockId );
void setBorrowAction( uint8_t slot, uint32_t action );
BorrowAction& getBorrowAction();
/*! learn a song / update the unlock bitmask. */ /*! learn a song / update the unlock bitmask. */
void learnSong( uint8_t songId, uint32_t itemId ); void learnSong( uint8_t songId, uint32_t itemId );
@ -966,6 +971,8 @@ namespace Sapphire::Entity
std::array< Common::HuntingLogEntry, Common::ARRSIZE_MONSTERNOTE > m_huntingLogEntries{}; std::array< Common::HuntingLogEntry, Common::ARRSIZE_MONSTERNOTE > m_huntingLogEntries{};
std::array< BorrowAction, Common::ARRSIZE_CLASSJOB > m_borrowActions{};
FriendListIDVec m_friendList{}; FriendListIDVec m_friendList{};
FriendListDataVec m_friendInviteList{}; FriendListDataVec m_friendInviteList{};

View file

@ -258,7 +258,7 @@ bool Sapphire::Entity::Player::loadAchievements()
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();
// ClassIdx, Exp, Lvl // ClassIdx, Exp, Lvl, BorrowAction
auto stmt = db.getPreparedStatement( Db::ZoneDbStatements::CHARA_CLASS_SEL ); auto stmt = db.getPreparedStatement( Db::ZoneDbStatements::CHARA_CLASS_SEL );
stmt->setUInt64( 1, m_characterId ); stmt->setUInt64( 1, m_characterId );
auto res = db.query( stmt ); auto res = db.query( stmt );
@ -268,9 +268,11 @@ bool Sapphire::Entity::Player::loadClassData()
auto index = res->getUInt16( 1 ); auto index = res->getUInt16( 1 );
auto exp = res->getUInt( 2 ); auto exp = res->getUInt( 2 );
auto lvl = res->getUInt8( 3 ); auto lvl = res->getUInt8( 3 );
auto borrowAction = res->getBlobVector( "BorrowAction" );
m_classArray[ index ] = lvl; m_classArray[ index ] = lvl;
m_expArray[ index ] = exp; m_expArray[ index ] = exp;
memcpy( m_borrowActions[ index ].data(), borrowAction.data(), borrowAction.size() );
} }
return true; return true;
@ -487,13 +489,19 @@ void Sapphire::Entity::Player::updateDbClass() const
auto& db = Common::Service< Db::DbWorkerPool< Db::ZoneDbConnection > >::ref(); auto& db = Common::Service< Db::DbWorkerPool< Db::ZoneDbConnection > >::ref();
auto& exdData = Common::Service< Data::ExdData >::ref(); auto& exdData = Common::Service< Data::ExdData >::ref();
uint8_t classJobIndex = exdData.getRow< Excel::ClassJob >( static_cast<uint8_t>( getClass() ) )->data().WorkIndex; uint8_t classJobIndex = exdData.getRow< Excel::ClassJob >( static_cast<uint8_t>( getClass() ) )->data().WorkIndex;
auto& borrowAction = m_borrowActions[ classJobIndex ];
//Exp = ?, Lvl = ? WHERE CharacterId = ? AND ClassIdx = ? //Exp = ?, Lvl = ?, BorrowAction = ? WHERE CharacterId = ? AND ClassIdx = ?
auto stmtS = db.getPreparedStatement( Db::CHARA_CLASS_UP ); auto stmtS = db.getPreparedStatement( Db::CHARA_CLASS_UP );
stmtS->setInt( 1, getExp() ); stmtS->setInt( 1, getExp() );
stmtS->setInt( 2, getLevel() ); stmtS->setInt( 2, getLevel() );
stmtS->setUInt64( 3, m_characterId );
stmtS->setInt( 4, classJobIndex ); std::vector< uint8_t > borrowActionVec( borrowAction.size() * 4 );
memcpy( borrowActionVec.data(), borrowAction.data(), borrowAction.size() * 4 );
stmtS->setBinary( 3, borrowActionVec );
stmtS->setUInt64( 4, m_characterId );
stmtS->setInt( 5, classJobIndex );
db.execute( stmtS ); db.execute( stmtS );
} }
@ -581,10 +589,14 @@ void Sapphire::Entity::Player::insertDbClass( const uint8_t classJobIndex, uint8
{ {
auto& db = Common::Service< Db::DbWorkerPool< Db::ZoneDbConnection > >::ref(); auto& db = Common::Service< Db::DbWorkerPool< Db::ZoneDbConnection > >::ref();
auto stmtClass = db.getPreparedStatement( Db::CHARA_CLASS_INS ); auto stmtClass = db.getPreparedStatement( Db::CHARA_CLASS_INS );
auto& borrowAction = m_borrowActions[ classJobIndex ];
stmtClass->setUInt64( 1, m_characterId ); stmtClass->setUInt64( 1, m_characterId );
stmtClass->setInt( 2, classJobIndex ); stmtClass->setInt( 2, classJobIndex );
stmtClass->setInt( 3, 0 ); stmtClass->setInt( 3, 0 );
stmtClass->setInt( 4, level ); stmtClass->setInt( 4, level );
std::vector< uint8_t > borrowActionVec( borrowAction.size() );
stmtClass->setBinary( 5, borrowActionVec );
db.directExecute( stmtClass ); db.directExecute( stmtClass );
} }

View file

@ -497,6 +497,11 @@ void Sapphire::Network::GameConnection::commandHandler( const Packets::FFXIVARR_
Network::Util::Player::sendTitleList( player ); Network::Util::Player::sendTitleList( player );
break; break;
} }
case PacketCommand::BORROW_ACTION:
{
player.setBorrowAction( static_cast< uint8_t >( data.Arg1 ), data.Arg2 );
break;
}
case PacketCommand::SET_HOWTO: // Update howtos seen case PacketCommand::SET_HOWTO: // Update howtos seen
{ {
player.updateHowtosSeen( data.Arg0 ); player.updateHowtosSeen( data.Arg0 );

View file

@ -291,10 +291,12 @@ void Util::Player::sendPlayerSetup( Entity::Player& player )
void Util::Player::sendChangeClass( Entity::Player& player ) void Util::Player::sendChangeClass( Entity::Player& player )
{ {
auto classInfo = makeZonePacket< FFXIVIpcChangeClass >( player.getId() ); auto classInfo = makeZonePacket< FFXIVIpcChangeClass >( player.getId() );
auto& borrowAction = player.getBorrowAction();
classInfo->data().ClassJob = static_cast< uint8_t >( player.getClass() ); classInfo->data().ClassJob = static_cast< uint8_t >( player.getClass() );
classInfo->data().Lv = player.getLevel(); classInfo->data().Lv = player.getLevel();
classInfo->data().Lv1 = player.getLevel(); classInfo->data().Lv1 = player.getLevel();
classInfo->data().Login = player.isLogin() ? 1 : 0; classInfo->data().Login = player.isLogin() ? 1 : 0;
memcpy( &classInfo->data().BorrowAction[ 0 ], borrowAction.data(), borrowAction.size() * 4 );
server().queueForPlayer( player.getCharacterId(), classInfo ); server().queueForPlayer( player.getCharacterId(), classInfo );
} }