mirror of
https://github.com/SapphireServer/Sapphire.git
synced 2025-05-03 09:17:47 +00:00
[3.x] Basic map icon support (MapMgr backport) (#896)
* Fix several structs * Preliminary map icon support (only quests work) Backport of #721 to 3.x * MapMgr cleanup * Add missing null check for ENpcBase * Use CLASSJOB_SLOTS in PlayerSetup instead * Use util function for getting bit fields
This commit is contained in:
parent
87295a0ff6
commit
a17c891c2c
15 changed files with 878 additions and 24 deletions
31
deps/datReader/Exd/Structs.h
vendored
31
deps/datReader/Exd/Structs.h
vendored
|
@ -1738,8 +1738,7 @@ namespace Excel
|
|||
struct ClassJobCategory
|
||||
{
|
||||
ClassJobCategoryTextStruct Text;
|
||||
bool ClassJob[31];
|
||||
int8_t padding0[1];
|
||||
bool ClassJob[34];
|
||||
};
|
||||
|
||||
/* 264228 */
|
||||
|
@ -1902,15 +1901,13 @@ namespace Excel
|
|||
uint8_t ItemStainId[7];
|
||||
uint8_t OptionalItemNum[5];
|
||||
uint8_t OptionalItemStainId[5];
|
||||
uint8_t CompanyPointType;
|
||||
uint8_t Emote;
|
||||
uint8_t unknown;
|
||||
uint8_t GeneralAction[2];
|
||||
uint8_t CompanyPointType;
|
||||
uint8_t AllaganTomestoneType;
|
||||
uint8_t AllaganTomestoneNum;
|
||||
uint8_t Unknown95E;
|
||||
uint8_t BeastReputationValueNum;
|
||||
uint8_t unknown1[4];
|
||||
uint8_t unknown[6];
|
||||
};
|
||||
|
||||
/* 264323 */
|
||||
|
@ -1927,27 +1924,28 @@ namespace Excel
|
|||
uint32_t InstanceContent[3];
|
||||
uint32_t Client;
|
||||
uint32_t Finish;
|
||||
uint32_t Header;
|
||||
uint32_t Image;
|
||||
uint32_t Inlay;
|
||||
int32_t Mount;
|
||||
uint16_t ClassLevel;
|
||||
uint16_t Unknown9A2;
|
||||
uint16_t ClassLevel2;
|
||||
uint16_t AcquiredReward;
|
||||
uint16_t Header;
|
||||
uint16_t TimeBegin;
|
||||
uint16_t TimeEnd;
|
||||
uint16_t BeastReputationValue;
|
||||
uint16_t ClientBehavior;
|
||||
uint16_t Area;
|
||||
uint16_t Sort;
|
||||
uint8_t Expansion;
|
||||
uint8_t ClassJob;
|
||||
uint8_t QuestLevelOffset;
|
||||
uint8_t ClassJob2;
|
||||
uint8_t PrevQuestOperator;
|
||||
uint8_t ExcludeQuestOperator;
|
||||
uint8_t StartTown;
|
||||
uint8_t FirstClassOperator;
|
||||
uint8_t FirstClass;
|
||||
uint8_t ClassJobUnlockFlag;
|
||||
uint8_t ClassJobUnlock;
|
||||
uint8_t GrandCompany;
|
||||
uint8_t GrandCompanyRank;
|
||||
uint8_t InstanceContentOperator;
|
||||
|
@ -1956,20 +1954,20 @@ namespace Excel
|
|||
uint8_t FestivalPhaseEnd;
|
||||
uint8_t BeastTribe;
|
||||
uint8_t BeastReputationRank;
|
||||
uint8_t DeliveryQuest;
|
||||
uint8_t RepeatCycle;
|
||||
uint8_t RepeatFlag;
|
||||
uint8_t ExpClass;
|
||||
uint8_t Genre;
|
||||
uint8_t Unknown9CA;
|
||||
uint8_t IconType;
|
||||
uint8_t Quality;
|
||||
uint8_t Unknown9C9;
|
||||
uint8_t Type;
|
||||
uint8_t padding2 : 3;
|
||||
uint8_t HideOfferIcon : 1;
|
||||
uint8_t Cancellable : 1;
|
||||
uint8_t Introduction : 1;
|
||||
uint8_t Repeatable : 1;
|
||||
uint8_t House : 1;
|
||||
int8_t padding3[3];
|
||||
};
|
||||
|
||||
/* 264324 */
|
||||
|
@ -3328,10 +3326,11 @@ namespace Excel
|
|||
/* 362341 */
|
||||
struct EventIconType
|
||||
{
|
||||
uint32_t Announce;
|
||||
uint32_t Map;
|
||||
uint32_t NpcAvailable;
|
||||
uint32_t MapAvailable;
|
||||
uint32_t NpcInvalid;
|
||||
uint32_t MapInvalid;
|
||||
uint8_t Num;
|
||||
int8_t padding0[3];
|
||||
};
|
||||
|
||||
/* 362342 */
|
||||
|
|
|
@ -24,7 +24,7 @@ namespace Sapphire::Common
|
|||
const uint16_t MAX_PLAYER_LEVEL = 60;
|
||||
const uint8_t CURRENT_EXPANSION_ID = 1;
|
||||
|
||||
const uint8_t CLASSJOB_TOTAL = 23;
|
||||
const uint8_t CLASSJOB_TOTAL = 34;
|
||||
const uint8_t CLASSJOB_SLOTS = 23;
|
||||
|
||||
const uint8_t TOWN_COUNT = 6;
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "Manager/PartyMgr.h"
|
||||
#include "Manager/WarpMgr.h"
|
||||
#include "Manager/FreeCompanyMgr.h"
|
||||
#include "Manager/MapMgr.h"
|
||||
|
||||
#include "Territory/Territory.h"
|
||||
#include "Territory/InstanceContent.h"
|
||||
|
@ -617,6 +618,21 @@ bool Player::hasReward( Common::UnlockEntry unlockId ) const
|
|||
return ( m_unlocks[ index ] & value ) != 0;
|
||||
}
|
||||
|
||||
bool Player::hasMount( uint32_t mountId ) const
|
||||
{
|
||||
auto& exdData = Common::Service< Data::ExdData >::ref();
|
||||
auto mount = exdData.getRow< Excel::Mount >( mountId );
|
||||
|
||||
if( !mount || mount->data().MountOrder == -1 || mount->data().Model == 0 )
|
||||
return false;
|
||||
|
||||
uint16_t index;
|
||||
uint8_t value;
|
||||
Util::valueToFlagByteIndexValue( mount->data().MountOrder, value, index );
|
||||
|
||||
return m_mountGuide[ index ] & value;
|
||||
}
|
||||
|
||||
void Player::gainExp( uint32_t amount )
|
||||
{
|
||||
uint32_t currentExp = getExp();
|
||||
|
@ -665,6 +681,7 @@ void Player::levelUp()
|
|||
setLevel( getLevel() + 1 );
|
||||
|
||||
Service< World::Manager::PlayerMgr >::ref().onLevelUp( *this );
|
||||
Service< World::Manager::MapMgr >::ref().updateQuests( *this );
|
||||
}
|
||||
|
||||
void Player::sendStatusUpdate()
|
||||
|
@ -743,6 +760,7 @@ void Player::setClassJob( Common::ClassJob classJob )
|
|||
|
||||
Service< World::Manager::PlayerMgr >::ref().onPlayerStatusUpdate( *this );
|
||||
Service< World::Manager::PlayerMgr >::ref().onChangeClass( *this );
|
||||
Service< World::Manager::MapMgr >::ref().updateQuests( *this );
|
||||
}
|
||||
|
||||
void Player::setLevel( uint8_t level )
|
||||
|
|
|
@ -464,6 +464,9 @@ namespace Sapphire::Entity
|
|||
/*! check if an action is already unlocked in the bitmask. */
|
||||
bool hasReward( Common::UnlockEntry unlockId ) const;
|
||||
|
||||
/*! check if a mount is already unlocked in the bitmask. */
|
||||
bool hasMount( uint32_t mountId ) const;
|
||||
|
||||
/*! return a const reference to the unlock bitmask array */
|
||||
const UnlockList& getUnlockBitmask() const;
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <Service.h>
|
||||
|
||||
#include "Manager/QuestMgr.h"
|
||||
#include "Manager/MapMgr.h"
|
||||
|
||||
#include "Player.h"
|
||||
|
||||
|
@ -41,11 +42,13 @@ void Sapphire::Entity::Player::removeQuest( uint16_t questId )
|
|||
}
|
||||
|
||||
auto& questMgr = Common::Service< World::Manager::QuestMgr >::ref();
|
||||
auto& mapMgr = Common::Service< World::Manager::MapMgr >::ref();
|
||||
|
||||
m_quests[ idx ] = World::Quest();
|
||||
removeQuestTracking( idx );
|
||||
deleteDbQuest( questId );
|
||||
|
||||
mapMgr.updateQuests( *this );
|
||||
questMgr.onRemoveQuest( *this, idx );
|
||||
|
||||
}
|
||||
|
@ -77,11 +80,13 @@ int8_t Sapphire::Entity::Player::getQuestIndex( uint16_t questId )
|
|||
void Sapphire::Entity::Player::updateQuest( const World::Quest& quest )
|
||||
{
|
||||
auto& questMgr = Common::Service< World::Manager::QuestMgr >::ref();
|
||||
auto& mapMgr = Common::Service< World::Manager::MapMgr >::ref();
|
||||
|
||||
if( hasQuest( quest.getId() ) )
|
||||
{
|
||||
uint8_t index = getQuestIndex( quest.getId() );
|
||||
m_quests[ index ] = quest;
|
||||
mapMgr.updateQuests( *this );
|
||||
questMgr.onUpdateQuest( *this, index );
|
||||
}
|
||||
else if( quest.getSeq() != 0 )
|
||||
|
@ -99,12 +104,14 @@ bool Sapphire::Entity::Player::addQuest( const World::Quest& quest )
|
|||
}
|
||||
|
||||
auto& questMgr = Common::Service< World::Manager::QuestMgr >::ref();
|
||||
auto& mapMgr = Common::Service< World::Manager::MapMgr >::ref();
|
||||
|
||||
m_quests[ idx ] = quest;
|
||||
|
||||
insertDbQuest( quest, idx );
|
||||
addQuestTracking( idx );
|
||||
|
||||
mapMgr.updateQuests( *this );
|
||||
questMgr.onUpdateQuest( *this, idx );
|
||||
|
||||
return true;
|
||||
|
@ -164,6 +171,7 @@ void Sapphire::Entity::Player::removeQuestsCompleted( uint32_t questId )
|
|||
|
||||
m_questCompleteFlags[ index ] ^= value;
|
||||
|
||||
Common::Service< World::Manager::MapMgr >::ref().updateQuests( *this );
|
||||
}
|
||||
|
||||
Sapphire::World::Quest& Sapphire::Entity::Player::getQuestByIndex( uint16_t index )
|
||||
|
|
|
@ -107,10 +107,18 @@ namespace Sapphire::Event
|
|||
SwitchTalk = 0x001F,
|
||||
Adventure = 0x0020,
|
||||
DailyQuestSupply = 0x0021,
|
||||
TripleTriad = 0x0023,
|
||||
ICDirector = 0x8003,
|
||||
QuestBattleDirector = 0x8006,
|
||||
};
|
||||
|
||||
enum class QuestAvailability : uint8_t
|
||||
{
|
||||
Invisible,
|
||||
Available,
|
||||
Locked
|
||||
};
|
||||
|
||||
using SceneReturnCallback = std::function< void( Entity::Player&, const SceneResult& ) >;
|
||||
using QuestSceneReturnCallback = std::function< void( World::Quest&, Entity::Player&, const SceneResult& ) >;
|
||||
using SceneChainCallback = std::function< void( Entity::Player& ) >;
|
||||
|
@ -182,4 +190,4 @@ namespace Sapphire::Event
|
|||
QuestSceneReturnCallback m_questReturnCallback;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
|
671
src/world/Manager/MapMgr.cpp
Normal file
671
src/world/Manager/MapMgr.cpp
Normal file
|
@ -0,0 +1,671 @@
|
|||
#include <Common.h>
|
||||
#include <Service.h>
|
||||
|
||||
#include <datReader/DatCategories/bg/lgb.h>
|
||||
#include <Exd/ExdData.h>
|
||||
|
||||
#include <Event/EventHandler.h>
|
||||
#include <Event/Director.h>
|
||||
|
||||
#include <Network/CommonActorControl.h>
|
||||
#include <Network/GameConnection.h>
|
||||
#include <Network/PacketDef/Zone/ServerZoneDef.h>
|
||||
#include <Network/PacketWrappers/ActorControlSelfPacket.h>
|
||||
|
||||
#include <Logging/Logger.h>
|
||||
#include <Util/Util.cpp>
|
||||
|
||||
#include <Actor/Player.h>
|
||||
#include <Inventory/Item.h>
|
||||
|
||||
#include "Territory/InstanceObjectCache.h"
|
||||
#include "Script/ScriptMgr.h"
|
||||
#include "Script/NativeScriptMgr.h"
|
||||
|
||||
#include "MapMgr.h"
|
||||
|
||||
#include "Session.h"
|
||||
#include "WorldServer.h"
|
||||
|
||||
using namespace Sapphire::Event;
|
||||
using namespace Sapphire::Network::Packets;
|
||||
using namespace Sapphire::Network::Packets::WorldPackets::Server;
|
||||
using namespace Sapphire::World::Manager;
|
||||
|
||||
bool MapMgr::loadQuests()
|
||||
{
|
||||
auto& exdData = Common::Service< Data::ExdData >::ref();
|
||||
auto idList = exdData.getIdList< Excel::Quest >();
|
||||
|
||||
for( auto id : idList )
|
||||
{
|
||||
auto questExdData = exdData.getRow< Excel::Quest >( id );
|
||||
|
||||
m_quests.emplace( id, std::move( questExdData ) );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MapMgr::updateAll( Entity::Player& player )
|
||||
{
|
||||
auto& exdData = Common::Service< Data::ExdData >::ref();
|
||||
auto& objectCache = Common::Service< Sapphire::InstanceObjectCache >::ref();
|
||||
|
||||
EventSet mapData;
|
||||
|
||||
auto eventNpcs = objectCache.getAllENpc( player.getTerritoryTypeId() );
|
||||
if( !eventNpcs )
|
||||
return;
|
||||
|
||||
for( const auto& eventNpc : *eventNpcs )
|
||||
{
|
||||
auto eNpc = exdData.getRow< Excel::ENpcBase >( eventNpc.second->data.enpcId );
|
||||
if( !eNpc )
|
||||
continue;
|
||||
|
||||
auto eNpcData = eNpc->data().EventHandler;
|
||||
for( int npcEvent = 0; npcEvent < 32; npcEvent++ )
|
||||
{
|
||||
auto npcData = eNpcData[ npcEvent ].EventHandler;
|
||||
|
||||
if( npcData == 0 )
|
||||
continue; // Some npcs have data gaps, so we have to iterate through the entire array
|
||||
|
||||
EventData eventData;
|
||||
eventData.layoutId = npcData;
|
||||
eventData.handlerId = eventNpc.first;
|
||||
|
||||
auto eventHandlerType = static_cast< EventHandler::EventHandlerType >( npcData >> 16 );
|
||||
|
||||
switch( eventHandlerType )
|
||||
{
|
||||
case EventHandler::EventHandlerType::Quest:
|
||||
{
|
||||
auto& quest = m_quests[ npcData ]->data();
|
||||
|
||||
if( quest.Client == eventNpc.second->data.enpcId )
|
||||
{
|
||||
insertQuest( player, npcData, eventNpc.first, mapData );
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EventHandler::EventHandlerType::GuildLeveAssignment:
|
||||
{
|
||||
if( player.hasReward( static_cast< Common::UnlockEntry >( 5 ) ) )
|
||||
{
|
||||
auto& guildLeve = exdData.getRow< Excel::GuildleveAssignment >( npcData )->data();
|
||||
|
||||
eventData.iconId = exdData.getRow< Excel::EventIconType >( 5 )->data().MapAvailable + 1;
|
||||
|
||||
if( player.isQuestCompleted( guildLeve.UnlockQuest ) ||
|
||||
( ( guildLeve.NeedGrandCompanyRank > 0 || npcData == 393217 || npcData == 393223 || npcData == 393225 ) && // Leve npc locations: Bentbranch / Horizon / Swiftperch
|
||||
( player.isQuestCompleted( 220 ) || player.isQuestCompleted( 687 ) || player.isQuestCompleted( 693 ) ) ) )
|
||||
{
|
||||
if( guildLeve.NeedGrandCompanyRank > 0 && player.getGc() != 0 )
|
||||
{
|
||||
for( int8_t i = 0; i < 3; i++ )
|
||||
{
|
||||
if( player.getGcRankArray()[ i ] >= guildLeve.NeedGrandCompanyRank )
|
||||
{
|
||||
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.getRow< Excel::CustomTalk >( npcData )->data();
|
||||
|
||||
eventData.iconId = customTalk.MapIcon;
|
||||
|
||||
mapData.insert( eventData );
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EventHandler::EventHandlerType::GuildOrderGuide:
|
||||
{
|
||||
if( player.hasReward( static_cast< Common::UnlockEntry>( 7 ) ) )
|
||||
{
|
||||
eventData.iconId = exdData.getRow< Excel::EventIconType >( 6 )->data().MapAvailable + 1;
|
||||
|
||||
mapData.insert( eventData );
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EventHandler::EventHandlerType::TripleTriad:
|
||||
{
|
||||
if( npcData == 2293771 ) // Triple Triad Master npc for now only
|
||||
{
|
||||
eventData.iconId = exdData.getRow< Excel::EventIconType >( 7 )->data().MapAvailable + 1;
|
||||
|
||||
mapData.insert( eventData );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto eventObjs = objectCache.getAllEObj( player.getTerritoryTypeId() );
|
||||
if( !eventObjs )
|
||||
return;
|
||||
|
||||
for( const auto& eventObj : *eventObjs )
|
||||
{
|
||||
auto eObj = exdData.getRow< Excel::EObj >( eventObj.second->data.BaseId );
|
||||
if( !eObj )
|
||||
return;
|
||||
|
||||
auto eObjData = eObj->data();
|
||||
EventData eventData;
|
||||
eventData.handlerId = eObjData.EventHandler;
|
||||
eventData.layoutId = eventObj.first;
|
||||
|
||||
auto eventHandlerType = static_cast< EventHandler::EventHandlerType >( eObjData.EventHandler >> 16 );
|
||||
|
||||
if( eventHandlerType == EventHandler::EventHandlerType::Quest )
|
||||
{
|
||||
auto& quest = m_quests[ eObjData.EventHandler ]->data();
|
||||
|
||||
if( quest.Client == eventObj.second->data.BaseId )
|
||||
{
|
||||
insertQuest( player, eObjData.EventHandler, eventObj.first, mapData );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sendPackets( player, mapData, All );
|
||||
}
|
||||
|
||||
void MapMgr::updateQuests( Entity::Player& player )
|
||||
{
|
||||
auto& exdData = Common::Service< Data::ExdData >::ref();
|
||||
auto& objectCache = Common::Service< Sapphire::InstanceObjectCache >::ref();
|
||||
|
||||
EventSet mapData;
|
||||
|
||||
auto eventNpcs = objectCache.getAllENpc( player.getTerritoryTypeId() );
|
||||
if( !eventNpcs )
|
||||
return;
|
||||
|
||||
for( const auto& eventNpc : *eventNpcs )
|
||||
{
|
||||
auto eNpc = exdData.getRow< Excel::ENpcBase >( eventNpc.second->data.enpcId );
|
||||
if( !eNpc )
|
||||
continue;
|
||||
|
||||
auto eNpcData = eNpc->data().EventHandler;
|
||||
|
||||
for( int npcEvent = 0; npcEvent < 32; npcEvent++ )
|
||||
{
|
||||
auto npcData = eNpcData[ npcEvent ].EventHandler;
|
||||
|
||||
if( npcData == 0 )
|
||||
continue; // Some npcs have data gaps, so we have to iterate through the entire array
|
||||
|
||||
EventData eventData;
|
||||
eventData.handlerId = npcData;
|
||||
eventData.layoutId = eventNpc.first;
|
||||
|
||||
auto eventHandlerType = static_cast< EventHandler::EventHandlerType >( npcData >> 16 );
|
||||
|
||||
if( eventHandlerType == EventHandler::EventHandlerType::Quest )
|
||||
{
|
||||
auto& quest = m_quests[ npcData ]->data();
|
||||
|
||||
if( quest.Client == eventNpc.second->data.enpcId )
|
||||
{
|
||||
insertQuest( player, npcData, eventNpc.first, mapData );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto eventObjs = objectCache.getAllEObj( player.getTerritoryTypeId() );
|
||||
if( !eventObjs )
|
||||
return;
|
||||
|
||||
for( const auto& eventObj : *eventObjs )
|
||||
{
|
||||
auto eObj = exdData.getRow< Excel::EObj >( eventObj.second->data.BaseId );
|
||||
if( !eObj )
|
||||
return;
|
||||
|
||||
auto eObjData = eObj->data();
|
||||
EventData eventData;
|
||||
eventData.handlerId = eObjData.EventHandler;
|
||||
eventData.layoutId = eventObj.first;
|
||||
|
||||
auto eventHandlerType = static_cast< EventHandler::EventHandlerType >( eObjData.EventHandler >> 16 );
|
||||
|
||||
if( eventHandlerType == EventHandler::EventHandlerType::Quest )
|
||||
{
|
||||
auto& quest = m_quests[ eObjData.EventHandler ]->data();
|
||||
|
||||
if( quest.Client == eventObj.second->data.BaseId )
|
||||
{
|
||||
insertQuest( player, eObjData.EventHandler, eventObj.first, mapData );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sendPackets( player, mapData, Quest );
|
||||
}
|
||||
|
||||
void MapMgr::insertQuest( Entity::Player& player, uint32_t questId, uint32_t layoutId, EventSet& mapData )
|
||||
{
|
||||
auto& exdData = Common::Service< Data::ExdData >::ref();
|
||||
auto& scriptMgr = Common::Service< Scripting::ScriptMgr >::ref();
|
||||
|
||||
auto& quest = m_quests[ questId ]->data();
|
||||
|
||||
if( isQuestVisible( player, questId, quest ) )
|
||||
{
|
||||
auto script = scriptMgr.getNativeScriptHandler().getScript< Sapphire::ScriptAPI::QuestScript >( questId );
|
||||
|
||||
// Just don't show quests on map, that aren't implemented yet
|
||||
if( !script )
|
||||
return;
|
||||
|
||||
EventData eventData;
|
||||
eventData.handlerId = questId;
|
||||
eventData.layoutId = layoutId;
|
||||
|
||||
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.getRow< Excel::EventIconType >( quest.IconType )->data().MapAvailable + 1 + quest.Repeatable;
|
||||
else
|
||||
eventData.iconId = exdData.getRow< Excel::EventIconType >( quest.IconType )->data().MapInvalid + 1 + quest.Repeatable;
|
||||
|
||||
mapData.insert( eventData );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool MapMgr::isQuestAvailable( Entity::Player& player, uint32_t questId, Excel::Quest& quest )
|
||||
{
|
||||
auto& exdData = Common::Service< Data::ExdData >::ref();
|
||||
|
||||
if( quest.GrandCompany || quest.GrandCompanyRank )
|
||||
{
|
||||
if( quest.GrandCompany != player.getGc() && quest.GrandCompanyRank > player.getGcRankArray()[ player.getGc() - 1 ] )
|
||||
return false;
|
||||
}
|
||||
|
||||
if( quest.InstanceContentOperator == 1 )
|
||||
{
|
||||
for( int32_t i = 0; i < 3; i++ )
|
||||
{
|
||||
if( quest.InstanceContent[ i ] == 0 )
|
||||
continue;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if( quest.InstanceContentOperator == 2 )
|
||||
{
|
||||
for( int32_t i = 0; i < 3; i++ )
|
||||
{
|
||||
if( quest.InstanceContent[ i ] == 0 )
|
||||
continue;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if( quest.TimeBegin || quest.TimeEnd )
|
||||
{
|
||||
uint64_t curEorzeaTime = Util::getEorzeanTimeStamp();
|
||||
uint32_t convTime = 100 * ( curEorzeaTime / 3600 % 24 ) + curEorzeaTime / 60 % 60;
|
||||
|
||||
if( quest.TimeBegin <= quest.TimeEnd )
|
||||
{
|
||||
if( convTime < quest.TimeBegin || convTime >= quest.TimeEnd )
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( convTime < quest.TimeBegin && convTime >= quest.TimeEnd )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
auto classJobCategory = exdData.getRow< Excel::ClassJobCategory >( quest.ClassJob )->data().ClassJob;
|
||||
if( !classJobCategory[ static_cast< uint8_t >( player.getClass() ) ] )
|
||||
return false;
|
||||
|
||||
if( quest.ClassJob2 > 1 )
|
||||
{
|
||||
classJobCategory = exdData.getRow< Excel::ClassJobCategory >( quest.ClassJob2 )->data().ClassJob;
|
||||
if( !classJobCategory[ static_cast< uint8_t >( player.getClass() ) ] )
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MapMgr::isQuestVisible( Entity::Player& player, uint32_t questId, Excel::Quest& quest )
|
||||
{
|
||||
auto& exdData = Common::Service< Data::ExdData >::ref();
|
||||
|
||||
if( ( player.isQuestCompleted( questId ) && ( !quest.Repeatable && questId != 67114 ) ) || player.hasQuest( questId ) )
|
||||
return false;
|
||||
|
||||
if( quest.ClassJobUnlock && quest.ClassJob != 1 )
|
||||
{
|
||||
if( quest.ClassJobUnlockFlag == 3 )
|
||||
if( static_cast< uint8_t >( player.getClass() ) != quest.ClassJobUnlock )
|
||||
return false;
|
||||
else if( quest.ClassJobUnlockFlag == 4 )
|
||||
if ( static_cast< uint8_t >( player.getClass() ) == quest.ClassJobUnlock )
|
||||
return false;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
// Was this really ever used?
|
||||
if( quest.StartTown && quest.StartTown != player.getStartTown() )
|
||||
return false;
|
||||
|
||||
if( Common::CURRENT_EXPANSION_ID < quest.Expansion )
|
||||
return false;
|
||||
|
||||
if( quest.Mount && !player.hasMount( quest.Mount ) )
|
||||
return false;
|
||||
|
||||
if( quest.GrandCompany && quest.GrandCompany != player.getGc() )
|
||||
return false;
|
||||
|
||||
if( quest.Header != 0 && !player.hasReward( static_cast< Common::UnlockEntry >( quest.Header ) ) )
|
||||
return false;
|
||||
|
||||
if( quest.PrevQuestOperator == 1 )
|
||||
{
|
||||
for( int32_t i = 0; i < 3; i++ )
|
||||
{
|
||||
if( quest.PrevQuest[ i ] == 0 )
|
||||
continue;
|
||||
|
||||
if( !player.isQuestCompleted( quest.PrevQuest[ i ] ) )
|
||||
{
|
||||
// todo: see if this can be done in 3.x
|
||||
/*if( i == 0 && questPtr->previousQuest0Sequence != 0 )
|
||||
{
|
||||
if( player.getQuestSeq( questPtr->previousQuest[ i ] ) < questPtr->previousQuest0Sequence )
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}*/
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( quest.PrevQuestOperator == 2 )
|
||||
{
|
||||
for( int32_t i = 0; i < 3; i++ )
|
||||
{
|
||||
if( quest.PrevQuest[ i ] == 0 )
|
||||
continue;
|
||||
|
||||
if( player.isQuestCompleted( quest.PrevQuest[ i ] ) )
|
||||
break;
|
||||
|
||||
if( i == 2 )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if( quest.ExcludeQuestOperator == 1 )
|
||||
{
|
||||
for( int32_t i = 0; i < 2; i++ )
|
||||
{
|
||||
if( quest.ExcludeQuest[ i ] == 0 )
|
||||
continue;
|
||||
|
||||
if( !player.isQuestCompleted( quest.ExcludeQuest[ i ] ) && !player.hasQuest( quest.ExcludeQuest[ i ] ) )
|
||||
break;
|
||||
|
||||
if( i == 1 )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if( quest.ExcludeQuestOperator == 2 )
|
||||
{
|
||||
for( int32_t i = 0; i < 2; i++ )
|
||||
{
|
||||
if( quest.ExcludeQuest[ i ] == 0 )
|
||||
continue;
|
||||
|
||||
if( player.isQuestCompleted( quest.ExcludeQuest[ i ] ) || player.hasQuest( quest.ExcludeQuest[ i ] ) )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if( quest.Festival )
|
||||
{
|
||||
auto& territoryMgr = Common::Service< Manager::TerritoryMgr >::ref();
|
||||
auto& festival = territoryMgr.getCurrentFestival();
|
||||
|
||||
if( quest.Festival != festival.first && quest.Festival != festival.second )
|
||||
return false;
|
||||
|
||||
// Don't show festivals with begin state other than 0 yet
|
||||
if( quest.FestivalPhaseBegin != 0 )
|
||||
return false;
|
||||
}
|
||||
|
||||
if( ( quest.Type & 1 ) == 0 )
|
||||
{
|
||||
auto classJobCategory = exdData.getRow< Excel::ClassJobCategory >( quest.ClassJob )->data().ClassJob;
|
||||
|
||||
for( int32_t i = 1; i <= Common::CLASSJOB_TOTAL; i++ )
|
||||
{
|
||||
if( i == Common::CLASSJOB_TOTAL )
|
||||
return false;
|
||||
|
||||
if( classJobCategory[ i ] )
|
||||
{
|
||||
if( player.getLevelForClass( static_cast< Common::ClassJob >( i ) ) >= quest.ClassLevel )
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( player.getLevel() < quest.ClassLevel )
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: I think this changed in 3.x to be for all relics, more research is needed.
|
||||
for( int32_t i = 0; i < Common::CLASSJOB_TOTAL; i++ )
|
||||
{
|
||||
auto classJob = exdData.getRow< Excel::ClassJob >( i );
|
||||
|
||||
if( classJob->data().ARRRelicQuestId == questId )
|
||||
{
|
||||
for( int32_t j = 0; i < Common::CLASSJOB_TOTAL; i++ )
|
||||
{
|
||||
classJob = exdData.getRow< Excel::ClassJob >( i );
|
||||
|
||||
if( player.hasQuest( classJob->data().ARRRelicQuestId ) )
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( quest.BeastTribe )
|
||||
return false;
|
||||
|
||||
if( quest.House )
|
||||
return false;
|
||||
|
||||
if( quest.DeliveryQuest )
|
||||
return false;
|
||||
|
||||
// TODO: dunno if 3.x has this, have to check
|
||||
/*if( player.getQuestSeq( questId ) == 0 )
|
||||
{
|
||||
auto& questAccept = exdData.getRow< Excel::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 MapMgr::isTripleTriadAvailable( Entity::Player& player, uint32_t tripleTriadId )
|
||||
{
|
||||
// TODO: map out Triple Triad sheet
|
||||
/*auto& exdData = Common::Service< Data::ExdData >::ref();
|
||||
auto tripleTriad = exdData.getRow< Excel::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 MapMgr::fillPacket( EventSet& mapData, uint32_t* iconIds, uint32_t* layoutIds, uint32_t* handlerIds )
|
||||
{
|
||||
int32_t i = 0;
|
||||
for( auto& eventData : mapData )
|
||||
{
|
||||
iconIds[ i ] = eventData.iconId;
|
||||
layoutIds[ i ] = eventData.layoutId;
|
||||
handlerIds[ i ] = eventData.handlerId;
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void MapMgr::sendPackets( Entity::Player& player, EventSet& mapData, UpdateMode updateMode )
|
||||
{
|
||||
auto& server = Common::Service< World::WorldServer >::ref();
|
||||
|
||||
server.queueForPlayer( player.getCharacterId(), makeActorControlSelf( player.getId(), Network::ActorControl::BeginMapUpdate, updateMode ) );
|
||||
|
||||
if( mapData.size() <= 2 )
|
||||
{
|
||||
auto mapUpdatePacket = makeZonePacket< FFXIVIpcMapMarker2 >( player.getId() );
|
||||
mapUpdatePacket->data().numOfMarkers = mapData.size();
|
||||
|
||||
fillPacket( mapData, mapUpdatePacket->data().iconIds, mapUpdatePacket->data().layoutIds, mapUpdatePacket->data().handlerIds );
|
||||
|
||||
server.queueForPlayer( player.getCharacterId(), mapUpdatePacket );
|
||||
}
|
||||
else if( mapData.size() <= 4 )
|
||||
{
|
||||
auto mapUpdatePacket = makeZonePacket< FFXIVIpcMapMarker4 >( player.getId() );
|
||||
mapUpdatePacket->data().numOfMarkers = mapData.size();
|
||||
|
||||
fillPacket( mapData, mapUpdatePacket->data().iconIds, mapUpdatePacket->data().layoutIds, mapUpdatePacket->data().handlerIds );
|
||||
|
||||
server.queueForPlayer( player.getCharacterId(), mapUpdatePacket );
|
||||
}
|
||||
else if( mapData.size() <= 8 )
|
||||
{
|
||||
auto mapUpdatePacket = makeZonePacket< FFXIVIpcMapMarker8 >( player.getId() );
|
||||
mapUpdatePacket->data().numOfMarkers = mapData.size();
|
||||
|
||||
fillPacket( mapData, mapUpdatePacket->data().iconIds, mapUpdatePacket->data().layoutIds, mapUpdatePacket->data().handlerIds );
|
||||
|
||||
server.queueForPlayer( player.getCharacterId(), mapUpdatePacket );
|
||||
}
|
||||
else if( mapData.size() <= 16 )
|
||||
{
|
||||
auto mapUpdatePacket = makeZonePacket< FFXIVIpcMapMarker16 >( player.getId() );
|
||||
mapUpdatePacket->data().numOfMarkers = mapData.size();
|
||||
|
||||
fillPacket( mapData, mapUpdatePacket->data().iconIds, mapUpdatePacket->data().layoutIds, mapUpdatePacket->data().handlerIds );
|
||||
|
||||
server.queueForPlayer( player.getCharacterId(), mapUpdatePacket );
|
||||
}
|
||||
else if( mapData.size() <= 32 )
|
||||
{
|
||||
auto mapUpdatePacket = makeZonePacket< FFXIVIpcMapMarker32 >( player.getId() );
|
||||
mapUpdatePacket->data().numOfMarkers = mapData.size();
|
||||
|
||||
fillPacket( mapData, mapUpdatePacket->data().iconIds, mapUpdatePacket->data().layoutIds, mapUpdatePacket->data().handlerIds );
|
||||
|
||||
server.queueForPlayer( player.getCharacterId(), mapUpdatePacket );
|
||||
}
|
||||
else if( mapData.size() <= 64 )
|
||||
{
|
||||
auto mapUpdatePacket = makeZonePacket< FFXIVIpcMapMarker64 >( player.getId() );
|
||||
mapUpdatePacket->data().numOfMarkers = mapData.size();
|
||||
|
||||
fillPacket( mapData, mapUpdatePacket->data().iconIds, mapUpdatePacket->data().layoutIds, mapUpdatePacket->data().handlerIds );
|
||||
|
||||
server.queueForPlayer( player.getCharacterId(), mapUpdatePacket );
|
||||
}
|
||||
else if( mapData.size() <= 128 )
|
||||
{
|
||||
auto mapUpdatePacket = makeZonePacket< FFXIVIpcMapMarker128 >( player.getId() );
|
||||
mapUpdatePacket->data().numOfMarkers = mapData.size();
|
||||
|
||||
fillPacket( mapData, mapUpdatePacket->data().iconIds, mapUpdatePacket->data().layoutIds, mapUpdatePacket->data().handlerIds );
|
||||
|
||||
server.queueForPlayer( player.getCharacterId(), mapUpdatePacket );
|
||||
}
|
||||
|
||||
server.queueForPlayer( player.getCharacterId(), makeActorControlSelf( player.getId(), Network::ActorControl::FinishMapUpdate ) );
|
||||
}
|
80
src/world/Manager/MapMgr.h
Normal file
80
src/world/Manager/MapMgr.h
Normal file
|
@ -0,0 +1,80 @@
|
|||
#pragma once
|
||||
|
||||
#include <Common.h>
|
||||
#include "ForwardsZone.h"
|
||||
|
||||
#include "Territory/Territory.h"
|
||||
|
||||
#include <bitset>
|
||||
#include <map>
|
||||
|
||||
namespace Sapphire::World::Manager
|
||||
{
|
||||
using QuestMap = std::unordered_map< uint32_t, std::shared_ptr< Excel::ExcelStruct< Excel::Quest > > >;
|
||||
|
||||
class MapMgr
|
||||
{
|
||||
public:
|
||||
enum UpdateMode : uint8_t
|
||||
{
|
||||
Quest = 1,
|
||||
GuildLeveAssignment = 2,
|
||||
GuildOrderGuide = 4,
|
||||
TripleTriad = 8,
|
||||
CustomTalk = 16,
|
||||
PreHandler = 32,
|
||||
|
||||
Fates = 0x0F,
|
||||
|
||||
All = 0x3F
|
||||
};
|
||||
|
||||
MapMgr() = default;
|
||||
|
||||
bool loadQuests();
|
||||
|
||||
void updateAll( Entity::Player& player );
|
||||
void updateQuests( Entity::Player& player );
|
||||
|
||||
private:
|
||||
struct EventData
|
||||
{
|
||||
uint32_t iconId;
|
||||
uint32_t layoutId;
|
||||
uint32_t handlerId;
|
||||
};
|
||||
|
||||
struct less
|
||||
{
|
||||
constexpr bool operator()( const EventData& _Left, const EventData& _Right ) const
|
||||
{
|
||||
const uint16_t left = _Left.handlerId;
|
||||
const uint16_t right = _Right.handlerId;
|
||||
|
||||
if( left == right )
|
||||
{
|
||||
const uint16_t typeLeft = _Left.handlerId >> 16;
|
||||
const uint16_t typeRight = _Right.handlerId >> 16;
|
||||
|
||||
return typeLeft < typeRight;
|
||||
}
|
||||
|
||||
return left < right;
|
||||
}
|
||||
};
|
||||
|
||||
using EventSet = std::multiset< EventData, less >;
|
||||
|
||||
QuestMap m_quests;
|
||||
|
||||
void insertQuest( Entity::Player& player, uint32_t questId, uint32_t layoutId, EventSet& mapData );
|
||||
|
||||
bool isQuestVisible( Entity::Player& player, uint32_t questId, Excel::Quest& quest );
|
||||
bool isQuestAvailable( Entity::Player& player, uint32_t questId, Excel::Quest& quest );
|
||||
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 );
|
||||
};
|
||||
|
||||
}
|
|
@ -16,6 +16,7 @@
|
|||
#include <Network/PacketWrappers/ActorControlPacket.h>
|
||||
|
||||
#include <Manager/PlayerMgr.h>
|
||||
#include <Manager/MapMgr.h>
|
||||
|
||||
#include "Territory/Territory.h"
|
||||
#include "Actor/Player.h"
|
||||
|
@ -103,6 +104,8 @@ void WarpMgr::finishWarp( Entity::Player& player )
|
|||
player.sendToInRangeSet( setStatusPacket, true );
|
||||
|
||||
playerMgr.onUnsetStateFlag( player, PlayerStateFlag::BetweenAreas );
|
||||
|
||||
Common::Service< MapMgr >::ref().updateAll( player );
|
||||
}
|
||||
|
||||
void WarpMgr::requestPlayerTeleport( Entity::Player& player, uint16_t aetheryteId, uint8_t teleportType )
|
||||
|
|
|
@ -49,7 +49,7 @@ namespace Sapphire::Network::Packets::WorldPackets::Server
|
|||
memcpy( m_data.Aetheryte, player.getAetheryteArray().data(), sizeof( m_data.Aetheryte ) );
|
||||
|
||||
// Set the class levels and exp.
|
||||
for( uint8_t i = 0; i < Common::CLASSJOB_TOTAL; ++i )
|
||||
for( uint8_t i = 0; i < Common::CLASSJOB_SLOTS; ++i )
|
||||
{
|
||||
m_data.Lv[ i ] = player.getClassArray()[ i ];
|
||||
m_data.Exp[ i ] = player.getExpArray()[ i ];
|
||||
|
|
|
@ -191,6 +191,11 @@ namespace Sapphire::ScriptAPI
|
|||
{
|
||||
}
|
||||
|
||||
Event::EventHandler::QuestAvailability QuestScript::getQuestAvailability( Sapphire::Entity::Player& player, uint32_t eventId )
|
||||
{
|
||||
return Event::EventHandler::QuestAvailability::Available;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
||||
EventObjectScript::EventObjectScript( uint32_t eobjId ) : ScriptObject( eobjId, typeid( EventObjectScript ).hash_code() )
|
||||
|
|
|
@ -273,6 +273,8 @@ namespace Sapphire::ScriptAPI
|
|||
|
||||
virtual void onEObjHit( World::Quest& quest, Sapphire::Entity::Player& player, uint64_t actorId, uint32_t actionId );
|
||||
|
||||
virtual Event::EventHandler::QuestAvailability getQuestAvailability( Sapphire::Entity::Player& player, uint32_t eventId );
|
||||
|
||||
World::Manager::EventMgr& eventMgr()
|
||||
{
|
||||
return Common::Service< World::Manager::EventMgr >::ref();
|
||||
|
|
|
@ -43,13 +43,16 @@ Sapphire::InstanceObjectCache::InstanceObjectCache()
|
|||
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
|
||||
{
|
||||
|
@ -75,9 +78,23 @@ Sapphire::InstanceObjectCache::InstanceObjectCache()
|
|||
LGB_FILE planmapLgb( &planmapSection[ 0 ], "planmap" );
|
||||
LGB_FILE planeventLgb( &planeventSection[ 0 ], "planevent" );
|
||||
|
||||
std::vector< LGB_FILE > lgbList{ bgLgb, planmapLgb, planeventLgb };
|
||||
uint32_t max_index = 0;
|
||||
|
||||
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 };
|
||||
}
|
||||
|
||||
for( const auto& lgb : lgbList )
|
||||
{
|
||||
for( const auto& group : lgb.groups )
|
||||
|
@ -110,12 +127,12 @@ Sapphire::InstanceObjectCache::InstanceObjectCache()
|
|||
else if( pEntry->getType() == LgbEntryType::EventObject )
|
||||
{
|
||||
auto pEObj = std::reinterpret_pointer_cast< LGB_EOBJ_ENTRY >( pEntry );
|
||||
m_eobjCache.insert( 0, pEObj );
|
||||
m_eobjCache.insert( id, pEObj );
|
||||
}
|
||||
else if( pEntry->getType() == LgbEntryType::EventNpc )
|
||||
{
|
||||
auto pENpc = std::reinterpret_pointer_cast< LGB_ENPC_ENTRY >( pEntry );
|
||||
m_enpcCache.insert( 0, pENpc );
|
||||
m_enpcCache.insert( id, pENpc );
|
||||
}
|
||||
else if( pEntry->getType() == LgbEntryType::EventRange )
|
||||
{
|
||||
|
@ -129,8 +146,8 @@ Sapphire::InstanceObjectCache::InstanceObjectCache()
|
|||
std::cout << "\n";
|
||||
|
||||
Logger::debug(
|
||||
"InstanceObjectCache Cached: MapRange: {} ExitRange: {} PopRange: {} EventNpc: {} EventRange: {}",
|
||||
m_mapRangeCache.size(), m_exitRangeCache.size(), m_popRangeCache.size(), m_enpcCache.size(), m_eventRangeCache.size()
|
||||
"InstanceObjectCache Cached: MapRange: {} ExitRange: {} PopRange: {} EventObj: {} EventNpc: {} EventRange: {}",
|
||||
m_mapRangeCache.size(), m_exitRangeCache.size(), m_popRangeCache.size(), m_eobjCache.size(), m_enpcCache.size(), m_eventRangeCache.size()
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -165,6 +182,18 @@ Sapphire::InstanceObjectCache::ENpcPtr
|
|||
return m_enpcCache.get( 0, eNpcId );
|
||||
}
|
||||
|
||||
Sapphire::InstanceObjectCache::EObjMapPtr
|
||||
Sapphire::InstanceObjectCache::getAllEObj( uint16_t zoneId )
|
||||
{
|
||||
return m_eobjCache.getAll( zoneId );
|
||||
}
|
||||
|
||||
Sapphire::InstanceObjectCache::ENpcMapPtr
|
||||
Sapphire::InstanceObjectCache::getAllENpc( uint16_t zoneId )
|
||||
{
|
||||
return m_enpcCache.getAll( zoneId );
|
||||
}
|
||||
|
||||
Sapphire::InstanceObjectCache::EventRangePtr Sapphire::InstanceObjectCache::getEventRange( uint32_t eventRangeId )
|
||||
{
|
||||
return m_eventRangeCache.get( 0, eventRangeId );
|
||||
|
|
|
@ -41,6 +41,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 )
|
||||
{
|
||||
if( m_objectCache.find( zoneId ) == m_objectCache.end() )
|
||||
|
@ -76,6 +86,9 @@ namespace Sapphire
|
|||
using ENpcPtr = std::shared_ptr< LGB_ENPC_ENTRY >;
|
||||
using EventRangePtr = std::shared_ptr< LGB_EVENT_RANGE_ENTRY >;
|
||||
|
||||
using EObjMapPtr = std::unordered_map< uint32_t, EObjPtr >*;
|
||||
using ENpcMapPtr = std::unordered_map< uint32_t, ENpcPtr >*;
|
||||
|
||||
struct PopRangeInfo
|
||||
{
|
||||
Common::FFXIVARR_POSITION3 m_pos;
|
||||
|
@ -95,6 +108,10 @@ namespace Sapphire
|
|||
|
||||
EObjPtr getEObj( uint32_t eObjId );
|
||||
ENpcPtr getENpc( uint32_t eNpcId );
|
||||
|
||||
EObjMapPtr getAllEObj( uint16_t zoneId );
|
||||
ENpcMapPtr getAllENpc( uint16_t zoneId );
|
||||
|
||||
EventRangePtr getEventRange( uint32_t eventRangeId );
|
||||
|
||||
private:
|
||||
|
|
|
@ -52,6 +52,7 @@
|
|||
#include "Manager/BlacklistMgr.h"
|
||||
#include "Manager/WarpMgr.h"
|
||||
#include "Manager/FreeCompanyMgr.h"
|
||||
#include "Manager/MapMgr.h"
|
||||
|
||||
#include "ContentFinder/ContentFinder.h"
|
||||
|
||||
|
@ -223,6 +224,16 @@ void WorldServer::run( int32_t argc, char* argv[] )
|
|||
}
|
||||
Common::Service< Manager::ActionMgr >::set( pActionMgr );
|
||||
|
||||
auto pMapMgr = std::make_shared< Manager::MapMgr >();
|
||||
|
||||
Logger::info( "MapMgr: Caching quests" );
|
||||
if( !pMapMgr->loadQuests() )
|
||||
{
|
||||
Logger::fatal( "Unable to cache quests!" );
|
||||
return;
|
||||
}
|
||||
Common::Service< Manager::MapMgr >::set( pMapMgr );
|
||||
|
||||
auto pNaviMgr = std::make_shared< Manager::NaviMgr >();
|
||||
Common::Service< Manager::NaviMgr >::set( pNaviMgr );
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue