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

Merge pull request #889 from Skyliegirl33/master

[3.x] Implement glamours, set firstclass, fix tp not being set, log all params in packet cmds
This commit is contained in:
Mordred 2023-02-11 22:04:38 +01:00 committed by GitHub
commit 81391f1ae1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 177 additions and 7 deletions

View file

@ -275,7 +275,7 @@ void Sapphire::Db::ZoneDbConnection::doPrepareStatements()
CONNECTION_BOTH );
prepareStatement( CHARA_ITEMGLOBAL_UP,
"UPDATE charaglobalitem SET stack = ?, durability = ?, stain = ? WHERE ItemId = ?;",
"UPDATE charaglobalitem SET stack = ?, durability = ?, stain = ?, pattern = ? WHERE ItemId = ?;",
CONNECTION_BOTH );
prepareStatement( CHARA_ITEMGLOBAL_DELETE,

View file

@ -549,6 +549,8 @@ namespace Sapphire::Network::ActorControl
MOBHUNT_RECEIPT_ORDER = 0x1B3,
MOBHUNT_BREAK_ORDER = 0x1B4,
DYE_ITEM = 0x1B5,
GLAMOUR_ITEM = 0x1BA,
GLAMOUR_DISPEL = 0x1BB,
EMOTE = 0x1F4,
EMOTE_WITH_WARP = 0x1F5,
EMOTE_CANCEL = 0x1F6,

View file

@ -0,0 +1,27 @@
#include <ScriptObject.h>
#include <Actor/Player.h>
#include <Action/Action.h>
#include <Inventory/Item.h>
class ActionGlamour2471 :
public Sapphire::ScriptAPI::ActionScript
{
public:
ActionGlamour2471() :
Sapphire::ScriptAPI::ActionScript( 2471 )
{
}
void onExecute( Sapphire::World::Action::Action& action ) override
{
auto sourceChara = action.getSourceChara();
if( !sourceChara->isPlayer() )
return;
//TODO: Effect
sourceChara->getAsPlayer()->glamourItemFromGlamouringInfo();
}
};
EXPOSE_SCRIPT(ActionGlamour2471);

View file

@ -690,6 +690,11 @@ uint8_t Player::getLevelForClass( Common::ClassJob pClass ) const
return static_cast< uint8_t >( m_classArray[ classJobIndex ] );
}
Common::ClassJob Player::getFirstClass() const
{
return m_firstClass;
}
bool Player::isClassJobUnlocked( Common::ClassJob classJob ) const
{
// todo: need to properly check if a job is unlocked, at the moment we just check the class array which will return true for every job if the base class is unlocked
@ -1505,6 +1510,68 @@ void Player::dyeItemFromDyeingInfo()
queuePacket( dyePkt );
}
void Player::setGlamouringInfo( uint32_t itemToGlamourContainer, uint32_t itemToGlamourSlot, uint32_t glamourBagContainer, uint32_t glamourBagSlot, bool shouldGlamour )
{
m_glamouringInfo.itemToGlamourContainer = itemToGlamourContainer;
m_glamouringInfo.itemToGlamourSlot = itemToGlamourSlot;
m_glamouringInfo.glamourBagContainer = glamourBagContainer;
m_glamouringInfo.glamourBagSlot = glamourBagSlot;
m_glamouringInfo.shouldGlamour = shouldGlamour;
}
void Player::glamourItemFromGlamouringInfo()
{
auto& playerMgr = Service< World::Manager::PlayerMgr >::ref();
uint32_t itemToGlamourContainer = m_glamouringInfo.itemToGlamourContainer;
uint32_t itemToGlamourSlot = m_glamouringInfo.itemToGlamourSlot;
uint32_t glamourBagContainer = m_glamouringInfo.glamourBagContainer;
uint32_t glamourBagSlot = m_glamouringInfo.glamourBagSlot;
bool shouldGlamour = m_glamouringInfo.shouldGlamour;
playerMgr.onSendStateFlags( *this, true );
auto itemToGlamour = getItemAt( itemToGlamourContainer, itemToGlamourSlot );
auto glamourToUse = getItemAt( glamourBagContainer, glamourBagSlot );
//auto prismToUse = getItemAt( glamourBagContainer, glamourBagSlot );
if( !itemToGlamour )
return;
//if( !removeItem( prismToUse->getId() ) )
// return;
uint32_t patternID = itemToGlamour->getPattern();
bool invalidateGearSet = shouldGlamour ? patternID != glamourToUse->getId() : true;
if( shouldGlamour )
{
itemToGlamour->setPattern( glamourToUse->getId() );
itemToGlamour->setStain( glamourToUse->getStain() );
}
else
{
itemToGlamour->setPattern( 0 );
itemToGlamour->setStain( 0 );
}
itemToGlamour->setGlamModelIds();
insertInventoryItem( static_cast< Sapphire::Common::InventoryType >( itemToGlamourContainer ), static_cast< uint16_t >( itemToGlamourSlot ), itemToGlamour );
writeItem( itemToGlamour );
if( shouldGlamour )
{
auto castGlamPkt = makeActorControlSelf( getId(), GlamourCastMsg, itemToGlamour->getId(), glamourToUse->getId(), invalidateGearSet );
queuePacket( castGlamPkt );
}
else
{
auto dispelGlamPkt = makeActorControlSelf( getId(), GlamourRemoveMsg, itemToGlamour->getId(), invalidateGearSet );
queuePacket( dispelGlamPkt );
}
}
void Player::resetObjSpawnIndex()
{
m_objSpawnIndexAllocator.freeAllSpawnIndexes();

View file

@ -214,6 +214,9 @@ namespace Sapphire::Entity
/*! returns the level of the provided class / job */
uint8_t getLevelForClass( Common::ClassJob pClass ) const;
/*! \return the first class of the player */
Common::ClassJob getFirstClass() const;
/*! returns if the classjob is unlocked */
bool isClassJobUnlocked( Common::ClassJob classJob ) const;
@ -357,6 +360,9 @@ namespace Sapphire::Entity
void setDyeingInfo( uint32_t itemToDyeContainer, uint32_t itemToDyeSlot, uint32_t dyeBagContainer, uint32_t dyeBagSlot );
void dyeItemFromDyeingInfo();
void setGlamouringInfo( uint32_t itemToGlamourContainer, uint32_t itemToGlamourSlot, uint32_t glamourBagContainer, uint32_t glamourBagSlot, bool shouldGlamour );
void glamourItemFromGlamouringInfo();
/*! get player's title list (available titles) */
TitleList& getTitleList();
@ -898,6 +904,8 @@ namespace Sapphire::Entity
ExpList m_expArray{};
StateFlags m_stateFlags{};
Common::ClassJob m_firstClass{};
uint8_t m_homePoint;
uint8_t m_startTown;
uint16_t m_townWarpFstFlags;
@ -968,6 +976,15 @@ namespace Sapphire::Entity
uint32_t dyeBagSlot;
} m_dyeingInfo{};
struct PlayerGlamouringInfo
{
uint32_t itemToGlamourContainer;
uint32_t itemToGlamourSlot;
uint32_t glamourBagContainer;
uint32_t glamourBagSlot;
bool shouldGlamour;
} m_glamouringInfo{};
Common::Util::SpawnIndexAllocator< uint8_t > m_objSpawnIndexAllocator;
Common::Util::SpawnIndexAllocator< uint8_t > m_actorSpawnIndexAllocator;

View file

@ -529,8 +529,9 @@ void Sapphire::Entity::Player::writeItem( Sapphire::ItemPtr pItem ) const
stmt->setInt( 1, pItem->getStackSize() );
stmt->setInt( 2, pItem->getDurability() );
stmt->setInt( 3, pItem->getStain() );
stmt->setInt( 4, pItem->getPattern() );
stmt->setInt64( 4, pItem->getUId() );
stmt->setInt64( 5, pItem->getUId() );
db.directExecute( stmt );
}

View file

@ -78,6 +78,7 @@ bool Sapphire::Entity::Player::loadFromDb( uint64_t characterId )
m_class = static_cast< ClassJob >( res->getUInt( "Class" ) );
m_homePoint = res->getUInt8( "Homepoint" );
m_firstClass = static_cast< ClassJob >( res->getUInt( "FirstClass" ) );
// Additional data
m_voice = res->getUInt8( "Voice" );

View file

@ -132,6 +132,23 @@ Sapphire::Common::ItemUICategory Sapphire::Item::getCategory() const
return m_category;
}
void Sapphire::Item::setGlamModelIds()
{
auto& exdData = Common::Service< Data::ExdData >::ref();
if( m_pattern != 0 )
{
auto itemInfo = exdData.getRow< Excel::Item >( m_pattern );
m_glamModel1 = itemInfo->data().ModelId;
m_glamModel2 = itemInfo->data().SubModelId;
}
else
{
m_glamModel1 = 0;
m_glamModel2 = 0;
}
}
void Sapphire::Item::setModelIds( uint64_t model1, uint64_t model2 )
{
m_model1 = model1;
@ -140,12 +157,12 @@ void Sapphire::Item::setModelIds( uint64_t model1, uint64_t model2 )
uint64_t Sapphire::Item::getModelId1() const
{
return m_model1;
return m_pattern != 0 ? m_glamModel1 : m_model1;
}
uint64_t Sapphire::Item::getModelId2() const
{
return m_model2;
return m_pattern != 0 ? m_glamModel2 : m_model2;
}
bool Sapphire::Item::isHq() const
@ -183,6 +200,16 @@ void Sapphire::Item::setStain( uint16_t stain )
m_stain = stain;
}
uint32_t Sapphire::Item::getPattern() const
{
return m_pattern;
}
void Sapphire::Item::setPattern( uint32_t pattern )
{
m_pattern = pattern;
}
uint32_t Sapphire::Item::getAdditionalData() const
{
return m_additionalData;

View file

@ -37,6 +37,8 @@ namespace Sapphire
Common::ItemUICategory getCategory() const;
void setGlamModelIds();
void setModelIds( uint64_t model1, uint64_t model2 );
uint64_t getModelId1() const;
@ -75,6 +77,9 @@ namespace Sapphire
uint16_t getStain() const;
void setStain( uint16_t stain );
uint32_t getPattern() const;
void setPattern( uint32_t pattern );
uint32_t getAdditionalData() const;
void setSpiritbond( uint16_t spiritbond );
@ -99,6 +104,9 @@ namespace Sapphire
uint64_t m_model1;
uint64_t m_model2;
uint64_t m_glamModel1;
uint64_t m_glamModel2;
bool m_isHq;
uint16_t m_delayMs;
@ -110,6 +118,7 @@ namespace Sapphire
uint8_t m_slot;
uint16_t m_durability;
uint16_t m_stain;
uint32_t m_pattern;
uint16_t m_spiritBond;
uint32_t m_reservedFlag;

View file

@ -61,6 +61,7 @@ void InventoryMgr::sendInventoryContainer( Entity::Player& player, ItemContainer
// todo: not sure if correct flag?
itemInfoPacket->data().item.flags = static_cast< uint8_t >( itM.second->isHq() ? 1 : 0 );
itemInfoPacket->data().item.stain = static_cast< uint8_t >( itM.second->getStain() );
itemInfoPacket->data().item.pattern = itM.second->getPattern();
server.queueForPlayer( player.getCharacterId(), itemInfoPacket );
}

View file

@ -141,7 +141,9 @@ ItemPtr ItemMgr::loadItem( uint64_t uId )
pItem->setStackSize( itemRes->getUInt( 2 ) );
pItem->setStain( itemRes->getUInt16( 13 ) );
pItem->setPattern( itemRes->getUInt( 14 ) );
pItem->setDurability( itemRes->getInt16( 6 ) );
pItem->setGlamModelIds();
return pItem;
}

View file

@ -184,6 +184,10 @@ const char* packetCommandToString( uint16_t commandId )
return "MOBHUNT_BREAK_ORDER";
case DYE_ITEM:
return "DYE_ITEM";
case GLAMOUR_ITEM:
return "GLAMOUR_ITEM";
case GLAMOUR_DISPEL:
return "GLAMOUR_DISPEL";
case EMOTE:
return "EMOTE";
case EMOTE_WITH_WARP:
@ -413,8 +417,8 @@ void Sapphire::Network::GameConnection::commandHandler( const Packets::FFXIVARR_
const auto param3 = packet.data().Target;
Logger::debug( "\t\t {5} | {1:X} ( p1:{2:X} p2:{3:X} p3:{4:X} )",
m_pSession->getId(), commandId, param1, param2, param3, packetCommandToString( commandId ) );
Logger::debug( "\t\t {8} | {1:X} ( p1:{2:X} p11:{3:X} p12:{4:X} p2:{5:X} p3:{6:X} p4:{7:X} )",
m_pSession->getId(), commandId, param1, param11, param12, param2, param3, param4, packetCommandToString( commandId ) );
//Logger::Log(LoggingSeverity::debug, "[" + std::to_string(m_pSession->getId()) + "] " + pInPacket->toString());
@ -635,6 +639,16 @@ void Sapphire::Network::GameConnection::commandHandler( const Packets::FFXIVARR_
player.setDyeingInfo( param11, param12, param2, param4 );
break;
}
case PacketCommand::GLAMOUR_ITEM:
{
player.setGlamouringInfo( param11, param12, param2, param4, true );
break;
}
case PacketCommand::GLAMOUR_DISPEL:
{
player.setGlamouringInfo( param11, param12, param2, param4, false );
break;
}
case PacketCommand::DIRECTOR_INIT_RETURN: // Director init finish
{
pZone->onInitDirector( player );

View file

@ -26,6 +26,7 @@ namespace Sapphire::Network::Packets::WorldPackets::Server
m_data.LvSync = 0; //player.getLevelSync();
m_data.Hp = player.getHp();
m_data.Mp = player.getMp();
m_data.Tp = player.getTp();
m_data.HpMax = player.getMaxHp();
m_data.MpMax = player.getMaxMp();;
};

View file

@ -34,7 +34,7 @@ namespace Sapphire::Network::Packets::WorldPackets::Server
m_data.Tribe = player.getLookAt( Common::CharaLook::Tribe );
m_data.Sex = player.getLookAt( Common::CharaLook::Gender );
m_data.ClassJob = static_cast< uint8_t >( player.getClass() );
m_data.FirstClass = static_cast< uint8_t >( player.getClass() );
m_data.FirstClass = static_cast< uint8_t >( player.getFirstClass() );
//m_data.maxLevel = player.getLevel();
m_data.GuardianDeity = static_cast< uint8_t >( player.getGuardianDeity() );
m_data.BirthMonth = player.getBirthMonth();

View file

@ -37,6 +37,7 @@ namespace Sapphire::Network::Packets::WorldPackets::Server
m_data.item.flags = static_cast< uint8_t >( item.isHq() ? 1 : 0 );
m_data.item.refine = item.getSpiritbond();
m_data.item.stain = static_cast< uint8_t >( item.getStain() );
m_data.item.pattern = item.getPattern();
m_data.item.durability = item.getDurability();
m_data.item.signatureId = 0;
};