From 4d2a8ee36c645b1afb7dd9ed4830b223a52b5d89 Mon Sep 17 00:00:00 2001 From: Adam <893184+NotAdam@users.noreply.github.com> Date: Sat, 19 Aug 2017 11:26:16 +0900 Subject: [PATCH 1/2] Fix getTimeMs not returning correct unix epoch Turned out high_resolution_clock did not return current UTC time. Use system_clock to fix it. --- src/servers/Server_Common/Util/Util.cpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/servers/Server_Common/Util/Util.cpp b/src/servers/Server_Common/Util/Util.cpp index 2d7a6a41..60903c30 100644 --- a/src/servers/Server_Common/Util/Util.cpp +++ b/src/servers/Server_Common/Util/Util.cpp @@ -17,17 +17,14 @@ std::string Core::Util::binaryToHexString( uint8_t* pBinData, uint16_t size ) uint64_t Core::Util::getTimeMs() { - std::chrono::high_resolution_clock::time_point t1 = std::chrono::high_resolution_clock::now(); - auto now_ms = std::chrono::time_point_cast< std::chrono::milliseconds >( t1 ).time_since_epoch().count(); - - return now_ms; + std::chrono::milliseconds epoch = std::chrono::duration_cast< std::chrono::milliseconds >(std::chrono::system_clock::now().time_since_epoch()); + return epoch.count(); } uint64_t Core::Util::getTimeSeconds() { - std::chrono::high_resolution_clock::time_point t1 = std::chrono::high_resolution_clock::now(); - auto now = std::chrono::time_point_cast< std::chrono::seconds >( t1 ).time_since_epoch().count(); - return now; + std::chrono::seconds epoch = std::chrono::duration_cast< std::chrono::seconds >(std::chrono::system_clock::now().time_since_epoch()); + return epoch.count(); } uint64_t Core::Util::getEorzeanTimeStamp() From 98748a4100318b94940f93fd272af6efb9d2b52a Mon Sep 17 00:00:00 2001 From: Adam <893184+NotAdam@users.noreply.github.com> Date: Sat, 19 Aug 2017 11:28:04 +0900 Subject: [PATCH 2/2] Reimplement of CFPenaltyTime Reimplement a730ef3 to reflect recent refactoring. --- sql/charadetail.sql | 1 + src/servers/Server_Common/Common.h | 8 ++- src/servers/Server_Zone/Actor/Player.cpp | 64 +++++++++++++++---- src/servers/Server_Zone/Actor/Player.h | 16 ++++- src/servers/Server_Zone/Actor/PlayerSql.cpp | 19 ++++-- .../ContentFinder/ContentFinder.cpp | 0 .../Server_Zone/ContentFinder/ContentFinder.h | 7 ++ .../DebugCommand/DebugCommandHandler.cpp | 15 +++-- src/servers/Server_Zone/Forwards.h | 11 +++- .../Network/Handlers/CFHandlers.cpp | 55 +++++++++------- 10 files changed, 140 insertions(+), 56 deletions(-) create mode 100644 src/servers/Server_Zone/ContentFinder/ContentFinder.cpp create mode 100644 src/servers/Server_Zone/ContentFinder/ContentFinder.h diff --git a/sql/charadetail.sql b/sql/charadetail.sql index c8430552..923662fc 100644 --- a/sql/charadetail.sql +++ b/sql/charadetail.sql @@ -77,6 +77,7 @@ CREATE TABLE charadetail ( `ContentRetryTime` blob, `ContentJoinTime` int(10) DEFAULT NULL, `ContentClearFlag` blob, + `CFPenaltyUntil` int unsigned NOT NULL DEFAULT '0', `TownWarpFstFlags` binary(2) DEFAULT NULL, `PathId` int(10) DEFAULT NULL, `StepIndex` int(5) DEFAULT NULL, diff --git a/src/servers/Server_Common/Common.h b/src/servers/Server_Common/Common.h index dec1509a..d5f6ff50 100644 --- a/src/servers/Server_Common/Common.h +++ b/src/servers/Server_Common/Common.h @@ -265,7 +265,7 @@ namespace Core { JOB_ASTROLOGIAN = 33, // astro JOB_SAMURAI = 34, // sam JOB_REDMAGE = 35, // red mage - + }; enum PlayerSyncFlags : uint32_t @@ -285,13 +285,15 @@ namespace Core { HpMp = 0x00000800, QuestTracker = 0x00001000, NewGame = 0x00002000, - + // 0x4000 is missing here Unlocks = 0x00008000, PlayTime = 0x00010000, NewAdventurer = 0x00020000, SearchInfo = 0x00040000, GC = 0x00080000, + CFPenaltyTime = 0x00100000, + All = 0xFFFFFFFF, }; @@ -691,7 +693,7 @@ namespace Core { ClassJobChange = 0x05, DefeatMsg = 0x06, GainExpMsg = 0x07, - + LevelUpEffect = 0x0A, ExpChainMsg = 0x0C, diff --git a/src/servers/Server_Zone/Actor/Player.cpp b/src/servers/Server_Zone/Actor/Player.cpp index 345a4b99..f5b65b49 100644 --- a/src/servers/Server_Zone/Actor/Player.cpp +++ b/src/servers/Server_Zone/Actor/Player.cpp @@ -194,7 +194,7 @@ void Core::Entity::Player::calculateStats() auto paramGrowthInfoIt = g_exdData.m_paramGrowthInfoMap.find( level ); if( tribeInfoIt == g_exdData.m_tribeInfoMap.end() || - classInfoIt == g_exdData.m_classJobInfoMap.end() || + classInfoIt == g_exdData.m_classJobInfoMap.end() || paramGrowthInfoIt == g_exdData.m_paramGrowthInfoMap.end() ) return; @@ -204,7 +204,7 @@ void Core::Entity::Player::calculateStats() // TODO: put formula somewhere else... float base = 0.0f; - + if( level < 51 ) base = 0.053f * ( level * level ) + ( 1.022f * level ) - 0.907f + 20; else @@ -224,11 +224,11 @@ void Core::Entity::Player::calculateStats() m_baseStats.attackPotMagic = paramGrowthInfo.base_secondary; m_baseStats.healingPotMagic = paramGrowthInfo.base_secondary; - m_baseStats.max_mp = floor( - floor( - ( ( m_baseStats.pie - base ) * ( static_cast< float >( paramGrowthInfo.piety_scalar ) / 100 ) ) + paramGrowthInfo.mp_const ) * ( static_cast< float >( classInfo.mod_mpcpgp ) / 100 ) + m_baseStats.max_mp = floor( + floor( + ( ( m_baseStats.pie - base ) * ( static_cast< float >( paramGrowthInfo.piety_scalar ) / 100 ) ) + paramGrowthInfo.mp_const ) * ( static_cast< float >( classInfo.mod_mpcpgp ) / 100 ) ); - + m_baseStats.max_hp = floor( floor( ( ( m_baseStats.vit - base ) * ( ( static_cast< float >( paramGrowthInfo.piety_scalar ) ) / 100 ) ) + paramGrowthInfo.hp_mod ) * ( static_cast< float >( classInfo.mod_hp * 0.9f ) / 100 ) * 15 @@ -309,7 +309,7 @@ void Core::Entity::Player::teleport( uint16_t aetheryteId, uint8_t type ) pos = z_pos->getTargetPosition(); rot = z_pos->getTargetRotation(); } - + sendDebug( "Teleport: " + data->placename + " " + data->placename_aethernet + "(" + std::to_string( data->levelId ) + ")" ); @@ -384,7 +384,7 @@ void Core::Entity::Player::setZone( uint32_t zoneId ) sendInventory(); - // set flags, will be reset automatically by zoning ( only on client side though ) + // set flags, will be reset automatically by zoning ( only on client side though ) pPlayer->setStateFlag( PlayerStateFlag::BetweenAreas ); pPlayer->setStateFlag( PlayerStateFlag::BetweenAreas1 ); pPlayer->sendStateFlags(); @@ -522,7 +522,7 @@ void Core::Entity::Player::discover( int16_t map_id, int16_t sub_id ) // map.exd field 12 -> index in one of the two discovery sections, if field 15 is false, need to use 2nd section // section 1 starts at 4 - 2 bytes each - // section to starts at 320 - 4 bytes long + // section to starts at 320 - 4 bytes long int32_t offset = 4; @@ -814,7 +814,7 @@ void Core::Entity::Player::eventActionStart( uint32_t eventId, setCurrentAction( pEventAction ); auto pEvent = getEvent( eventId ); - + if( !pEvent && getEventCount() ) { // We're trying to play a nested event, need to start it first. @@ -1106,7 +1106,7 @@ void Core::Entity::Player::update( int64_t currTime ) for( auto actor : m_inRangeActors ) { - if( isAutoattackOn() && + if( isAutoattackOn() && actor->getId() == m_targetId && actor->isAlive() && mainWeap && @@ -1462,7 +1462,7 @@ void Core::Entity::Player::autoAttack( ActorPtr pTarget ) //uint64_t tick = Util::getTimeMs(); //srand(static_cast< uint32_t >(tick)); - uint32_t damage = mainWeap->getAutoAttackDmg() + rand() % 12; + uint32_t damage = mainWeap->getAutoAttackDmg() + rand() % 12; uint32_t variation = 0 + rand() % 3; if( getClass() == 5 || getClass() == 23 || getClass() == 31 ) @@ -1507,14 +1507,14 @@ void Core::Entity::Player::autoAttack( ActorPtr pTarget ) } pTarget->takeDamage(damage); - + } void Core::Entity::Player::handleScriptSkill( uint32_t type, uint32_t actionId, uint64_t param1, uint64_t param2, Entity::Actor& pTarget ) { sendDebug( std::to_string( pTarget.getId() ) ); sendDebug( "Handle script skill type: " + std::to_string( type ) ); - + switch( type ) { @@ -1569,3 +1569,39 @@ void Core::Entity::Player::handleScriptSkill( uint32_t type, uint32_t actionId, break; } } + + +///////////////////////////// +// Content Finder +///////////////////////////// +uint32_t Core::Entity::Player::getCFPenaltyTimestamp() const +{ + return m_cfPenaltyUntil; +} + +void Core::Entity::Player::setCFPenaltyTimestamp( uint32_t timestamp ) +{ + m_cfPenaltyUntil = timestamp; + setSyncFlag( PlayerSyncFlags::CFPenaltyTime ); +} + +uint32_t Core::Entity::Player::getCFPenaltyMinutes() const +{ + auto currentTimestamp = Core::Util::getTimeSeconds(); + auto endTimestamp = getCFPenaltyTimestamp(); + + // check if penalty timestamp already passed current time + if (currentTimestamp > endTimestamp) + { + return 0; + } + + auto deltaTime = endTimestamp - currentTimestamp; + return static_cast< uint32_t > ( ceil( static_cast< float > (deltaTime) / 60 ) ); +} + +void Core::Entity::Player::setCFPenaltyMinutes( uint32_t minutes ) +{ + auto currentTimestamp = Core::Util::getTimeSeconds(); + setCFPenaltyTimestamp(static_cast< uint32_t >( currentTimestamp + minutes * 60 )); +} diff --git a/src/servers/Server_Zone/Actor/Player.h b/src/servers/Server_Zone/Actor/Player.h index 6e3d459a..c86fc3d2 100644 --- a/src/servers/Server_Zone/Actor/Player.h +++ b/src/servers/Server_Zone/Actor/Player.h @@ -78,7 +78,7 @@ public: void checkEvent( uint32_t eventId ); - + // Events ////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -484,6 +484,16 @@ public: void handleScriptSkill( uint32_t type, uint32_t actionId, uint64_t param1, uint64_t param2, Entity::Actor& target ); + // Content Finder handling + ////////////////////////////////////////////////////////////////////////////////////////////////////// + /*! Get an unix time when the player can register into content finder again. */ + uint32_t getCFPenaltyTimestamp() const; + + /*! Set an unix time when the player can register into content finder again. */ + void setCFPenaltyTimestamp( uint32_t timestamp ); + + uint32_t getCFPenaltyMinutes() const; + void setCFPenaltyMinutes( uint32_t minutes ); private: uint32_t m_lastWrite; uint32_t m_lastPing; @@ -583,7 +593,7 @@ private: bool m_bAutoattack; Common::ZoneingType m_zoningType; - + bool m_bMarkedForZoning; uint32_t m_updateFlags; bool m_bNewAdventurer; @@ -599,6 +609,8 @@ private: uint8_t m_gc; uint8_t m_gcRank[3]; + // content finder info + uint32_t m_cfPenaltyUntil; // unix time }; } diff --git a/src/servers/Server_Zone/Actor/PlayerSql.cpp b/src/servers/Server_Zone/Actor/PlayerSql.cpp index 1de2d549..e904dead 100644 --- a/src/servers/Server_Zone/Actor/PlayerSql.cpp +++ b/src/servers/Server_Zone/Actor/PlayerSql.cpp @@ -43,7 +43,8 @@ bool Core::Entity::Player::load( uint32_t charId, Core::SessionPtr pSession ) // TODO: can't help but think that the whole player loading could be handled better... const std::string char_id_str = std::to_string( charId ); - auto pQR = g_database.query( "SELECT c.Name, " + auto pQR = g_database.query( "SELECT " + "c.Name, " "c.PrimaryTerritoryId, " "c.Hp, " "c.Mp, " @@ -53,7 +54,7 @@ bool Core::Entity::Player::load( uint32_t charId, Core::SessionPtr pSession ) "c.Pos_0_1, " "c.Pos_0_2, " "c.Pos_0_3, " - "c.FirstLogin, " + "c.FirstLogin, " // 10 "c.Customize, " "c.ModelMainWeapon, " "c.ModelSubWeapon, " @@ -63,7 +64,7 @@ bool Core::Entity::Player::load( uint32_t charId, Core::SessionPtr pSession ) "cd.BirthMonth, " "cd.Status, " "cd.Class, " - "cd.Homepoint, " + "cd.Homepoint, " // 20 "cd.HowTo, " "c.ContentId, " "c.Voice, " @@ -73,11 +74,12 @@ bool Core::Entity::Player::load( uint32_t charId, Core::SessionPtr pSession ) "cd.Aetheryte, " "cd.unlocks, " "cd.Discovery, " - "cd.StartTown, " + "cd.StartTown, " // 30 "cd.TotalPlayTime, " "c.IsNewAdventurer, " "cd.GrandCompany, " - "cd.GrandCompanyRank " + "cd.GrandCompanyRank, " + "cd.CFPenaltyUntil " "FROM charabase AS c " " INNER JOIN charadetail AS cd " " ON c.CharacterId = cd.CharacterId " @@ -166,6 +168,8 @@ bool Core::Entity::Player::load( uint32_t charId, Core::SessionPtr pSession ) m_gc = field[33].getUInt8(); field[34].getBinary( reinterpret_cast< char* >( m_gcRank ), 3 ); + m_cfPenaltyUntil = field[35].getUInt32(); + m_pCell = nullptr; if( !loadActiveQuests() || !loadClassData() || !loadSearchInfo() ) @@ -327,7 +331,10 @@ void Core::Entity::Player::createUpdateSql() charaDetailSet.insert( " GrandCompanyRank = UNHEX('" + std::string( Util::binaryToHexString( reinterpret_cast< uint8_t* >( m_gcRank ), sizeof( m_gcRank ) ) ) + "')" ); } - + if( m_updateFlags & PlayerSyncFlags::CFPenaltyTime ) + { + charaDetailSet.insert( " CFPenaltyUntil = " + std::to_string( m_cfPenaltyUntil ) ); + } if( m_updateFlags & PlayerSyncFlags::ExpLevel ) { diff --git a/src/servers/Server_Zone/ContentFinder/ContentFinder.cpp b/src/servers/Server_Zone/ContentFinder/ContentFinder.cpp new file mode 100644 index 00000000..e69de29b diff --git a/src/servers/Server_Zone/ContentFinder/ContentFinder.h b/src/servers/Server_Zone/ContentFinder/ContentFinder.h new file mode 100644 index 00000000..c0800273 --- /dev/null +++ b/src/servers/Server_Zone/ContentFinder/ContentFinder.h @@ -0,0 +1,7 @@ +#ifndef _CONTENTFINDER_H +#define _CONTENTFINDER_H + +#include "../Forwards.h" + + +#endif diff --git a/src/servers/Server_Zone/DebugCommand/DebugCommandHandler.cpp b/src/servers/Server_Zone/DebugCommand/DebugCommandHandler.cpp index fac2c3e3..09dde13c 100644 --- a/src/servers/Server_Zone/DebugCommand/DebugCommandHandler.cpp +++ b/src/servers/Server_Zone/DebugCommand/DebugCommandHandler.cpp @@ -85,7 +85,7 @@ void Core::DebugCommandHandler::execCommand( char * data, Core::Entity::PlayerPt // no parameters, just get the command commandString = tmpCommand; - // try to retrieve the command + // try to retrieve the command auto it = m_commandMap.find( commandString ); if( it == m_commandMap.end() ) @@ -104,7 +104,6 @@ void Core::DebugCommandHandler::execCommand( char * data, Core::Entity::PlayerPt } - /////////////////////////////////////////////////////////////////////////////////////// // Definition of the commands /////////////////////////////////////////////////////////////////////////////////////// @@ -267,8 +266,6 @@ void Core::DebugCommandHandler::set( char * data, Core::Entity::PlayerPtr pPlaye sscanf( params.c_str(), "%d", &id ); - - uint8_t typeshift = 0x6; uint8_t mask = 1 << typeshift; id &= mask; @@ -282,6 +279,14 @@ void Core::DebugCommandHandler::set( char * data, Core::Entity::PlayerPtr pPlaye sscanf( params.c_str(), "%d", &id ); pPlayer->sendDebug( std::to_string( pPlayer->actionHasCastTime( id ) ) ); } + else if ( subCommand == "cfpenalty" ) + { + int32_t minutes; + + sscanf( params.c_str(), "%d", &minutes ); + + pPlayer->setCFPenaltyMinutes( minutes ); + } } @@ -394,7 +399,7 @@ void Core::DebugCommandHandler::add( char * data, Core::Entity::PlayerPtr pPlaye sscanf( params.c_str(), "%x %x %x %x %x %x %x %x", &opcode, ¶m1, ¶m2, ¶m3, ¶m4, ¶m5, ¶m6, &playerId ); pPlayer->sendNotice( "Injecting ACTOR_CONTROL " + std::to_string( opcode ) ); - + Network::Packets::GamePacketNew< Network::Packets::Server::FFXIVIpcActorControl143 > actorControl( playerId, pPlayer->getId() ); actorControl.data().category = opcode; actorControl.data().param1 = param1; diff --git a/src/servers/Server_Zone/Forwards.h b/src/servers/Server_Zone/Forwards.h index 87ec8bd2..c0f48782 100644 --- a/src/servers/Server_Zone/Forwards.h +++ b/src/servers/Server_Zone/Forwards.h @@ -7,9 +7,9 @@ #define TYPE_FORWARD( x ) \ class x; \ typedef boost::shared_ptr< x > x ## Ptr; \ -typedef std::vector< x > x ## PtrList; +typedef std::vector< x > x ## PtrList; -namespace Core +namespace Core { TYPE_FORWARD( Cell ); TYPE_FORWARD( Zone ); @@ -62,6 +62,11 @@ namespace Core } } + namespace ContentFinder + { + TYPE_FORWARD( ContentFinder ); + } + namespace Scripting { typedef std::function< void( Entity::Player&, uint32_t, uint16_t, uint16_t, uint16_t ) > EventReturnCallback; @@ -72,4 +77,4 @@ namespace Core } -#endif \ No newline at end of file +#endif diff --git a/src/servers/Server_Zone/Network/Handlers/CFHandlers.cpp b/src/servers/Server_Zone/Network/Handlers/CFHandlers.cpp index 62efce32..400238c0 100644 --- a/src/servers/Server_Zone/Network/Handlers/CFHandlers.cpp +++ b/src/servers/Server_Zone/Network/Handlers/CFHandlers.cpp @@ -27,46 +27,55 @@ using namespace Core::Network::Packets::Server; void Core::Network::GameConnection::cfDutyInfoRequest( const Packets::GamePacket& inPacket, Entity::PlayerPtr pPlayer ) { - GamePacketNew< FFXIVIpcCFDutyInfo > dutyInfoPacket( pPlayer->getId() ); - queueOutPacket( dutyInfoPacket ); + GamePacketNew< FFXIVIpcCFDutyInfo > dutyInfoPacket( pPlayer->getId() ); - GamePacketNew< FFXIVIpcCFPlayerInNeed > inNeedsPacket( pPlayer->getId() ); - queueOutPacket( inNeedsPacket ); + auto penaltyMinutes = pPlayer->getCFPenaltyMinutes(); + if (penaltyMinutes > 255) + { + // cap it since it's uint8_t in packets + penaltyMinutes = 255; + } + dutyInfoPacket.data().penaltyTime = penaltyMinutes; + + queueOutPacket( dutyInfoPacket ); + + GamePacketNew< FFXIVIpcCFPlayerInNeed > inNeedsPacket( pPlayer->getId() ); + queueOutPacket( inNeedsPacket ); } void Core::Network::GameConnection::cfRegisterDuty( const Packets::GamePacket& inPacket, Entity::PlayerPtr pPlayer) { - // TODO use for loop for this - auto contentId1 = inPacket.getValAt< uint16_t >( 46 ); - auto contentId2 = inPacket.getValAt< uint16_t >( 48 ); - auto contentId3 = inPacket.getValAt< uint16_t >( 50 ); - auto contentId4 = inPacket.getValAt< uint16_t >( 52 ); - auto contentId5 = inPacket.getValAt< uint16_t >( 54 ); + // TODO use for loop for this + auto contentId1 = inPacket.getValAt< uint16_t >( 46 ); + auto contentId2 = inPacket.getValAt< uint16_t >( 48 ); + auto contentId3 = inPacket.getValAt< uint16_t >( 50 ); + auto contentId4 = inPacket.getValAt< uint16_t >( 52 ); + auto contentId5 = inPacket.getValAt< uint16_t >( 54 ); - pPlayer->sendDebug("Duty register request"); - pPlayer->sendDebug("ContentId1" + std::to_string(contentId1)); - pPlayer->sendDebug("ContentId2" + std::to_string(contentId2)); - pPlayer->sendDebug("ContentId3" + std::to_string(contentId3)); - pPlayer->sendDebug("ContentId4" + std::to_string(contentId4)); - pPlayer->sendDebug("ContentId5" + std::to_string(contentId5)); + pPlayer->sendDebug("Duty register request"); + pPlayer->sendDebug("ContentId1" + std::to_string(contentId1)); + pPlayer->sendDebug("ContentId2" + std::to_string(contentId2)); + pPlayer->sendDebug("ContentId3" + std::to_string(contentId3)); + pPlayer->sendDebug("ContentId4" + std::to_string(contentId4)); + pPlayer->sendDebug("ContentId5" + std::to_string(contentId5)); - // let's cancel it because otherwise you can't register it again - GamePacketNew< FFXIVIpcCFNotify > cfCancelPacket( pPlayer->getId() ); - cfCancelPacket.data().state1 = 3; - cfCancelPacket.data().state2 = 1; // Your registration is withdrawn. - queueOutPacket( cfCancelPacket ); + // let's cancel it because otherwise you can't register it again + GamePacketNew< FFXIVIpcCFNotify > cfCancelPacket( pPlayer->getId() ); + cfCancelPacket.data().state1 = 3; + cfCancelPacket.data().state2 = 1; // Your registration is withdrawn. + queueOutPacket( cfCancelPacket ); } void Core::Network::GameConnection::cfRegisterRoulette( const Packets::GamePacket& inPacket, Entity::PlayerPtr pPlayer) { - pPlayer->sendDebug("Roulette register"); + pPlayer->sendDebug("Roulette register"); } void Core::Network::GameConnection::cfDutyAccepted( const Packets::GamePacket& inPacket, Entity::PlayerPtr pPlayer) { - pPlayer->sendDebug("TODO: Duty accept"); + pPlayer->sendDebug("TODO: Duty accept"); }