mirror of
https://github.com/SapphireServer/Sapphire.git
synced 2025-06-13 19:07:45 +00:00
Merge pull request #721 from Taezen/develop-map
Including support for basic map icons
This commit is contained in:
commit
0ebc900cc4
18 changed files with 1007 additions and 21 deletions
|
@ -4582,9 +4582,11 @@ Sapphire::Data::GuildleveAssignment::GuildleveAssignment( uint32_t row_id, Sapph
|
|||
{
|
||||
auto row = exdData->m_GuildleveAssignmentDat.get_row( row_id );
|
||||
type = exdData->getField< std::string >( row, 0 );
|
||||
typeId = exdData->getField< uint8_t >( row, 1 );
|
||||
assignmentTalk = exdData->getField< uint32_t >( row, 2 );
|
||||
quest.push_back( exdData->getField< uint32_t >( row, 3 ) );
|
||||
quest.push_back( exdData->getField< uint32_t >( row, 4 ) );
|
||||
grandCompanyRank = exdData->getField< uint8_t >( row, 10 );
|
||||
}
|
||||
|
||||
Sapphire::Data::GuildleveAssignmentCategory::GuildleveAssignmentCategory( uint32_t row_id, Sapphire::Data::ExdDataGenerated* exdData )
|
||||
|
@ -7669,13 +7671,16 @@ Sapphire::Data::Quest::Quest( uint32_t row_id, Sapphire::Data::ExdDataGenerated*
|
|||
classJobCategory1 = exdData->getField< uint8_t >( row, 6 );
|
||||
classJobLevel1 = exdData->getField< uint16_t >( row, 7 );
|
||||
previousQuestJoin = exdData->getField< uint8_t >( row, 8 );
|
||||
previousQuest0 = exdData->getField< uint32_t >( row, 9 );
|
||||
previousQuest1 = exdData->getField< uint32_t >( row, 11 );
|
||||
previousQuest2 = exdData->getField< uint32_t >( row, 12 );
|
||||
previousQuest.push_back( exdData->getField< uint32_t >( row, 9 ) );
|
||||
previousQuest0Sequence = exdData->getField< uint8_t >( row, 10 );
|
||||
previousQuest.push_back( exdData->getField< uint32_t >( row, 11 ) );
|
||||
previousQuest.push_back( exdData->getField< uint32_t >( row, 12 ) );
|
||||
questLockJoin = exdData->getField< uint8_t >( row, 13 );
|
||||
questLock.push_back( exdData->getField< uint32_t >( row, 14 ) );
|
||||
questLock.push_back( exdData->getField< uint32_t >( row, 15 ) );
|
||||
header = exdData->getField< uint16_t >( row, 16 );
|
||||
startTown = exdData->getField< uint8_t >( row, 17 );
|
||||
classJobUnlockFlag = exdData->getField< uint8_t >( row, 18 );
|
||||
classJobUnlock = exdData->getField< uint8_t >( row, 19 );
|
||||
grandCompany = exdData->getField< uint8_t >( row, 20 );
|
||||
grandCompanyRank = exdData->getField< uint8_t >( row, 21 );
|
||||
|
@ -7691,6 +7696,8 @@ Sapphire::Data::Quest::Quest( uint32_t row_id, Sapphire::Data::ExdDataGenerated*
|
|||
beastTribe = exdData->getField< uint8_t >( row, 31 );
|
||||
beastReputationRank = exdData->getField< uint8_t >( row, 32 );
|
||||
beastReputationValue = exdData->getField< uint16_t >( row, 33 );
|
||||
satisfactionNpc = exdData->getField< uint8_t >( row, 34 );
|
||||
satisfactionLevel = exdData->getField< uint8_t >( row, 35 );
|
||||
mountRequired = exdData->getField< int32_t >( row, 36 );
|
||||
isHouseRequired = exdData->getField< bool >( row, 37 );
|
||||
deliveryQuest = exdData->getField< uint8_t >( row, 38 );
|
||||
|
|
|
@ -4366,8 +4366,10 @@ struct GuideTitle
|
|||
struct GuildleveAssignment
|
||||
{
|
||||
std::string type;
|
||||
uint8_t typeId;
|
||||
uint32_t assignmentTalk;
|
||||
std::vector< uint32_t > quest;
|
||||
uint8_t grandCompanyRank;
|
||||
|
||||
GuildleveAssignment( uint32_t row_id, Sapphire::Data::ExdDataGenerated* exdData );
|
||||
};
|
||||
|
@ -6324,12 +6326,13 @@ struct Quest
|
|||
uint8_t classJobCategory1;
|
||||
uint16_t classJobLevel1;
|
||||
uint8_t previousQuestJoin;
|
||||
uint32_t previousQuest0;
|
||||
uint32_t previousQuest1;
|
||||
uint32_t previousQuest2;
|
||||
std::vector< uint32_t > previousQuest;
|
||||
uint8_t previousQuest0Sequence;
|
||||
uint8_t questLockJoin;
|
||||
std::vector< uint32_t > questLock;
|
||||
uint16_t header;
|
||||
uint8_t startTown;
|
||||
uint8_t classJobUnlockFlag;
|
||||
uint8_t classJobUnlock;
|
||||
uint8_t grandCompany;
|
||||
uint8_t grandCompanyRank;
|
||||
|
@ -6343,6 +6346,8 @@ struct Quest
|
|||
uint8_t beastTribe;
|
||||
uint8_t beastReputationRank;
|
||||
uint16_t beastReputationValue;
|
||||
uint8_t satisfactionNpc;
|
||||
uint8_t satisfactionLevel;
|
||||
int32_t mountRequired;
|
||||
bool isHouseRequired;
|
||||
uint8_t deliveryQuest;
|
||||
|
|
|
@ -215,7 +215,19 @@ namespace Sapphire::Network::ActorControl
|
|||
SetFavorite = 0x1FC,
|
||||
LearnTeleport = 0x1FD,
|
||||
|
||||
OpenRecommendationGuide = 0x200,
|
||||
/*!
|
||||
* param1 = event type bitmask
|
||||
* 1 = Quest
|
||||
* 2 = GuildLeveAssignment
|
||||
* 4 = GuildOrderGuide
|
||||
* 8 = TripleTriad
|
||||
* 16 = CustomTalk
|
||||
* 32 = PreHandler
|
||||
*/
|
||||
BeginMapUpdate = 0x1FF,
|
||||
FinishMapUpdate = 0x200,
|
||||
|
||||
//OpenRecommendationGuide = 0x200,
|
||||
ArmoryErrorMsg = 0x201,
|
||||
|
||||
AchievementPopup = 0x203,
|
||||
|
|
|
@ -282,6 +282,14 @@ namespace Sapphire::Network::Packets
|
|||
DailyQuests = 0x0331, // updated 5.58
|
||||
DailyQuestRepeatFlags = 0x01D1, // updated 5.58
|
||||
|
||||
MapUpdate = 0x03A2, // updated 5.58
|
||||
MapUpdate4 = 0x0284, // updated 5.58
|
||||
MapUpdate8 = 0x01BC, // updated 5.58
|
||||
MapUpdate16 = 0x02D1, // updated 5.58
|
||||
MapUpdate32 = 0x00DB, // updated 5.58
|
||||
MapUpdate64 = 0x0368, // updated 5.58
|
||||
MapUpdate128 = 0x0349, // updated 5.58
|
||||
|
||||
/// Doman Mahjong //////////////////////////////////////
|
||||
MahjongOpenGui = 0x02A4, // only available in mahjong instance
|
||||
MahjongNextRound = 0x02BD, // initial hands(baipai), # of riichi(wat), winds, honba, score and stuff
|
||||
|
|
|
@ -928,12 +928,11 @@ namespace Sapphire::Network::Packets::Server
|
|||
|
||||
uint8_t unknown5;
|
||||
uint32_t unknown8;
|
||||
uint16_t festivalId;
|
||||
uint16_t additionalFestivalId;
|
||||
uint32_t unknown9;
|
||||
uint32_t unknown10;
|
||||
uint32_t unknown11;
|
||||
uint32_t unknown12[4];
|
||||
uint32_t festivalId;
|
||||
uint32_t unknown12[3];
|
||||
uint32_t additionalFestivalId;
|
||||
uint32_t unknown13[3];
|
||||
Common::FFXIVARR_POSITION3 pos;
|
||||
uint32_t unknown14[3];
|
||||
|
@ -2289,6 +2288,60 @@ namespace Sapphire::Network::Packets::Server
|
|||
uint16_t padding3;
|
||||
} actors[2];
|
||||
};
|
||||
|
||||
//For quests this is only used for pre-accepted ones. Accepted quests are getting handled by the client.
|
||||
template< int ArgCount >
|
||||
struct FFXIVIpcMapUpdateN
|
||||
{
|
||||
uint8_t entryCount;
|
||||
uint8_t padding[ 3 ];
|
||||
uint32_t iconIds[ ArgCount ];
|
||||
uint32_t levelIds[ ArgCount ];
|
||||
uint32_t eventIds[ ArgCount ]; // possible event ids for this: Quest, GuildLeveAssignment, GuildOrderGuide, TripleTriad, CustomTalk, PreHandler
|
||||
uint8_t additionalData[ ArgCount ]; // use unknown
|
||||
};
|
||||
|
||||
struct FFXIVIpcMapUpdate :
|
||||
FFXIVIpcBasePacket< MapUpdate >,
|
||||
FFXIVIpcMapUpdateN< 2 >
|
||||
{
|
||||
};
|
||||
|
||||
struct FFXIVIpcMapUpdate4 :
|
||||
FFXIVIpcBasePacket< MapUpdate4 >,
|
||||
FFXIVIpcMapUpdateN< 4 >
|
||||
{
|
||||
};
|
||||
|
||||
struct FFXIVIpcMapUpdate8 :
|
||||
FFXIVIpcBasePacket< MapUpdate8 >,
|
||||
FFXIVIpcMapUpdateN< 8 >
|
||||
{
|
||||
};
|
||||
|
||||
struct FFXIVIpcMapUpdate16 :
|
||||
FFXIVIpcBasePacket< MapUpdate16 >,
|
||||
FFXIVIpcMapUpdateN< 16 >
|
||||
{
|
||||
};
|
||||
|
||||
struct FFXIVIpcMapUpdate32 :
|
||||
FFXIVIpcBasePacket< MapUpdate32 >,
|
||||
FFXIVIpcMapUpdateN< 32 >
|
||||
{
|
||||
};
|
||||
|
||||
struct FFXIVIpcMapUpdate64 :
|
||||
FFXIVIpcBasePacket< MapUpdate64 >,
|
||||
FFXIVIpcMapUpdateN< 64 >
|
||||
{
|
||||
};
|
||||
|
||||
struct FFXIVIpcMapUpdate128 :
|
||||
FFXIVIpcBasePacket< MapUpdate128 >,
|
||||
FFXIVIpcMapUpdateN< 128 >
|
||||
{
|
||||
};
|
||||
}
|
||||
|
||||
#endif /*_CORE_NETWORK_PACKETS_SERVER_IPC_H*/
|
||||
|
|
|
@ -129,7 +129,7 @@ uint32_t Util::getTimeSeconds()
|
|||
|
||||
uint64_t Util::getEorzeanTimeStamp()
|
||||
{
|
||||
return static_cast< uint64_t >( getTimeSeconds() * 20.571428571428573f );
|
||||
return static_cast< uint64_t >( getTimeSeconds() * 20.571428571428573 );
|
||||
}
|
||||
|
||||
void Util::valueToFlagByteIndexValue( uint32_t inVal, uint8_t& outVal, uint16_t& outIndex )
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "Manager/HousingMgr.h"
|
||||
#include "Manager/TerritoryMgr.h"
|
||||
#include "Manager/RNGMgr.h"
|
||||
#include "Manager/MapMgr.h"
|
||||
|
||||
#include "Territory/Territory.h"
|
||||
#include "Territory/ZonePosition.h"
|
||||
|
@ -730,7 +731,7 @@ void Sapphire::Entity::Player::learnSong( uint8_t songId, uint32_t itemId )
|
|||
queuePacket( makeActorControlSelf( getId(), ToggleOrchestrionUnlock, songId, 1, itemId ) );
|
||||
}
|
||||
|
||||
bool Sapphire::Entity::Player::isActionLearned( uint8_t actionId ) const
|
||||
bool Sapphire::Entity::Player::isActionLearned( uint32_t actionId ) const
|
||||
{
|
||||
uint16_t index;
|
||||
uint8_t value;
|
||||
|
@ -1286,6 +1287,17 @@ const uint8_t* Sapphire::Entity::Player::getMountGuideBitmask() const
|
|||
return m_mountGuide;
|
||||
}
|
||||
|
||||
const bool Sapphire::Entity::Player::hasMount( uint32_t mountId ) const
|
||||
{
|
||||
auto& exdData = Common::Service< Data::ExdDataGenerated >::ref();
|
||||
auto mount = exdData.get< Data::Mount >( mountId );
|
||||
|
||||
if( mount->order == -1 || mount->modelChara == 0 )
|
||||
return false;
|
||||
|
||||
return m_mountGuide[ mount->order / 8 ] & ( 1 << ( mount->order % 8 ) );
|
||||
}
|
||||
|
||||
uint64_t Sapphire::Entity::Player::getContentId() const
|
||||
{
|
||||
return m_contentId;
|
||||
|
@ -1890,6 +1902,8 @@ Sapphire::Entity::Player::sendZoneInPackets( uint32_t param1, uint32_t param2 =
|
|||
|
||||
setZoningType( Common::ZoneingType::None );
|
||||
unsetStateFlag( PlayerStateFlag::BetweenAreas );
|
||||
|
||||
Common::Service< MapMgr >::ref().updateAll( *this );
|
||||
}
|
||||
|
||||
void Sapphire::Entity::Player::finishZoning()
|
||||
|
|
|
@ -194,6 +194,8 @@ namespace Sapphire::Entity
|
|||
/*! remove a given quest */
|
||||
void removeQuest( uint16_t questId );
|
||||
|
||||
bool isQuestCompleted( uint16_t questId );
|
||||
|
||||
/*! add a quest to the completed quests mask */
|
||||
void updateQuestsCompleted( uint32_t questId );
|
||||
|
||||
|
@ -644,7 +646,7 @@ namespace Sapphire::Entity
|
|||
void learnSong( uint8_t songId, uint32_t itemId );
|
||||
|
||||
/*! check if an action is already unlocked in the bitmask. */
|
||||
bool isActionLearned( uint8_t actionId ) const;
|
||||
bool isActionLearned( uint32_t actionId ) const;
|
||||
|
||||
/*! return a const pointer to the unlock bitmask array */
|
||||
const uint8_t* getUnlockBitmask() const;
|
||||
|
@ -655,6 +657,8 @@ namespace Sapphire::Entity
|
|||
/*! return a const pointer to the mount guide bitmask array */
|
||||
const uint8_t* getMountGuideBitmask() const;
|
||||
|
||||
const bool hasMount( uint32_t mountId ) const;
|
||||
|
||||
bool checkAction() override;
|
||||
|
||||
bool hasQueuedAction() const;
|
||||
|
@ -950,6 +954,7 @@ namespace Sapphire::Entity
|
|||
uint16_t calculateEquippedGearItemLevel();
|
||||
|
||||
ItemPtr getEquippedWeapon();
|
||||
ItemPtr getEquippedSecondaryWeapon();
|
||||
|
||||
/*! return the current amount of currency of type */
|
||||
uint32_t getCurrency( Common::CurrencyType type );
|
||||
|
|
|
@ -939,6 +939,11 @@ Sapphire::ItemPtr Sapphire::Entity::Player::getEquippedWeapon()
|
|||
return m_storageMap[ GearSet0 ]->getItem( GearSetSlot::MainHand );
|
||||
}
|
||||
|
||||
Sapphire::ItemPtr Sapphire::Entity::Player::getEquippedSecondaryWeapon()
|
||||
{
|
||||
return m_storageMap[ InventoryType::GearSet0 ]->getItem( GearSetSlot::OffHand );
|
||||
}
|
||||
|
||||
uint8_t Sapphire::Entity::Player::getFreeSlotsInBags()
|
||||
{
|
||||
uint8_t slots = 0;
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#include "Network/GameConnection.h"
|
||||
#include "Network/PacketWrappers/QuestMessagePacket.h"
|
||||
|
||||
#include "Manager/MapMgr.h"
|
||||
|
||||
#include "Session.h"
|
||||
|
||||
using namespace Sapphire::Common;
|
||||
|
@ -42,6 +44,11 @@ void Sapphire::Entity::Player::removeQuest( uint16_t questId )
|
|||
|
||||
if( ( idx != -1 ) && ( m_activeQuests[ idx ] != nullptr ) )
|
||||
{
|
||||
std::shared_ptr< QuestActive > pQuest = m_activeQuests[ idx ];
|
||||
m_activeQuests[ idx ].reset();
|
||||
|
||||
Common::Service< World::Manager::MapMgr >::ref().updateQuests( *this );
|
||||
|
||||
auto questUpdatePacket = makeZonePacket< FFXIVIpcQuestUpdate >( getId() );
|
||||
questUpdatePacket->data().slot = static_cast< uint8_t >( idx );
|
||||
questUpdatePacket->data().questInfo.c.questId = 0;
|
||||
|
@ -54,9 +61,6 @@ void Sapphire::Entity::Player::removeQuest( uint16_t questId )
|
|||
m_questTracking[ ii ] = -1;
|
||||
}
|
||||
|
||||
std::shared_ptr< QuestActive > pQuest = m_activeQuests[ idx ];
|
||||
m_activeQuests[ idx ].reset();
|
||||
|
||||
m_questIdToQuestIdx.erase( questId );
|
||||
m_questIdxToQuestId.erase( idx );
|
||||
|
||||
|
@ -916,6 +920,8 @@ void Sapphire::Entity::Player::updateQuest( uint16_t questId, uint8_t sequence )
|
|||
m_questIdToQuestIdx[ questId ] = idx;
|
||||
m_questIdxToQuestId[ idx ] = questId;
|
||||
|
||||
Common::Service< World::Manager::MapMgr >::ref().updateQuests( *this );
|
||||
|
||||
auto questUpdatePacket = makeZonePacket< FFXIVIpcQuestUpdate >( getId() );
|
||||
questUpdatePacket->data().slot = idx;
|
||||
questUpdatePacket->data().questInfo = *pNewQuest;
|
||||
|
@ -1013,6 +1019,11 @@ Sapphire::Entity::Player::sendQuestMessage( uint32_t questId, int8_t msgId, uint
|
|||
}
|
||||
|
||||
|
||||
bool Sapphire::Entity::Player::isQuestCompleted( uint16_t questId )
|
||||
{
|
||||
return ( m_questCompleteFlags[ questId / 8 ] & ( 0x80 >> ( questId % 8 ) ) );
|
||||
}
|
||||
|
||||
void Sapphire::Entity::Player::updateQuestsCompleted( uint32_t questId )
|
||||
{
|
||||
uint16_t index = questId / 8;
|
||||
|
@ -1032,6 +1043,8 @@ void Sapphire::Entity::Player::removeQuestsCompleted( uint32_t questId )
|
|||
|
||||
m_questCompleteFlags[ index ] ^= value;
|
||||
|
||||
Common::Service< World::Manager::MapMgr >::ref().updateQuests( *this );
|
||||
|
||||
}
|
||||
|
||||
bool Sapphire::Entity::Player::giveQuestRewards( uint32_t questId, uint32_t optionalChoice )
|
||||
|
|
|
@ -78,11 +78,20 @@ namespace Sapphire::Event
|
|||
FcTalk = 0x001F,
|
||||
Adventure = 0x0021,
|
||||
DailyQuestSupply = 0x0022,
|
||||
TripleTriad = 0x0023,
|
||||
PreHandler = 0x0036,
|
||||
ICDirector = 0x8003,
|
||||
PublicContentDirector = 0x8004,
|
||||
QuestBattleDirector = 0x8006,
|
||||
};
|
||||
|
||||
enum class QuestAvailability : uint8_t
|
||||
{
|
||||
Invisible,
|
||||
Available,
|
||||
Locked
|
||||
};
|
||||
|
||||
using SceneReturnCallback = std::function< void( Entity::Player&, const SceneResult& ) >;
|
||||
using SceneChainCallback = std::function< void( Entity::Player& ) >;
|
||||
using EventFinishCallback = std::function< void( Entity::Player&, uint64_t ) >;
|
||||
|
|
685
src/world/Manager/MapMgr.cpp
Normal file
685
src/world/Manager/MapMgr.cpp
Normal file
|
@ -0,0 +1,685 @@
|
|||
#include <Common.h>
|
||||
#include <Service.h>
|
||||
|
||||
#include <Exd/ExdDataGenerated.h>
|
||||
|
||||
#include <Event/EventHandler.h>
|
||||
|
||||
#include <Network/CommonActorControl.h>
|
||||
#include <Network/PacketDef/Zone/ServerZoneDef.h>
|
||||
#include <Network/PacketWrappers/ActorControlSelfPacket.h>
|
||||
|
||||
#include <Util/Util.cpp>
|
||||
|
||||
#include <Actor/Player.h>
|
||||
|
||||
#include <Script/ScriptMgr.h>
|
||||
#include <Script/NativeScriptMgr.h>
|
||||
|
||||
#include <Territory/InstanceObjectCache.h>
|
||||
#include <datReader/DatCategories/bg/lgb.h>
|
||||
|
||||
#include "MapMgr.h"
|
||||
#include "TerritoryMgr.h"
|
||||
|
||||
using namespace Sapphire::Event;
|
||||
using namespace Sapphire::Network::Packets;
|
||||
using namespace Sapphire::Network::Packets::Server;
|
||||
|
||||
Sapphire::World::Manager::MapMgr::MapMgr()
|
||||
{
|
||||
auto& exdData = Common::Service< Data::ExdDataGenerated >::ref();
|
||||
|
||||
for( uint32_t questId = 65536; auto curQuest = exdData.get< Data::Quest >( questId ); questId++ )
|
||||
m_quests.emplace( questId, curQuest );
|
||||
}
|
||||
|
||||
void Sapphire::World::Manager::MapMgr::updateAll( Entity::Player& player )
|
||||
{
|
||||
auto& exdData = Common::Service< Data::ExdDataGenerated >::ref();
|
||||
auto& objectCache = Common::Service< Sapphire::InstanceObjectCache >::ref();
|
||||
|
||||
EventSet mapData;
|
||||
|
||||
auto eventNpcs = objectCache.getAllEventNpc( player.getZoneId() );
|
||||
if( eventNpcs )
|
||||
{
|
||||
for( const auto& eventNpc : *eventNpcs )
|
||||
{
|
||||
auto eNpc = exdData.get< Data::ENpcBase >( eventNpc.second->data.enpcId );
|
||||
if( eNpc )
|
||||
{
|
||||
auto eNpcData = eNpc->eNpcData;
|
||||
for( auto npcData : eNpcData )
|
||||
{
|
||||
if( npcData == 0 )
|
||||
continue; // Some npcs have data gaps, so we have to iterate through the entire array
|
||||
|
||||
EventData eventData;
|
||||
eventData.eventId = npcData;
|
||||
eventData.levelId = eventNpc.first;
|
||||
|
||||
auto eventHandlerType = static_cast< EventHandler::EventHandlerType >( npcData >> 16 );
|
||||
|
||||
switch( eventHandlerType )
|
||||
{
|
||||
case EventHandler::EventHandlerType::Quest:
|
||||
{
|
||||
auto quest = m_quests[ npcData ];
|
||||
|
||||
if( quest->issuerLocation == eventNpc.first )
|
||||
{
|
||||
insertQuest( player, npcData, mapData );
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EventHandler::EventHandlerType::GuildLeveAssignment:
|
||||
{
|
||||
if( player.isActionLearned( 5 ) )
|
||||
{
|
||||
auto guildLeve = exdData.get< Data::GuildleveAssignment >( npcData );
|
||||
|
||||
eventData.iconId = exdData.get< Data::EventIconType >( 5 )->mapIconAvailable + 1;
|
||||
|
||||
if( player.isQuestCompleted( guildLeve->quest[ 0 ] ) ||
|
||||
( ( guildLeve->typeId == 2 || npcData == 393217 || npcData == 393223 || npcData == 393225 ) && // Leve npc locations: Bentbranch / Horizon / Swiftperch
|
||||
( player.isQuestCompleted( 220 ) || player.isQuestCompleted( 687 ) || player.isQuestCompleted( 693 ) ) ) )
|
||||
{
|
||||
if( guildLeve->typeId == 2 )
|
||||
{
|
||||
if( player.getGc() != 0 )
|
||||
{
|
||||
for( int8_t i = 0; i < 3; i++ )
|
||||
{
|
||||
if( player.getGcRankArray()[ i ] >= guildLeve->grandCompanyRank )
|
||||
{
|
||||
mapData.insert( eventData );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mapData.insert( eventData );
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case EventHandler::EventHandlerType::CustomTalk:
|
||||
{
|
||||
// Include only the beginner arena icon yet. There a few other ones, that aren't referenced in the game files (Some examples are: The Triple Triad Tournament npc which has multiple icons and the ocean fishing icon)
|
||||
if( npcData == 721223 )
|
||||
{
|
||||
auto customTalk = exdData.get< Data::CustomTalk >( npcData );
|
||||
|
||||
eventData.iconId = customTalk->iconMap;
|
||||
|
||||
mapData.insert( eventData );
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case EventHandler::EventHandlerType::GuildOrderGuide:
|
||||
{
|
||||
if( player.isActionLearned( 7 ) )
|
||||
{
|
||||
eventData.iconId = exdData.get< Data::EventIconType >( 6 )->mapIconAvailable + 1;
|
||||
|
||||
mapData.insert( eventData );
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case EventHandler::EventHandlerType::TripleTriad:
|
||||
{
|
||||
if( npcData == 2293771 ) // Triple Triad Master npc for now only
|
||||
{
|
||||
eventData.iconId = exdData.get< Data::EventIconType >( 7 )->mapIconAvailable + 1;
|
||||
|
||||
mapData.insert( eventData );
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case EventHandler::EventHandlerType::PreHandler:
|
||||
{
|
||||
//I think this is used in Bozja and Zadnor, need evidence
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto eventObjs = objectCache.getAllEventObj( player.getZoneId() );
|
||||
if( eventObjs )
|
||||
{
|
||||
for( const auto& eventObj : *eventObjs )
|
||||
{
|
||||
auto eObj = exdData.get< Data::EObj >( eventObj.second->data.eobjId );
|
||||
if( eObj )
|
||||
{
|
||||
auto eObjData = eObj->data;
|
||||
if( eObjData )
|
||||
{
|
||||
EventData eventData;
|
||||
eventData.eventId = eObjData;
|
||||
eventData.levelId = eventObj.first;
|
||||
|
||||
auto eventHandlerType = static_cast< EventHandler::EventHandlerType >( eObjData >> 16 );
|
||||
|
||||
if( eventHandlerType == EventHandler::EventHandlerType::Quest )
|
||||
{
|
||||
auto quest = m_quests[ eObjData ];
|
||||
|
||||
if( quest->issuerLocation == eventObj.first )
|
||||
{
|
||||
insertQuest( player, eObjData, mapData );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sendPackets( player, mapData, All );
|
||||
}
|
||||
|
||||
void Sapphire::World::Manager::MapMgr::updateQuests( Entity::Player& player )
|
||||
{
|
||||
auto& exdData = Common::Service< Data::ExdDataGenerated >::ref();
|
||||
auto& objectCache = Common::Service< Sapphire::InstanceObjectCache >::ref();
|
||||
|
||||
EventSet mapData;
|
||||
|
||||
auto eventNpcs = objectCache.getAllEventNpc( player.getZoneId() );
|
||||
if( eventNpcs )
|
||||
{
|
||||
for( const auto& eventNpc : *eventNpcs )
|
||||
{
|
||||
auto eNpcData = exdData.get< Data::ENpcBase >( eventNpc.second->data.enpcId )->eNpcData;
|
||||
|
||||
for( auto npcData : eNpcData )
|
||||
{
|
||||
if( npcData == 0 )
|
||||
continue; // Some npcs have data gaps, so we have to iterate through the entire array
|
||||
|
||||
EventData eventData;
|
||||
eventData.eventId = npcData;
|
||||
eventData.levelId = eventNpc.first;
|
||||
|
||||
auto eventHandlerType = static_cast< EventHandler::EventHandlerType >( npcData >> 16 );
|
||||
|
||||
if( eventHandlerType == EventHandler::EventHandlerType::Quest )
|
||||
{
|
||||
auto quest = m_quests[ npcData ];
|
||||
|
||||
if( quest->issuerLocation == eventNpc.first )
|
||||
{
|
||||
insertQuest( player, npcData, mapData );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto eventObjs = objectCache.getAllEventObj( player.getZoneId() );
|
||||
if( eventObjs )
|
||||
{
|
||||
for( const auto& eventObj : *eventObjs )
|
||||
{
|
||||
auto eObj = exdData.get< Data::EObj >( eventObj.second->data.eobjId );
|
||||
if( eObj )
|
||||
{
|
||||
auto eObjData = eObj->data;
|
||||
if( eObjData )
|
||||
{
|
||||
EventData eventData;
|
||||
eventData.eventId = eObjData;
|
||||
eventData.levelId = eventObj.first;
|
||||
|
||||
auto eventHandlerType = static_cast< EventHandler::EventHandlerType >( eObjData >> 16 );
|
||||
|
||||
if( eventHandlerType == EventHandler::EventHandlerType::Quest )
|
||||
{
|
||||
auto quest = m_quests[ eObjData ];
|
||||
|
||||
if( quest->issuerLocation == eventObj.first )
|
||||
{
|
||||
insertQuest( player, eObjData, mapData );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sendPackets( player, mapData, Quest );
|
||||
}
|
||||
|
||||
void Sapphire::World::Manager::MapMgr::insertQuest( Entity::Player& player, uint32_t questId, EventSet& mapData )
|
||||
{
|
||||
auto& exdData = Common::Service< Data::ExdDataGenerated >::ref();
|
||||
auto& scriptMgr = Common::Service< Scripting::ScriptMgr >::ref();
|
||||
|
||||
auto quest = m_quests[ questId ];
|
||||
|
||||
if( isQuestVisible( player, questId, quest ) )
|
||||
{
|
||||
auto script = scriptMgr.getNativeScriptHandler().getScript< Sapphire::ScriptAPI::EventScript >( questId );
|
||||
|
||||
// Just don't show quests on map, that aren't implemented yet
|
||||
if( script )
|
||||
{
|
||||
EventData eventData;
|
||||
eventData.eventId = questId;
|
||||
|
||||
auto eventState = script->getQuestAvailability( player, questId );
|
||||
|
||||
if( eventState == Event::EventHandler::QuestAvailability::Available || eventState == Event::EventHandler::QuestAvailability::Locked )
|
||||
{
|
||||
if( eventState == Event::EventHandler::QuestAvailability::Available && isQuestAvailable( player, questId, quest ) )
|
||||
{
|
||||
eventData.iconId = exdData.get< Data::EventIconType >( quest->eventIconType )->mapIconAvailable + 1 + quest->isRepeatable;
|
||||
eventData.levelId = quest->issuerLocation;
|
||||
}
|
||||
else
|
||||
{
|
||||
eventData.iconId = exdData.get< Data::EventIconType >( quest->eventIconType )->mapIconInvalid + 1 + quest->isRepeatable;
|
||||
eventData.levelId = quest->issuerLocation;
|
||||
}
|
||||
|
||||
mapData.insert( eventData );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Sapphire::World::Manager::MapMgr::isQuestAvailable( Entity::Player& player, uint32_t questId, Data::ExdDataGenerated::QuestPtr questPtr )
|
||||
{
|
||||
auto& exdData = Common::Service< Data::ExdDataGenerated >::ref();
|
||||
|
||||
if( questPtr->grandCompany || questPtr->grandCompanyRank )
|
||||
{
|
||||
if( questPtr->grandCompany != player.getGc() )
|
||||
{
|
||||
if( questPtr->grandCompanyRank > player.getGcRankArray()[ player.getGc() - 1 ] )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if( questPtr->instanceContentJoin == 1 )
|
||||
{
|
||||
for( int32_t i = 0; i < 3; i++ )
|
||||
{
|
||||
if( questPtr->instanceContent[ i ] == 0 )
|
||||
continue;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if( questPtr->instanceContentJoin == 2 )
|
||||
{
|
||||
for( int32_t i = 0; i < 3; i++ )
|
||||
{
|
||||
if( questPtr->instanceContent[ i ] == 0 )
|
||||
continue;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if( questPtr->bellStart || questPtr->bellEnd )
|
||||
{
|
||||
uint64_t curEorzeaTime = Util::getEorzeanTimeStamp();
|
||||
uint32_t convTime = 100 * ( curEorzeaTime / 3600 % 24 ) + curEorzeaTime / 60 % 60;
|
||||
|
||||
if( questPtr->bellStart <= questPtr->bellEnd )
|
||||
{
|
||||
if( convTime < questPtr->bellStart || convTime >= questPtr->bellEnd )
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( convTime < questPtr->bellStart && convTime >= questPtr->bellEnd )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
auto classJobCategory = &exdData.get< Data::ClassJobCategory >( questPtr->classJobCategory0 )->aDV;
|
||||
if( !classJobCategory[ static_cast< uint8_t >( player.getClass() ) ] )
|
||||
return false;
|
||||
|
||||
if( questPtr->classJobCategory1 > 1 )
|
||||
{
|
||||
classJobCategory = &exdData.get< Data::ClassJobCategory >( questPtr->classJobCategory1 )->aDV;
|
||||
if( !classJobCategory[ static_cast< uint8_t >( player.getClass() ) ] )
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Sapphire::World::Manager::MapMgr::isQuestVisible( Entity::Player& player, uint32_t questId, Data::ExdDataGenerated::QuestPtr questPtr )
|
||||
{
|
||||
auto& exdData = Common::Service< Data::ExdDataGenerated >::ref();
|
||||
|
||||
if( ( player.isQuestCompleted( questId ) && ( !questPtr->isRepeatable && questId != 67114 ) ) || player.hasQuest( questId ) )
|
||||
return false;
|
||||
|
||||
if( questPtr->classJobUnlock )
|
||||
{
|
||||
if( questPtr->classJobUnlockFlag == 3 )
|
||||
if( static_cast< uint8_t >( player.getClass() ) != questPtr->classJobUnlock )
|
||||
return false;
|
||||
else if( questPtr->classJobUnlockFlag == 4 )
|
||||
if ( static_cast< uint8_t >( player.getClass() ) == questPtr->classJobUnlock )
|
||||
return false;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
// Was this really ever used?
|
||||
if( questPtr->startTown )
|
||||
{
|
||||
if( questPtr->startTown != player.getStartTown() )
|
||||
return false;
|
||||
}
|
||||
|
||||
if( Common::CURRENT_EXPANSION_ID < questPtr->expansion )
|
||||
return false;
|
||||
|
||||
if( questPtr->mountRequired )
|
||||
{
|
||||
if( !player.hasMount( questPtr->mountRequired ) )
|
||||
return false;
|
||||
}
|
||||
|
||||
if( questPtr->grandCompany )
|
||||
{
|
||||
if( questPtr->grandCompany != player.getGc() )
|
||||
return false;
|
||||
}
|
||||
|
||||
if( questPtr->header != 0 )
|
||||
{
|
||||
if ( !player.isActionLearned( questPtr->header ) )
|
||||
return false;
|
||||
}
|
||||
|
||||
if( questPtr->previousQuestJoin == 1 )
|
||||
{
|
||||
for( int32_t i = 0; i < 3; i++ )
|
||||
{
|
||||
if( questPtr->previousQuest[ i ] == 0 )
|
||||
continue;
|
||||
|
||||
if( !player.isQuestCompleted( questPtr->previousQuest[ i ] ) )
|
||||
{
|
||||
if( i == 0 && questPtr->previousQuest0Sequence != 0 )
|
||||
{
|
||||
if( player.getQuestSeq( questPtr->previousQuest[ i ] ) < questPtr->previousQuest0Sequence )
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( questPtr->previousQuestJoin == 2 )
|
||||
{
|
||||
for( int32_t i = 0; i < 3; i++ )
|
||||
{
|
||||
if( questPtr->previousQuest[ i ] == 0 )
|
||||
continue;
|
||||
|
||||
if( player.isQuestCompleted( questPtr->previousQuest[ i ] ) )
|
||||
break;
|
||||
|
||||
if( i == 2 )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if( questPtr->questLockJoin == 1 )
|
||||
{
|
||||
for( int32_t i = 0; i < 2; i++ )
|
||||
{
|
||||
if( questPtr->questLock[ i ] == 0 )
|
||||
continue;
|
||||
|
||||
if( !player.isQuestCompleted( questPtr->questLock[ i ] ) && !player.hasQuest( questPtr->questLock[ i ] ) )
|
||||
break;
|
||||
|
||||
if( i == 1 )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if( questPtr->questLockJoin == 2 )
|
||||
{
|
||||
for( int32_t i = 0; i < 2; i++ )
|
||||
{
|
||||
if( questPtr->questLock[ i ] == 0 )
|
||||
continue;
|
||||
|
||||
if( player.isQuestCompleted( questPtr->questLock[ i ] ) || player.hasQuest( questPtr->questLock[ i ] ) )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if( questPtr->festival )
|
||||
{
|
||||
auto& territoryMgr = Common::Service< Manager::TerritoryMgr >::ref();
|
||||
auto& festival = territoryMgr.getCurrentFestival();
|
||||
|
||||
if( questPtr->festival != festival.first && questPtr->festival != festival.second )
|
||||
return false;
|
||||
|
||||
// Don't show festivals with begin state other than 0 yet
|
||||
if( questPtr->festivalBegin != 0 )
|
||||
return false;
|
||||
}
|
||||
|
||||
if( ( questPtr->type & 1 ) == 0 )
|
||||
{
|
||||
auto classJobCategory = &exdData.get< Data::ClassJobCategory >( questPtr->classJobCategory0 )->aDV;
|
||||
|
||||
for( int32_t i = 1; i <= Common::CLASSJOB_TOTAL; i++ )
|
||||
{
|
||||
if( classJobCategory[ i ] )
|
||||
{
|
||||
if( player.getLevelForClass( static_cast< Common::ClassJob >( i ) ) >= questPtr->classJobLevel0 )
|
||||
break;
|
||||
}
|
||||
|
||||
if( i == Common::CLASSJOB_TOTAL )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( player.getLevel() < questPtr->classJobLevel0 )
|
||||
return false;
|
||||
}
|
||||
|
||||
for( int32_t i = 0; i <= Common::CLASSJOB_TOTAL; i++ )
|
||||
{
|
||||
auto classJob = exdData.get< Data::ClassJob >( i );
|
||||
|
||||
if( classJob->relicQuest == questId )
|
||||
{
|
||||
for( int32_t j = 0; i <= Common::CLASSJOB_TOTAL; i++ )
|
||||
{
|
||||
classJob = exdData.get< Data::ClassJob >( i );
|
||||
|
||||
if( player.hasQuest( classJob->relicQuest ) )
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( questPtr->beastTribe )
|
||||
return false;
|
||||
|
||||
if( questPtr->satisfactionNpc )
|
||||
return false;
|
||||
|
||||
if( questPtr->isHouseRequired )
|
||||
return false;
|
||||
|
||||
if( questPtr->deliveryQuest )
|
||||
return false;
|
||||
|
||||
if( player.getQuestSeq( questId ) == 0 )
|
||||
{
|
||||
auto questAccept = exdData.get< Data::QuestAcceptAdditionCondition >( questId );
|
||||
|
||||
if( questAccept )
|
||||
{
|
||||
for( int32_t i = 0; i < 2; i++ )
|
||||
{
|
||||
if( ( &questAccept->requirement0 )[ i ] >= 65536 )
|
||||
{
|
||||
if( !player.isActionLearned( 245 ) && !player.isQuestCompleted( ( &questAccept->requirement0 )[ i ] ) )
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( !player.isActionLearned( ( &questAccept->requirement0 )[ i ] ) )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Sapphire::World::Manager::MapMgr::isTripleTriadAvailable( Entity::Player& player, uint32_t tripleTriadId )
|
||||
{
|
||||
auto& exdData = Common::Service< Data::ExdDataGenerated >::ref();
|
||||
auto tripleTriad = exdData.get< Data::TripleTriad >( tripleTriadId );
|
||||
|
||||
if( tripleTriad->previousQuestJoin == 1 )
|
||||
{
|
||||
for( int32_t i = 0; i < 3; i++ )
|
||||
{
|
||||
if( tripleTriad->previousQuest[ i ] == 0 )
|
||||
continue;
|
||||
|
||||
if( !player.isQuestCompleted( tripleTriad->previousQuest[ i ] ) )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if( tripleTriad->previousQuestJoin == 2 )
|
||||
{
|
||||
for( int32_t i = 0; i < 3; i++ )
|
||||
{
|
||||
if( tripleTriad->previousQuest[ i ] == 0 )
|
||||
continue;
|
||||
|
||||
if( player.isQuestCompleted( tripleTriad->previousQuest[ i ] ) )
|
||||
break;
|
||||
|
||||
if( i == 2 )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Sapphire::World::Manager::MapMgr::fillPacket( EventSet& mapData, uint32_t* iconIds, uint32_t* levelIds, uint32_t* eventIds )
|
||||
{
|
||||
int32_t i = 0;
|
||||
for( auto& eventData : mapData )
|
||||
{
|
||||
iconIds[ i ] = eventData.iconId;
|
||||
levelIds[ i ] = eventData.levelId;
|
||||
eventIds[ i ] = eventData.eventId;
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void Sapphire::World::Manager::MapMgr::sendPackets( Entity::Player& player, EventSet& mapData, UpdateMode updateMode )
|
||||
{
|
||||
player.queuePacket( makeActorControlSelf( player.getId(), Network::ActorControl::BeginMapUpdate, updateMode ) );
|
||||
|
||||
if( mapData.size() <= 2 )
|
||||
{
|
||||
auto mapUpdatePacket = makeZonePacket< FFXIVIpcMapUpdate >( player.getId() );
|
||||
mapUpdatePacket->data().entryCount = mapData.size();
|
||||
|
||||
fillPacket( mapData, mapUpdatePacket->data().iconIds, mapUpdatePacket->data().levelIds, mapUpdatePacket->data().eventIds );
|
||||
|
||||
player.queuePacket( mapUpdatePacket );
|
||||
}
|
||||
else if( mapData.size() <= 4 )
|
||||
{
|
||||
auto mapUpdatePacket = makeZonePacket< FFXIVIpcMapUpdate4 >( player.getId() );
|
||||
mapUpdatePacket->data().entryCount = mapData.size();
|
||||
|
||||
fillPacket( mapData, mapUpdatePacket->data().iconIds, mapUpdatePacket->data().levelIds, mapUpdatePacket->data().eventIds );
|
||||
|
||||
player.queuePacket( mapUpdatePacket );
|
||||
}
|
||||
else if( mapData.size() <= 8 )
|
||||
{
|
||||
auto mapUpdatePacket = makeZonePacket< FFXIVIpcMapUpdate8 >( player.getId() );
|
||||
mapUpdatePacket->data().entryCount = mapData.size();
|
||||
|
||||
fillPacket( mapData, mapUpdatePacket->data().iconIds, mapUpdatePacket->data().levelIds, mapUpdatePacket->data().eventIds );
|
||||
|
||||
player.queuePacket( mapUpdatePacket );
|
||||
}
|
||||
else if( mapData.size() <= 16 )
|
||||
{
|
||||
auto mapUpdatePacket = makeZonePacket< FFXIVIpcMapUpdate16 >( player.getId() );
|
||||
mapUpdatePacket->data().entryCount = mapData.size();
|
||||
|
||||
fillPacket( mapData, mapUpdatePacket->data().iconIds, mapUpdatePacket->data().levelIds, mapUpdatePacket->data().eventIds );
|
||||
|
||||
player.queuePacket( mapUpdatePacket );
|
||||
}
|
||||
else if( mapData.size() <= 32 )
|
||||
{
|
||||
auto mapUpdatePacket = makeZonePacket< FFXIVIpcMapUpdate32 >( player.getId() );
|
||||
mapUpdatePacket->data().entryCount = mapData.size();
|
||||
|
||||
fillPacket( mapData, mapUpdatePacket->data().iconIds, mapUpdatePacket->data().levelIds, mapUpdatePacket->data().eventIds );
|
||||
|
||||
player.queuePacket( mapUpdatePacket );
|
||||
}
|
||||
else if( mapData.size() <= 64 )
|
||||
{
|
||||
auto mapUpdatePacket = makeZonePacket< FFXIVIpcMapUpdate64 >( player.getId() );
|
||||
mapUpdatePacket->data().entryCount = mapData.size();
|
||||
|
||||
fillPacket( mapData, mapUpdatePacket->data().iconIds, mapUpdatePacket->data().levelIds, mapUpdatePacket->data().eventIds );
|
||||
|
||||
player.queuePacket( mapUpdatePacket );
|
||||
}
|
||||
else if( mapData.size() <= 128 )
|
||||
{
|
||||
auto mapUpdatePacket = makeZonePacket< FFXIVIpcMapUpdate128 >( player.getId() );
|
||||
mapUpdatePacket->data().entryCount = mapData.size();
|
||||
|
||||
fillPacket( mapData, mapUpdatePacket->data().iconIds, mapUpdatePacket->data().levelIds, mapUpdatePacket->data().eventIds );
|
||||
|
||||
player.queuePacket( mapUpdatePacket );
|
||||
}
|
||||
|
||||
player.queuePacket( makeActorControlSelf( player.getId(), Network::ActorControl::FinishMapUpdate ) );
|
||||
}
|
77
src/world/Manager/MapMgr.h
Normal file
77
src/world/Manager/MapMgr.h
Normal file
|
@ -0,0 +1,77 @@
|
|||
#ifndef SAPPHIRE_MAPMGR_H
|
||||
#define SAPPHIRE_MAPMGR_H
|
||||
|
||||
#include "ForwardsZone.h"
|
||||
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace Sapphire::World::Manager
|
||||
{
|
||||
|
||||
using QuestMap = std::unordered_map< uint32_t, Data::ExdDataGenerated::QuestPtr >;
|
||||
|
||||
class MapMgr
|
||||
{
|
||||
public:
|
||||
enum UpdateMode : uint8_t
|
||||
{
|
||||
Quest = 1,
|
||||
GuildLeveAssignment = 2,
|
||||
GuildOrderGuide = 4,
|
||||
TripleTriad = 8,
|
||||
CustomTalk = 16,
|
||||
PreHandler = 32,
|
||||
|
||||
All = 0x3F
|
||||
};
|
||||
|
||||
MapMgr();
|
||||
|
||||
void updateAll( Entity::Player& player );
|
||||
void updateQuests( Entity::Player& player );
|
||||
|
||||
private:
|
||||
struct EventData
|
||||
{
|
||||
uint32_t iconId;
|
||||
uint32_t levelId;
|
||||
uint32_t eventId;
|
||||
};
|
||||
|
||||
struct less
|
||||
{
|
||||
constexpr bool operator()( const EventData& _Left, const EventData& _Right ) const
|
||||
{
|
||||
const uint16_t left = _Left.eventId;
|
||||
const uint16_t right = _Right.eventId;
|
||||
|
||||
if( left == right )
|
||||
{
|
||||
const uint16_t typeLeft = _Left.eventId >> 16;
|
||||
const uint16_t typeRight = _Right.eventId >> 16;
|
||||
|
||||
return typeLeft < typeRight;
|
||||
}
|
||||
|
||||
return left < right;
|
||||
}
|
||||
};
|
||||
|
||||
using EventSet = std::multiset< EventData, less >;
|
||||
|
||||
QuestMap m_quests;
|
||||
|
||||
void insertQuest( Entity::Player& player, uint32_t questId, EventSet& mapData );
|
||||
|
||||
bool isQuestVisible( Entity::Player& player, uint32_t questId, Data::ExdDataGenerated::QuestPtr questPtr );
|
||||
bool isQuestAvailable( Entity::Player& player, uint32_t questId, Data::ExdDataGenerated::QuestPtr questPtr );
|
||||
bool isTripleTriadAvailable( Entity::Player& player, uint32_t tripleTriadId );
|
||||
|
||||
void fillPacket( EventSet& mapData, uint32_t* iconIds, uint32_t* levelIds, uint32_t* eventIds );
|
||||
void sendPackets( Entity::Player& player, EventSet& mapData, UpdateMode updateMode );
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // SAPPHIRE_MAPMGR_H
|
|
@ -1,7 +1,6 @@
|
|||
#include <string>
|
||||
#include <typeinfo>
|
||||
#include <typeindex>
|
||||
#include <Event/EventHandler.h>
|
||||
#include "NativeScriptApi.h"
|
||||
#include <cassert>
|
||||
|
||||
|
@ -138,6 +137,11 @@ namespace Sapphire::ScriptAPI
|
|||
{
|
||||
}
|
||||
|
||||
Event::EventHandler::QuestAvailability EventScript::getQuestAvailability( Sapphire::Entity::Player& player, uint32_t eventId )
|
||||
{
|
||||
return Event::EventHandler::QuestAvailability::Available;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
||||
EventObjectScript::EventObjectScript( uint32_t eobjId ) :
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define NATIVE_SCRIPT_API
|
||||
|
||||
#include <string>
|
||||
#include <Event/EventHandler.h>
|
||||
#include "ForwardsZone.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
@ -168,6 +169,8 @@ namespace Sapphire::ScriptAPI
|
|||
virtual void onEObjHit( Sapphire::Entity::Player& player, uint64_t actorId, uint32_t actionId );
|
||||
|
||||
virtual void onEventYield( Sapphire::Entity::Player& player, uint16_t scene, std::vector< uint32_t > param );
|
||||
|
||||
virtual Event::EventHandler::QuestAvailability getQuestAvailability( Sapphire::Entity::Player& player, uint32_t eventId );
|
||||
};
|
||||
|
||||
/*!
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include "Manager/RNGMgr.h"
|
||||
#include "Manager/NaviMgr.h"
|
||||
#include "Manager/ActionMgr.h"
|
||||
#include "Manager/MapMgr.h"
|
||||
|
||||
#include "Territory/InstanceObjectCache.h"
|
||||
|
||||
|
@ -173,6 +174,10 @@ void Sapphire::World::ServerMgr::run( int32_t argc, char* argv[] )
|
|||
auto pInstanceObjCache = std::make_shared< Sapphire::InstanceObjectCache >();
|
||||
Common::Service< Sapphire::InstanceObjectCache >::set( pInstanceObjCache );
|
||||
|
||||
Logger::info( "MapMgr: Caching quests" );
|
||||
auto pMapMgr = std::make_shared< Manager::MapMgr >();
|
||||
Common::Service< Manager::MapMgr >::set( pMapMgr );
|
||||
|
||||
auto pActionMgr = std::make_shared< Manager::ActionMgr >();
|
||||
Common::Service< Manager::ActionMgr >::set( pActionMgr );
|
||||
|
||||
|
|
|
@ -41,16 +41,23 @@ Sapphire::InstanceObjectCache::InstanceObjectCache()
|
|||
// TODO: it does feel like this needs to be streamlined into the datReader instead of being done here...
|
||||
std::string bgLgbPath( path + "/level/bg.lgb" );
|
||||
std::string planmapLgbPath( path + "/level/planmap.lgb" );
|
||||
std::string planeventLgbPath( path + "/level/planevent.lgb" );
|
||||
std::string plannerLgbPath( path + "/level/planner.lgb" );
|
||||
std::vector< char > bgSection;
|
||||
std::vector< char > planmapSection;
|
||||
std::vector< char > planeventSection;
|
||||
std::vector< char > plannerSection;
|
||||
|
||||
std::unique_ptr< xiv::dat::File > bgFile;
|
||||
std::unique_ptr< xiv::dat::File > planmap_file;
|
||||
std::unique_ptr< xiv::dat::File > planevent_file;
|
||||
std::unique_ptr< xiv::dat::File > planner_file;
|
||||
|
||||
try
|
||||
{
|
||||
bgFile = exdData.getGameData()->getFile( bgLgbPath );
|
||||
planmap_file = exdData.getGameData()->getFile( planmapLgbPath );
|
||||
planevent_file = exdData.getGameData()->getFile( planeventLgbPath );
|
||||
}
|
||||
catch( std::runtime_error& )
|
||||
{
|
||||
|
@ -60,6 +67,7 @@ Sapphire::InstanceObjectCache::InstanceObjectCache()
|
|||
|
||||
bgSection = bgFile->access_data_sections().at( 0 );
|
||||
planmapSection = planmap_file->access_data_sections().at( 0 );
|
||||
planeventSection = planevent_file->access_data_sections().at( 0 );
|
||||
|
||||
std::vector< std::string > stringList;
|
||||
|
||||
|
@ -67,8 +75,23 @@ Sapphire::InstanceObjectCache::InstanceObjectCache()
|
|||
|
||||
LGB_FILE bgLgb( &bgSection[ 0 ], "bg" );
|
||||
LGB_FILE planmapLgb( &planmapSection[ 0 ], "planmap" );
|
||||
LGB_FILE planeventLgb( &planeventSection[ 0 ], "planevent" );
|
||||
|
||||
std::vector< LGB_FILE > lgbList;
|
||||
|
||||
try
|
||||
{
|
||||
planner_file = exdData.getGameData()->getFile( plannerLgbPath );
|
||||
plannerSection = planner_file->access_data_sections().at( 0 );
|
||||
LGB_FILE plannerLgb( &plannerSection[ 0 ], "planner" );
|
||||
|
||||
lgbList = { bgLgb, planmapLgb, planeventLgb, plannerLgb };
|
||||
}
|
||||
catch( std::runtime_error& )
|
||||
{
|
||||
lgbList = { bgLgb, planmapLgb, planeventLgb };
|
||||
}
|
||||
|
||||
std::vector< LGB_FILE > lgbList{ bgLgb, planmapLgb };
|
||||
uint32_t max_index = 0;
|
||||
|
||||
for( const auto& lgb : lgbList )
|
||||
|
@ -92,6 +115,16 @@ Sapphire::InstanceObjectCache::InstanceObjectCache()
|
|||
auto pPopRange = std::reinterpret_pointer_cast< LGB_POP_RANGE_ENTRY >( pEntry );
|
||||
m_popRangeCache.insert( id, pPopRange );
|
||||
}
|
||||
else if( pEntry->getType() == LgbEntryType::EventNpc )
|
||||
{
|
||||
auto pEventNpc = std::reinterpret_pointer_cast< LGB_ENPC_ENTRY >( pEntry );
|
||||
m_eventNpcCache.insert( id, pEventNpc );
|
||||
}
|
||||
else if( pEntry->getType() == LgbEntryType::EventObject )
|
||||
{
|
||||
auto pEventObj = std::reinterpret_pointer_cast< LGB_EOBJ_ENTRY >( pEntry );
|
||||
m_eventObjCache.insert( id, pEventObj );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -99,8 +132,8 @@ Sapphire::InstanceObjectCache::InstanceObjectCache()
|
|||
std::cout << "\n";
|
||||
|
||||
Logger::debug(
|
||||
"InstanceObjectCache Cached: MapRange: {} ExitRange: {} PopRange: {}",
|
||||
m_mapRangeCache.size(), m_exitRangeCache.size(), m_popRangeCache.size()
|
||||
"InstanceObjectCache Cached: MapRange: {} ExitRange: {} PopRange: {} ENpc: {} Eobj: {}",
|
||||
m_mapRangeCache.size(), m_exitRangeCache.size(), m_popRangeCache.size(), m_eventNpcCache.size(), m_eventObjCache.size()
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -121,4 +154,28 @@ Sapphire::InstanceObjectCache::PopRangePtr
|
|||
Sapphire::InstanceObjectCache::getPopRange( uint16_t zoneId, uint32_t popRangeId )
|
||||
{
|
||||
return m_popRangeCache.get( zoneId, popRangeId );
|
||||
}
|
||||
|
||||
Sapphire::InstanceObjectCache::EventNpcPtr
|
||||
Sapphire::InstanceObjectCache::getEventNpc( uint16_t zoneId, uint32_t eventNpcId )
|
||||
{
|
||||
return m_eventNpcCache.get( zoneId, eventNpcId );
|
||||
}
|
||||
|
||||
Sapphire::InstanceObjectCache::EventObjPtr
|
||||
Sapphire::InstanceObjectCache::getEventObj( uint16_t zoneId, uint32_t eventObjId )
|
||||
{
|
||||
return m_eventObjCache.get( zoneId, eventObjId );
|
||||
}
|
||||
|
||||
Sapphire::InstanceObjectCache::EventNpcMapPtr
|
||||
Sapphire::InstanceObjectCache::getAllEventNpc( uint16_t zoneId )
|
||||
{
|
||||
return m_eventNpcCache.getAll( zoneId );
|
||||
}
|
||||
|
||||
Sapphire::InstanceObjectCache::EventObjMapPtr
|
||||
Sapphire::InstanceObjectCache::getAllEventObj( uint16_t zoneId )
|
||||
{
|
||||
return m_eventObjCache.getAll( zoneId );
|
||||
}
|
|
@ -7,6 +7,8 @@
|
|||
struct LGB_MAP_RANGE_ENTRY;
|
||||
struct LGB_EXIT_RANGE_ENTRY;
|
||||
struct LGB_POP_RANGE_ENTRY;
|
||||
struct LGB_ENPC_ENTRY;
|
||||
struct LGB_EOBJ_ENTRY;
|
||||
|
||||
|
||||
namespace Sapphire
|
||||
|
@ -37,6 +39,16 @@ namespace Sapphire
|
|||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ObjectMap* getAll( uint16_t zoneId )
|
||||
{
|
||||
auto it = m_objectCache.find( zoneId );
|
||||
if( it != m_objectCache.end() )
|
||||
{
|
||||
return &it->second;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void insert( uint16_t zoneId, std::shared_ptr< T > entry )
|
||||
{
|
||||
|
@ -65,6 +77,11 @@ namespace Sapphire
|
|||
using MapRangePtr = std::shared_ptr< LGB_MAP_RANGE_ENTRY >;
|
||||
using ExitRangePtr = std::shared_ptr< LGB_EXIT_RANGE_ENTRY >;
|
||||
using PopRangePtr = std::shared_ptr< LGB_POP_RANGE_ENTRY >;
|
||||
using EventNpcPtr = std::shared_ptr< LGB_ENPC_ENTRY >;
|
||||
using EventObjPtr = std::shared_ptr< LGB_EOBJ_ENTRY >;
|
||||
|
||||
using EventNpcMapPtr = std::unordered_map< uint32_t, EventNpcPtr >*;
|
||||
using EventObjMapPtr = std::unordered_map< uint32_t, EventObjPtr >*;
|
||||
|
||||
InstanceObjectCache();
|
||||
~InstanceObjectCache() = default;
|
||||
|
@ -72,11 +89,18 @@ namespace Sapphire
|
|||
MapRangePtr getMapRange( uint16_t zoneId, uint32_t mapRangeId );
|
||||
ExitRangePtr getExitRange( uint16_t zoneId, uint32_t exitRangeId );
|
||||
PopRangePtr getPopRange( uint16_t zoneId, uint32_t popRangeId );
|
||||
EventNpcPtr getEventNpc( uint16_t zoneId, uint32_t eventNpcId );
|
||||
EventObjPtr getEventObj( uint16_t zoneId, uint32_t eventObjId );
|
||||
|
||||
EventNpcMapPtr getAllEventNpc( uint16_t zoneId );
|
||||
EventObjMapPtr getAllEventObj( uint16_t zoneId );
|
||||
|
||||
private:
|
||||
ObjectCache< LGB_MAP_RANGE_ENTRY > m_mapRangeCache;
|
||||
ObjectCache< LGB_EXIT_RANGE_ENTRY > m_exitRangeCache;
|
||||
ObjectCache< LGB_POP_RANGE_ENTRY > m_popRangeCache;
|
||||
ObjectCache< LGB_ENPC_ENTRY > m_eventNpcCache;
|
||||
ObjectCache< LGB_EOBJ_ENTRY > m_eventObjCache;
|
||||
std::shared_ptr< Framework > m_pFramework;
|
||||
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue