diff --git a/bin/web/assets/img/background.png b/bin/web/assets/img/background.png index a2fae17b..ea97ac81 100644 Binary files a/bin/web/assets/img/background.png and b/bin/web/assets/img/background.png differ diff --git a/sql/charadetail.sql b/sql/charadetail.sql index 05ed0de0..2a47302c 100644 --- a/sql/charadetail.sql +++ b/sql/charadetail.sql @@ -70,6 +70,7 @@ CREATE TABLE IF NOT EXISTS `charadetail` ( `StepIndex` int(5) DEFAULT NULL, `ChocoboTaxiStandFlags` binary(8) DEFAULT NULL, `GMRank` int(3) DEFAULT '0', + `EquipDisplayFlags` int(3) DEFAULT '0', `unlocks` binary(64) DEFAULT NULL, `CharacterId` int(20) NOT NULL DEFAULT '0', `IS_DELETE` int(3) DEFAULT '0', diff --git a/sql/update.sql b/sql/update.sql index 03b7679d..c0f2ed69 100644 --- a/sql/update.sql +++ b/sql/update.sql @@ -22,4 +22,6 @@ -- -- ALTER TABLE `charadetail` CHANGE `OpeningSequence` `OpeningSequence` INT(3) NULL DEFAULT '0'; -- ------------------------------------------- --- update.sql Before Merge into Other SQL's 30/08/2017 \ No newline at end of file +-- update.sql Before Merge into Other SQL's 30/08/2017 + +ALTER TABLE `charadetail` ADD `EquipDisplayFlags` int(3) DEFAULT '0' AFTER `GMRank`; \ No newline at end of file diff --git a/src/servers/Server_Common/Common.h b/src/servers/Server_Common/Common.h index dc4c5fff..12b97937 100644 --- a/src/servers/Server_Common/Common.h +++ b/src/servers/Server_Common/Common.h @@ -946,7 +946,7 @@ namespace Core { SetMaxGearSets = 0x230, - ToggleDisplayHeadAndWeapon = 0x260, + SetCharaGearParamUI = 0x260, GearSetEquipMsg = 0x321 }; @@ -1056,6 +1056,15 @@ namespace Core { Unused100 }; + enum EquipDisplayFlags : uint8_t + { + HideNothing = 0x0, + HideHead = 0x1, + HideWeapon = 0x2, + + Visor = 0x40, + }; + struct ServerEntry { uint32_t serverId; diff --git a/src/servers/Server_Common/Network/PacketDef/Ipcs.h b/src/servers/Server_Common/Network/PacketDef/Ipcs.h index 22a7ed3f..16243669 100644 --- a/src/servers/Server_Common/Network/PacketDef/Ipcs.h +++ b/src/servers/Server_Common/Network/PacketDef/Ipcs.h @@ -119,6 +119,8 @@ namespace Packets { EorzeaTimeOffset = 0x01B4, + EquipDisplayFlags = 0x01C0, + CFAvailableContents = 0x01CF, PrepareZoning = 0x0239, // updated for sb @@ -186,6 +188,8 @@ namespace Packets { LinkshellEventHandler = 0x013B, LinkshellEventHandler1 = 0x013C, + + ReqEquipDisplayFlagsChange = 0x0143, }; //////////////////////////////////////////////////////////////////////////////// diff --git a/src/servers/Server_Common/Network/PacketDef/Zone/ServerZoneDef.h b/src/servers/Server_Common/Network/PacketDef/Zone/ServerZoneDef.h index bfae778b..131ac089 100644 --- a/src/servers/Server_Common/Network/PacketDef/Zone/ServerZoneDef.h +++ b/src/servers/Server_Common/Network/PacketDef/Zone/ServerZoneDef.h @@ -1294,6 +1294,14 @@ struct FFXIVIpcEorzeaTimeOffset : FFXIVIpcBasePacket uint64_t timestamp; }; +/** +* Structural representation of the packet sent by the server +* to set the gear show/hide status of a character +*/ +struct FFXIVIpcEquipDisplayFlags : FFXIVIpcBasePacket +{ + uint8_t bitmask; +}; } /* Server */ diff --git a/src/servers/Server_Zone/Actor/Actor.h b/src/servers/Server_Zone/Actor/Actor.h index 215ec666..5a784f28 100644 --- a/src/servers/Server_Zone/Actor/Actor.h +++ b/src/servers/Server_Zone/Actor/Actor.h @@ -43,6 +43,16 @@ public: Active = 1, }; + enum DisplayFlags : uint16_t + { + ActiveStance = 0x001, + Invisible = 0x020, + HideHead = 0x040, + HideWeapon = 0x080, + Faded = 0x100, + Visor = 0x800, + }; + enum struct ActorStatus : uint8_t { Idle = 0x01, diff --git a/src/servers/Server_Zone/Actor/Player.cpp b/src/servers/Server_Zone/Actor/Player.cpp index cd4b0c68..e407b214 100644 --- a/src/servers/Server_Zone/Actor/Player.cpp +++ b/src/servers/Server_Zone/Actor/Player.cpp @@ -388,6 +388,11 @@ void Core::Entity::Player::setZone( uint32_t zoneId ) sendInventory(); + if( isLogin() ) + { + queuePacket(ActorControlPacket143( getId(), SetCharaGearParamUI, m_equipDisplayFlags, 1 ) ); + } + // set flags, will be reset automatically by zoning ( only on client side though ) pPlayer->setStateFlag( PlayerStateFlag::BetweenAreas ); pPlayer->setStateFlag( PlayerStateFlag::BetweenAreas1 ); @@ -1421,6 +1426,20 @@ void Core::Entity::Player::setTitle( uint16_t titleId ) sendToInRangeSet( ActorControlPacket142( getId(), SetTitle, titleId ), true ); } +void Core::Entity::Player::setEquipDisplayFlags( uint8_t state ) +{ + m_equipDisplayFlags = state; + GamePacketNew< FFXIVIpcEquipDisplayFlags, ServerZoneIpcType > paramPacket( getId() ); + paramPacket.data().bitmask = m_equipDisplayFlags; + sendToInRangeSet( paramPacket, true ); + setSyncFlag( PlayerSyncFlags::Status ); +} + +uint8_t Core::Entity::Player::getEquipDisplayFlags() const +{ + return m_equipDisplayFlags; +} + void Core::Entity::Player::autoAttack( ActorPtr pTarget ) { diff --git a/src/servers/Server_Zone/Actor/Player.h b/src/servers/Server_Zone/Actor/Player.h index f64c1d75..3f0a3451 100644 --- a/src/servers/Server_Zone/Actor/Player.h +++ b/src/servers/Server_Zone/Actor/Player.h @@ -330,6 +330,10 @@ public: void prepareZoning( uint16_t targetZone, bool fadeOut, uint8_t fadoutTime = 0, uint16_t animation = 0 ); /*! change player's title */ void setTitle( uint16_t titleId ); + /*! change gear param state */ + void setEquipDisplayFlags( uint8_t state ); + /*! get gear param state and send update to inRangeSet */ + uint8_t getEquipDisplayFlags() const; void calculateStats() override; void sendStats(); @@ -602,6 +606,8 @@ private: uint8_t m_gmRank; uint16_t zoneId; + uint8_t m_equipDisplayFlags; + bool m_bInCombat; bool m_bLoadingComplete; bool m_bAutoattack; diff --git a/src/servers/Server_Zone/Actor/PlayerSql.cpp b/src/servers/Server_Zone/Actor/PlayerSql.cpp index 7d5db611..d8cf4194 100644 --- a/src/servers/Server_Zone/Actor/PlayerSql.cpp +++ b/src/servers/Server_Zone/Actor/PlayerSql.cpp @@ -81,7 +81,8 @@ bool Core::Entity::Player::load( uint32_t charId, Core::SessionPtr pSession ) "cd.GrandCompanyRank, " "cd.CFPenaltyUntil, " "cd.OpeningSequence, " - "cd.GMRank " + "cd.GMRank, " + "cd.EquipDisplayFlags " "FROM charabase AS c " " INNER JOIN charadetail AS cd " " ON c.CharacterId = cd.CharacterId " @@ -89,7 +90,7 @@ bool Core::Entity::Player::load( uint32_t charId, Core::SessionPtr pSession ) if( !pQR ) { - g_log.error( "Player id " + char_id_str + " does not exist!" ); + g_log.error( "[DB] Failed loading Player ID " + char_id_str ); return false; } @@ -173,6 +174,7 @@ bool Core::Entity::Player::load( uint32_t charId, Core::SessionPtr pSession ) m_openingSequence = field[36].get< uint32_t >(); m_gmRank = field[37].get< uint8_t >(); + m_equipDisplayFlags = field[38].get< uint8_t >(); m_pCell = nullptr; @@ -350,6 +352,7 @@ void Core::Entity::Player::createUpdateSql() charaBaseSet.insert( " ModelEquip = UNHEX('" + std::string( Util::binaryToHexString( reinterpret_cast< uint8_t* >( m_modelEquip ), 40 ) ) + "')" ); charaDetailSet.insert( " Class = " + std::to_string( static_cast< uint32_t >( getClass() ) ) ); charaDetailSet.insert( " Status = " + std::to_string( static_cast< uint8_t >( getStatus() ) ) ); + charaDetailSet.insert( " EquipDisplayFlags = " + std::to_string( static_cast< uint8_t >( getEquipDisplayFlags() ) ) ); } if( m_updateFlags & PlayerSyncFlags::OpeningSeq ) diff --git a/src/servers/Server_Zone/Network/GameConnection.cpp b/src/servers/Server_Zone/Network/GameConnection.cpp index 0563b007..a89d1bfe 100644 --- a/src/servers/Server_Zone/Network/GameConnection.cpp +++ b/src/servers/Server_Zone/Network/GameConnection.cpp @@ -93,8 +93,9 @@ Core::Network::GameConnection::GameConnection( Core::Network::HivePtr pHive, setZoneHandler( ClientZoneIpcType::CFRegisterRoulette, "CFRegisterRoulette", &GameConnection::cfRegisterRoulette ); setZoneHandler( ClientZoneIpcType::CFCommenceHandler, "CFDutyAccepted", &GameConnection::cfDutyAccepted); + setZoneHandler( ClientZoneIpcType::ReqEquipDisplayFlagsChange, "ReqEquipDisplayFlagsChange",&GameConnection::reqEquipDisplayFlagsHandler); - setChatHandler( ClientChatIpcType::TellReq, "TellReq", &GameConnection::tellHandler); + setChatHandler( ClientChatIpcType::TellReq, "TellReq", &GameConnection::tellHandler); } @@ -116,7 +117,7 @@ void Core::Network::GameConnection::OnAccept( const std::string & host, uint16_t void Core::Network::GameConnection::OnDisconnect() { - g_log.debug( "DISCONNECT" ); + g_log.debug( "GameConnection DISCONNECT" ); m_pSession = nullptr; } @@ -167,7 +168,7 @@ void Core::Network::GameConnection::OnRecv( std::vector< uint8_t > & buffer ) void Core::Network::GameConnection::OnError( const boost::system::error_code & error ) { - g_log.debug( "ERROR" ); + g_log.debug( "GameConnection ERROR: " + error.message() ); } void Core::Network::GameConnection::queueInPacket( Core::Network::Packets::GamePacketPtr inPacket ) @@ -380,10 +381,21 @@ void Core::Network::GameConnection::handlePackets( const Core::Network::Packets: { g_log.info( "[" + std::string( id ) + "] Session not registered, creating" ); // return; - g_serverZone.createSession( playerId ); + if( !g_serverZone.createSession( playerId ) ) + { + Disconnect(); + return; + } session = g_serverZone.getSession( playerId ); } + if( !session->isValid() ) //TODO: Catch more things in lobby and send real errors + { + g_log.error( "[" + std::string(id) + "] Session INVALID, disconnecting" ); + Disconnect(); + return; + } + // if not set, set the session for this connection if( !m_pSession && session ) m_pSession = session; @@ -418,8 +430,6 @@ void Core::Network::GameConnection::handlePackets( const Core::Network::Packets: sendSinglePacket( &pPe ); } - - break; } diff --git a/src/servers/Server_Zone/Network/GameConnection.h b/src/servers/Server_Zone/Network/GameConnection.h index d9156583..d89ae491 100644 --- a/src/servers/Server_Zone/Network/GameConnection.h +++ b/src/servers/Server_Zone/Network/GameConnection.h @@ -116,10 +116,10 @@ public: DECLARE_HANDLER( gm1Handler ); DECLARE_HANDLER( gm2Handler ); + DECLARE_HANDLER( reqEquipDisplayFlagsHandler ); + DECLARE_HANDLER( tellHandler ); - - }; diff --git a/src/servers/Server_Zone/Network/Handlers/PacketHandlers.cpp b/src/servers/Server_Zone/Network/Handlers/PacketHandlers.cpp index 8a438e39..fc8add9f 100644 --- a/src/servers/Server_Zone/Network/Handlers/PacketHandlers.cpp +++ b/src/servers/Server_Zone/Network/Handlers/PacketHandlers.cpp @@ -285,7 +285,11 @@ void Core::Network::GameConnection::updatePositionHandler( const Packets::GamePa } - +void Core::Network::GameConnection::reqEquipDisplayFlagsHandler( const Packets::GamePacket& inPacket, + Entity::PlayerPtr pPlayer ) +{ + pPlayer->setEquipDisplayFlags( inPacket.getValAt< uint8_t >( 0x20 ) ); +} void Core::Network::GameConnection::zoneLineHandler( const Packets::GamePacket& inPacket, Entity::PlayerPtr pPlayer ) diff --git a/src/servers/Server_Zone/Network/PacketWrappers/PlayerSpawnPacket.h b/src/servers/Server_Zone/Network/PacketWrappers/PlayerSpawnPacket.h index c4be1206..00540d78 100644 --- a/src/servers/Server_Zone/Network/PacketWrappers/PlayerSpawnPacket.h +++ b/src/servers/Server_Zone/Network/PacketWrappers/PlayerSpawnPacket.h @@ -85,7 +85,22 @@ namespace Server { if( pPlayer->getZoningType() != Common::ZoneingType::None ) { - m_data.displayFlags |= 0x20; + m_data.displayFlags |= Entity::Actor::DisplayFlags::Invisible; + } + + if( pPlayer->getEquipDisplayFlags() & Core::Common::EquipDisplayFlags::HideHead ) + { + m_data.displayFlags |= Entity::Actor::DisplayFlags::HideHead; + } + + if( pPlayer->getEquipDisplayFlags() & Core::Common::EquipDisplayFlags::HideWeapon ) + { + m_data.displayFlags |= Entity::Actor::DisplayFlags::HideWeapon; + } + + if( pPlayer->getEquipDisplayFlags() & Core::Common::EquipDisplayFlags::Visor ) + { + m_data.displayFlags |= Entity::Actor::DisplayFlags::Visor; } m_data.targetId = pPlayer->getTargetId(); diff --git a/src/servers/Server_Zone/Session.cpp b/src/servers/Server_Zone/Session.cpp index 5754e2eb..d1daddd7 100644 --- a/src/servers/Server_Zone/Session.cpp +++ b/src/servers/Server_Zone/Session.cpp @@ -9,6 +9,7 @@ Core::Session::Session( uint32_t sessionId ) : m_sessionId( sessionId ) + , m_isValid( false ) , m_lastDataTime( static_cast< uint32_t >( time( nullptr ) ) ) { @@ -50,7 +51,12 @@ bool Core::Session::loadPlayer() m_pPlayer = Entity::PlayerPtr( new Entity::Player() ); if( !m_pPlayer->load( m_sessionId, shared_from_this() ) ) + { + m_isValid = false; return false; + } + + m_isValid = true; return true; @@ -61,6 +67,9 @@ void Core::Session::close() if( m_pZoneConnection ) m_pZoneConnection->Disconnect(); + if( m_pChatConnection ) + m_pChatConnection->Disconnect(); + // remove the session from the player if( m_pPlayer ) // reset the zone, so the zone handler knows to remove the actor @@ -77,6 +86,11 @@ uint32_t Core::Session::getLastDataTime() const return m_lastDataTime; } +bool Core::Session::isValid() const +{ + return m_isValid; +} + void Core::Session::updateLastDataTime() { m_lastDataTime = static_cast< uint32_t >( time( nullptr ) ); diff --git a/src/servers/Server_Zone/Session.h b/src/servers/Server_Zone/Session.h index d1aba601..66b81090 100644 --- a/src/servers/Server_Zone/Session.h +++ b/src/servers/Server_Zone/Session.h @@ -35,6 +35,8 @@ namespace Core { void update(); + bool isValid() const; + Entity::PlayerPtr getPlayer() const; private: @@ -44,6 +46,8 @@ namespace Core { uint32_t m_lastDataTime; + bool m_isValid; + Network::GameConnectionPtr m_pZoneConnection; Network::GameConnectionPtr m_pChatConnection;