1
Fork 0
mirror of https://github.com/SapphireServer/Sapphire.git synced 2025-04-27 22:57:45 +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;
}
// CharacterId, ClassIdx, Exp, Lvl
// CharacterId, ClassIdx, Exp, Lvl, BorrowAction
auto stmtClass = g_charaDb.getPreparedStatement( Db::ZoneDbStatements::CHARA_CLASS_INS );
stmtClass->setUInt64( 1, m_characterId );
stmtClass->setInt( 2, g_exdData.getRow< Excel::ClassJob >( m_class )->data().WorkIndex );
stmtClass->setInt( 3, 0 );
stmtClass->setInt( 4, 1 );
std::vector< uint8_t > borrowActionVec( Common::ARRSIZE_BORROWACTION * 4 );
stmtClass->setBinary( 5, borrowActionVec );
g_charaDb.directExecute( stmtClass );
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_ORCHESTRION = 40u;
const uint16_t ARRSIZE_MONSTERNOTE = 12u;
const uint16_t ARRSIZE_BORROWACTION = 10u;
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 );
/// 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 );
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 );
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 );
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 );
}
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 )
{
uint16_t index;

View file

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

View file

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

View file

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

View file

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