1
Fork 0
mirror of https://github.com/SapphireServer/Sapphire.git synced 2025-04-25 05:57:45 +00:00

PublicContent support. (#720)

* PublicContent support.

* update code
This commit is contained in:
コレット 2021-08-16 17:18:29 +09:00 committed by GitHub
parent b1e430cf39
commit 23b7b052a1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
44 changed files with 1037 additions and 64 deletions

View file

@ -1248,9 +1248,6 @@ namespace Sapphire::Common
GetGil = 9, // p1: gil
EmptyCoffer = 11, // seems like no param
};
using PlayerStateFlagList = std::vector< PlayerStateFlag >;
}
#endif

View file

@ -111,6 +111,8 @@ namespace Sapphire::Network::ActorControl
ScreenFadeOut = 0xAA,
CeremonyDecoration = 0xB9,
ZoneIn = 0xC8,
ZoneInDefaultPos = 0xC9,
@ -364,6 +366,7 @@ namespace Sapphire::Network::ActorControl
TitleList = 0x12F,
UpdatedSeenHowTos = 0x133,
CutscenePlayed = 0x134, // param1 = cutscene id
AllotAttribute = 0x135,
ClearFieldMarkers = 0x13A,

View file

@ -194,14 +194,7 @@ namespace Sapphire::Network::Packets
EventPlay128 = 0x026E, // updated 5.58
EventPlay255 = 0x039E, // updated 5.58
EventYield = 0x0123, // updated 5.58
//EventYield4 = 0x0000,
//EventYield8 = 0x0000,
//EventYield16 = 0x0000,
//EventYield32 = 0x0000,
//EventYield64 = 0x0000,
//EventYield128 = 0x0000,
//EventYield255 = 0x0000,
EventContinue = 0x0123, // updated 5.58
EventStart = 0x01CC, // updated 5.58
EventFinish = 0x0180, // updated 5.58
@ -274,6 +267,8 @@ namespace Sapphire::Network::Packets
LandSetMap = 0x02F6, // updated 5.58
CeremonySetActorAppearance = 0x00EB, // updated 5.58
//////////////////////////////////////////////////
DuelChallenge = 0x0277, // 4.2; this is responsible for opening the ui
@ -390,7 +385,7 @@ namespace Sapphire::Network::Packets
BuildPresetHandler = 0x00DC, // updated 5.58
TalkEventHandler = 0x012D, // updated 5.58
EmoteEventHandler = 0xF35A, // updated 5.55 hotfix
EmoteEventHandler = 0x039E, // updated 5.58
WithinRangeEventHandler = 0x022C, // updated 5.58
OutOfRangeEventHandler = 0x0294, // updated 5.58
EnterTeriEventHandler = 0x00C1, // updated 5.58
@ -398,7 +393,8 @@ namespace Sapphire::Network::Packets
EventYieldHandler = 0x03A2, // updated 5.58
ReturnEventHandler = 0x0333, // updated 5.58
TradeReturnEventHandler = 0x0179, // updated 5.58
TradeReturnEventHandler2 = 0x0169, // updated 5.55 hotfix
TradeReturnEventHandler2 = 0x02E1, // updated 5.58
EventYield16Handler = 0x03D7, // updated 5.58
LinkshellEventHandler = 0x016B, // updated 4.5
LinkshellEventHandler1 = 0x016C, // updated 4.5

View file

@ -446,6 +446,24 @@ struct FFXIVIpcHousingEditInterior :
uint16_t slot[10];
};
struct FFXIVIpcEventYieldHandler :
FFXIVIpcBasePacket< EventYieldHandler >
{
uint32_t eventId;
uint16_t scene;
uint16_t padding;
uint64_t unknown;
};
struct FFXIVIpcEventYield16Handler :
FFXIVIpcBasePacket< EventYield16Handler >
{
uint32_t eventId;
uint16_t scene;
uint16_t padding;
uint32_t params[16];
};
struct FFXIVIpcCFCommenceHandler :
FFXIVIpcBasePacket< CFCommenceHandler >
{

View file

@ -1439,6 +1439,20 @@ namespace Sapphire::Network::Packets::Server
uint8_t unknown[8];
};
struct FFXIVIpcEventPlay16 : FFXIVIpcBasePacket< EventPlay16 >
{
uint64_t actorId;
uint32_t eventId;
uint16_t scene;
uint16_t padding;
uint32_t flags;
uint32_t param3;
uint8_t paramSize;
uint8_t padding1[3];
uint32_t param[16];
uint32_t padding2;
};
template< int ArgCount >
struct FFXIVIpcEventPlayN
{
@ -1835,7 +1849,7 @@ namespace Sapphire::Network::Packets::Server
uint32_t bNPCName;
uint32_t textId;
uint32_t popupTimeMs;
uint32_t pad3[4];
uint32_t param[6];
};
@ -2238,6 +2252,43 @@ namespace Sapphire::Network::Packets::Server
char memberName[32];
uint8_t padding[3];
};
struct FFXIVIpcEventContinue : FFXIVIpcBasePacket< EventContinue >
{
uint32_t eventId;
uint16_t scene;
uint16_t unknown;
uint64_t unknown2;
};
struct FFXIVDirectorUnk4 : FFXIVIpcBasePacket< SomeDirectorUnk4 >
{
uint32_t param[4];
uint64_t unknown;
};
struct FFXIVCeremonySetActorAppearance : FFXIVIpcBasePacket< CeremonySetActorAppearance >
{
uint8_t u1;
uint8_t questBL;
uint16_t padding1;
uint32_t u3;
struct
{
uint64_t mainWeaponModel;
uint64_t secWeaponModel;
uint64_t craftToolModel;
uint32_t c_u6;
uint32_t c_u7;
uint32_t charId;
uint16_t u4;
uint16_t guardianDeity;
uint32_t u5;
uint32_t models[10];
uint8_t look[26];
uint16_t padding3;
} actors[2];
};
}
#endif /*_CORE_NETWORK_PACKETS_SERVER_IPC_H*/

View file

@ -77,3 +77,8 @@ uint8_t Util::floatToUInt8Rot( float val )
{
return static_cast< uint8_t >( 0x80 * ( ( val + PI ) ) / PI );
}
float Util::floatFromUInt16Rot( uint16_t rot )
{
return rot / 32768.0f * PI - PI;
}

View file

@ -25,6 +25,8 @@ namespace Sapphire::Common::Util
uint16_t floatToUInt16Rot( float val );
float floatFromUInt16Rot( uint16_t rot );
uint8_t floatToUInt8Rot( float val );
template < typename T >

View file

@ -32,7 +32,7 @@ public:
// todo: this is fucked
};
player.playScene( getId(), 1, 0xFB2EC8F8, 0, 1, returnScene, callback );
player.playScene( getId(), 1, FADE_OUT | CONDITION_CUTSCENE | HIDE_UI, 0, 1, returnScene, callback );
}
void onTalk( uint32_t eventId, Entity::Player& player, uint64_t actorId ) override

View file

@ -78,7 +78,7 @@ public:
return;
}
player.setInstance( internalZone, pos );
player.setInstance( internalZone, pos, player.getRot() );
} );
}
};

View file

@ -351,7 +351,7 @@ Sapphire::InstanceContentPtr Sapphire::Entity::Actor::getCurrentInstance() const
return nullptr;
}
/*! \return QuestBattlePtr to the current instance, nullptr if not an instance or not set */
/*! \return QuestBattlePtr to the current instance, nullptr if not a quest battle or not set */
Sapphire::QuestBattlePtr Sapphire::Entity::Actor::getCurrentQuestBattle() const
{
if( m_pCurrentTerritory )
@ -360,6 +360,15 @@ Sapphire::QuestBattlePtr Sapphire::Entity::Actor::getCurrentQuestBattle() const
return nullptr;
}
/*! \return PublicContentPtr to the current instance, nullptr if not a public content or not set */
Sapphire::PublicContentPtr Sapphire::Entity::Actor::getCurrentPublicContent() const
{
if( m_pCurrentTerritory )
return m_pCurrentTerritory->getAsPublicContent();
return nullptr;
}
/*!
Get the current cell of a region the actor is in

View file

@ -130,6 +130,8 @@ namespace Sapphire::Entity
QuestBattlePtr getCurrentQuestBattle() const;
PublicContentPtr getCurrentPublicContent() const;
// get the current cell of a region the actor is in
Cell* getCellPtr();

View file

@ -13,7 +13,7 @@ namespace Sapphire::Entity
Common::FFXIVARR_POSITION3 pos, float rotation, const std::string& givenName = "none" );
using OnTalkEventHandler = std::function< void( Entity::Player&, Entity::EventObjectPtr,
TerritoryPtr, uint64_t ) >;
TerritoryPtr, uint32_t, uint64_t ) >;
uint32_t getGimmickId() const;

View file

@ -23,6 +23,8 @@
#include "Territory/Territory.h"
#include "Territory/ZonePosition.h"
#include "Territory/InstanceContent.h"
#include "Territory/QuestBattle.h"
#include "Territory/PublicContent.h"
#include "Territory/InstanceObjectCache.h"
#include "Territory/Land.h"
@ -472,7 +474,7 @@ bool Sapphire::Entity::Player::setInstance( TerritoryPtr instance )
return teriMgr.movePlayer( instance, getAsPlayer() );
}
bool Sapphire::Entity::Player::setInstance( TerritoryPtr instance, Common::FFXIVARR_POSITION3 pos )
bool Sapphire::Entity::Player::setInstance( TerritoryPtr instance, Common::FFXIVARR_POSITION3 pos, float rot )
{
m_onEnterEventDone = false;
if( !instance )
@ -490,11 +492,17 @@ bool Sapphire::Entity::Player::setInstance( TerritoryPtr instance, Common::FFXIV
m_prevTerritoryId = getTerritoryId();
}
m_pos = pos;
m_rot = rot;
if( teriMgr.movePlayer( instance, getAsPlayer() ) )
{
m_pos = pos;
return true;
}
else
{
m_pos = m_prevPos;
m_rot= m_prevRot;
}
return false;
}
@ -503,8 +511,18 @@ bool Sapphire::Entity::Player::exitInstance()
{
auto& teriMgr = Common::Service< TerritoryMgr >::ref();
auto pZone = getCurrentTerritory();
auto pInstance = pZone->getAsInstanceContent();
auto d = getCurrentTerritory()->getAsDirector();
if( d && d->getContentFinderConditionId() > 0 )
{
auto p = makeZonePacket< FFXIVDirectorUnk4 >( getId() );
p->data().param[0] = d->getDirectorId();
p->data().param[1] = 1534;
p->data().param[2] = 1;
p->data().param[3] = d->getContentFinderConditionId();
queuePacket( p );
prepareZoning( 0, 1, 1, 0, 0, 1, 9 );
}
resetHp();
resetMp();
@ -1755,14 +1773,14 @@ void Sapphire::Entity::Player::sendZonePackets()
//setStateFlag( PlayerStateFlag::BetweenAreas );
//setStateFlag( PlayerStateFlag::BetweenAreas1 );
if( isActionLearned( static_cast< uint8_t >( Common::UnlockEntry::HuntingLog ) ) )
sendHuntingLog();
sendStats();
// only initialize the UI if the player in fact just logged in.
if( isLogin() )
{
if( isActionLearned( static_cast< uint8_t >( Common::UnlockEntry::HuntingLog ) ) )
sendHuntingLog();
auto contentFinderList = makeZonePacket< FFXIVIpcCFAvailableContents >( getId() );
for( auto i = 0; i < sizeof( contentFinderList->data().contents ); i++ )
@ -1812,6 +1830,12 @@ void Sapphire::Entity::Player::sendZonePackets()
initZonePacket->data().pos.x = getPos().x;
initZonePacket->data().pos.y = getPos().y;
initZonePacket->data().pos.z = getPos().z;
if( auto d = getCurrentTerritory()->getAsDirector() )
{
initZonePacket->data().contentfinderConditionId = d->getContentFinderConditionId();
initZonePacket->data().bitmask = 0xFF;
initZonePacket->data().bitmask1 = 0x2A;
}
queuePacket( initZonePacket );
getCurrentTerritory()->onPlayerZoneIn( *this );

View file

@ -111,6 +111,8 @@ namespace Sapphire::Entity
void playSceneChain( uint32_t eventId, uint32_t scene, uint32_t flags,
Event::EventHandler::SceneChainCallback sceneChainCallback );
void playScene16( uint32_t eventId, uint32_t scene, uint32_t flags, uint32_t param3, std::vector< uint32_t > paramList, Event::EventHandler::SceneReturnCallback eventReturnCallback );
/*! setup the event and return a ptr to it */
Event::EventHandlerPtr bootstrapSceneEvent( uint32_t eventId, uint32_t flags );
@ -490,7 +492,7 @@ namespace Sapphire::Entity
bool setInstance( TerritoryPtr instance );
/*! sets the players instance & initiates zoning process */
bool setInstance( Sapphire::TerritoryPtr instance, Sapphire::Common::FFXIVARR_POSITION3 pos );
bool setInstance( Sapphire::TerritoryPtr instance, Sapphire::Common::FFXIVARR_POSITION3 pos, float rot );
/*! returns the player to their position before zoning into an instance */
bool exitInstance();
@ -992,6 +994,8 @@ namespace Sapphire::Entity
//////////////////////////////////////////////////////////////////////////////////////////////////////
void setPosAndNotifyClient( float x, float y, float z, float rot );
Common::HuntingLogEntry& getHuntingLogEntry( uint8_t index );
void sendHuntingLog();

View file

@ -323,6 +323,33 @@ void Sapphire::Entity::Player::eventFinish( uint32_t eventId, uint32_t freePlaye
unsetStateFlag( PlayerStateFlag::InNpcEvent );
}
void Sapphire::Entity::Player::playScene16( uint32_t eventId, uint32_t scene, uint32_t flags, uint32_t param3, std::vector< uint32_t > paramList, Event::EventHandler::SceneReturnCallback eventReturnCallback )
{
auto pEvent = bootstrapSceneEvent( eventId, flags );
if( !pEvent )
return;
pEvent->setPlayedScene( true );
pEvent->setEventReturnCallback( eventReturnCallback );
pEvent->setSceneChainCallback( nullptr );
auto eventPlay16 = makeZonePacket< FFXIVIpcEventPlay16 >( getId() );
eventPlay16->data().actorId = pEvent->getActorId();
eventPlay16->data().eventId = pEvent->getId();
eventPlay16->data().scene = scene;
eventPlay16->data().flags = flags;
eventPlay16->data().param3 = param3;
eventPlay16->data().paramSize = paramList.size();
int i = 0;
for( auto p : paramList )
{
assert( i < 16 );
eventPlay16->data().param[ i ] = paramList.at( i );
i++;
}
queuePacket( eventPlay16 );
}
void Sapphire::Entity::Player::eventActionStart( uint32_t eventId,
uint32_t action,
World::Action::ActionCallback finishCallback,

View file

@ -16,9 +16,10 @@ using namespace Sapphire::Network::Packets;
using namespace Sapphire::Network::Packets::Server;
using namespace Sapphire::Network::ActorControl;
Sapphire::Event::Director::Director( Sapphire::Event::Director::DirectorType type, uint16_t contentId ) :
Sapphire::Event::Director::Director( Sapphire::Event::Director::DirectorType type, uint16_t contentId, uint16_t contentFinderConditionId ) :
m_contentId( contentId ),
m_type( type ),
m_contentFinderConditionId( contentFinderConditionId ),
m_directorId( ( static_cast< uint32_t >( type ) << 16 ) | contentId ),
m_sequence( 1 ),
m_branch( 0 ),
@ -37,6 +38,11 @@ uint16_t Sapphire::Event::Director::getContentId() const
return m_contentId;
}
uint16_t Sapphire::Event::Director::getContentFinderConditionId() const
{
return m_contentFinderConditionId;
}
uint8_t Sapphire::Event::Director::getSequence() const
{
return m_sequence;
@ -52,14 +58,18 @@ void Sapphire::Event::Director::sendDirectorVars( Sapphire::Entity::Player& play
auto varPacket = makeZonePacket< FFXIVIpcDirectorVars >( player.getId() );
varPacket->data().m_directorId = getDirectorId();
varPacket->data().m_sequence = getSequence();
varPacket->data().m_branch = 0;
varPacket->data().m_branch = getBranch();
memcpy( varPacket->data().m_unionData, m_unionData.arrData, sizeof( varPacket->data().m_unionData ) );
player.queuePacket( varPacket );
player.sendDebug( "DirectorVar#{}: {:02X}{:02X}{:02X}{:02X}{:02X}{:02X}{:02X}{:02X}{:02X}{:02X} seq{}, b{}", getDirectorId(),
m_unionData.ui8.UI8A, m_unionData.ui8.UI8B, m_unionData.ui8.UI8C, m_unionData.ui8.UI8D, m_unionData.ui8.UI8E,
m_unionData.ui8.UI8F, m_unionData.ui8.UI8G, m_unionData.ui8.UI8H, m_unionData.ui8.UI8I, m_unionData.ui8.UI8J,
getSequence(), getBranch() );
}
void Sapphire::Event::Director::sendDirectorInit( Sapphire::Entity::Player& player ) const
{
Logger::debug( "DirectorID#{}, QuestBattleID#{}", m_directorId, m_contentId );
Logger::debug( "DirectorID#{}, ContentId#{}, ContentFinderConditionId#{}", m_directorId, m_contentId, m_contentFinderConditionId );
player.queuePacket( makeActorControlSelf( player.getId(), DirectorInit, m_directorId, m_contentId ) );
}
@ -183,12 +193,12 @@ void Sapphire::Event::Director::setDirectorSequence( uint8_t value )
m_sequence = value;
}
void Sapphire::Event::Director::setCustomVar( uint32_t varId, uint32_t value )
void Sapphire::Event::Director::setCustomVar( uint32_t varId, uint64_t value )
{
m_customVarMap[ varId ] = value;
}
uint32_t Sapphire::Event::Director::getCustomVar( uint32_t varId )
uint64_t Sapphire::Event::Director::getCustomVar( uint32_t varId )
{
auto it = m_customVarMap.find( varId );
if( it != m_customVarMap.end() )

View file

@ -42,12 +42,14 @@ namespace Sapphire::Event
DutyFailed
};
Director( DirectorType type, uint16_t contentId );
Director( DirectorType type, uint16_t contentId, uint16_t contentFinderConditionId = 0 );
uint32_t getDirectorId() const;
uint16_t getContentId() const;
uint16_t getContentFinderConditionId() const;
DirectorType getType() const;
uint8_t getSequence() const;
@ -104,8 +106,8 @@ namespace Sapphire::Event
void setDirectorBranch( uint8_t value );
void setCustomVar( uint32_t varId, uint32_t value );
uint32_t getCustomVar( uint32_t varId );
void setCustomVar( uint32_t varId, uint64_t value );
uint64_t getCustomVar( uint32_t varId );
private:
/*! Id of the content of the director */
@ -114,6 +116,8 @@ namespace Sapphire::Event
/*! DirectorType | ContentId */
uint32_t m_directorId;
uint16_t m_contentFinderConditionId;
/*! currect sequence */
uint8_t m_sequence;
@ -183,7 +187,7 @@ namespace Sapphire::Event
uint32_t m_elapsedTime;
std::unordered_map< uint32_t, uint32_t > m_customVarMap;
std::unordered_map< uint32_t, uint64_t > m_customVarMap;
};

View file

@ -79,6 +79,7 @@ namespace Sapphire::Event
Adventure = 0x0021,
DailyQuestSupply = 0x0022,
ICDirector = 0x8003,
PublicContentDirector = 0x8004,
QuestBattleDirector = 0x8006,
};

View file

@ -24,6 +24,7 @@ TYPE_FORWARD( HousingZone );
TYPE_FORWARD( House );
TYPE_FORWARD( InstanceContent );
TYPE_FORWARD( QuestBattle );
TYPE_FORWARD( PublicContent );
TYPE_FORWARD( Item );
TYPE_FORWARD( ItemContainer );
TYPE_FORWARD( ZonePosition );

View file

@ -32,6 +32,7 @@
#include "Territory/HousingZone.h"
#include "Territory/InstanceContent.h"
#include "Territory/QuestBattle.h"
#include "Territory/PublicContent.h"
#include "Manager/TerritoryMgr.h"
#include "Event/EventDefs.h"
@ -60,6 +61,8 @@ Sapphire::World::Manager::DebugCommandMgr::DebugCommandMgr()
registerCommand( "script", &DebugCommandMgr::script, "Server script utilities.", 1 );
registerCommand( "instance", &DebugCommandMgr::instance, "Instance utilities", 1 );
registerCommand( "questbattle", &DebugCommandMgr::questBattle, "Quest battle utilities", 1 );
registerCommand( "pc", &DebugCommandMgr::pc, "Public content utilities", 1 );
registerCommand( "publiccontent", &DebugCommandMgr::pc, "Public content utilities", 1 );
registerCommand( "qb", &DebugCommandMgr::questBattle, "Quest battle utilities", 1 );
registerCommand( "housing", &DebugCommandMgr::housing, "Housing utilities", 1 );
}
@ -583,9 +586,23 @@ void Sapphire::World::Manager::DebugCommandMgr::get( char* data, Entity::Player&
int16_t map_id = exdData.get< Sapphire::Data::TerritoryType >( player.getCurrentTerritory()->getTerritoryTypeId() )->map;
player.sendNotice( "Pos:\n {0}\n {1}\n {2}\n {3}\n MapId: {4}\n ZoneId:{5}",
player.sendNotice( "Pos: x: {0}, y: {1}, z: {2}, r: {3}\n MapId: {4}, ZoneId:{5}, Weather:{6}, Festival:{7}, {8}",
player.getPos().x, player.getPos().y, player.getPos().z,
player.getRot(), map_id, player.getCurrentTerritory()->getTerritoryTypeId() );
player.getRot(), map_id, player.getCurrentTerritory()->getTerritoryTypeId(),
static_cast< uint8_t >( player.getCurrentTerritory()->getCurrentWeather() ), player.getCurrentTerritory()->getCurrentFestival().first,
player.getCurrentTerritory()->getCurrentFestival().second );
if( auto instance = player.getCurrentInstance() )
{
player.sendNotice( "Instance info:\nContentId: {}, DirectorId: {}\nSequence: {}, Branch: {}, BGM: {}",
instance->getInstanceContentId(), instance->getDirectorId(), instance->getSequence(),
instance->getBranch(), instance->getCurrentBGM() );
}
else if( auto instance = player.getCurrentPublicContent() )
{
player.sendNotice( "Public content info:\nContentId: {}, DirectorId: {}\nSequence: {}, Branch: {}",
instance->getContentId(), instance->getDirectorId(), instance->getSequence(),
instance->getBranch() );
}
}
else
{
@ -1282,3 +1299,137 @@ void Sapphire::World::Manager::DebugCommandMgr::housing( char* data, Entity::Pla
player.sendDebug( "Unknown sub command." );
}
}
void Sapphire::World::Manager::DebugCommandMgr::pc( char* data, Entity::Player& player, std::shared_ptr< DebugCommand > command )
{
auto& terriMgr = Common::Service< TerritoryMgr >::ref();
std::string cmd( data ), params, subCommand;
auto cmdPos = cmd.find_first_of( ' ' );
if( cmdPos != std::string::npos )
{
params = cmd.substr( cmdPos + 1 );
auto p = params.find_first_of( ' ' );
if( p != std::string::npos )
{
subCommand = params.substr( 0, p );
params = params.substr( subCommand.length() + 1 );
}
else
subCommand = params;
}
if( subCommand == "create" || subCommand == "cr" )
{
uint32_t contentFinderConditionId;
sscanf( params.c_str(), "%d", &contentFinderConditionId );
auto instance = terriMgr.createPublicContent( contentFinderConditionId );
if( instance )
player.sendDebug( "Created instance with id#{0} -> {1}", instance->getGuId(), instance->getName() );
else
player.sendDebug( "Failed to create instance with id#{0}", contentFinderConditionId );
}
else if ( subCommand == "create2" || subCommand == "cr2" )
{
uint16_t contentId, terriId;
sscanf( params.c_str(), "%hu %hu", &contentId, &terriId );
auto instance = terriMgr.createPublicContent( contentId, terriId );
if( instance )
player.sendDebug( "Created instance with id#{0} -> {1}", instance->getGuId(), instance->getName() );
else
player.sendDebug( "Failed to create instance with id#{0}, territory#{1}. Server console output may contain additional info.", contentId, terriId );
}
else if( subCommand == "remove" || subCommand == "rm" )
{
uint32_t terriId;
sscanf( params.c_str(), "%d", &terriId );
if( terriMgr.removeTerritoryInstance( terriId ) )
player.sendDebug( "Removed instance with id#{0}", terriId );
else
player.sendDebug( "Failed to remove instance with id#{0}", terriId );
}
else if( subCommand == "return" || subCommand == "ret" )
{
player.exitInstance();
}
else if( subCommand == "set" )
{
uint32_t index;
uint32_t value;
sscanf( params.c_str(), "%d %d", &index, &value );
auto instance = std::dynamic_pointer_cast< PublicContent >( player.getCurrentTerritory() );
if( !instance )
return;
instance->setVar( static_cast< uint8_t >( index ), static_cast< uint8_t >( value ) );
}
else if( subCommand == "seq" )
{
uint8_t seq;
sscanf( params.c_str(), "%hhu", &seq );
auto instance = std::dynamic_pointer_cast< PublicContent >( player.getCurrentTerritory() );
if( !instance )
return;
instance->setSequence( seq );
}
else if( subCommand == "branch" )
{
uint8_t branch;
sscanf( params.c_str(), "%hhu", &branch );
auto instance = std::dynamic_pointer_cast< PublicContent >( player.getCurrentTerritory() );
if( !instance )
return;
instance->setBranch( branch );
}
else if( subCommand == "objstate" )
{
char objName[128];
uint8_t state;
sscanf( params.c_str(), "%s %hhu", objName, &state );
auto instance = std::dynamic_pointer_cast< PublicContent >( player.getCurrentTerritory() );
if( !instance )
return;
auto obj = instance->getEObjByName( objName );
if( !obj )
return;
obj->setState( state );
}
else if( subCommand == "objflag" )
{
char objName[256];
uint32_t state1;
uint32_t state2;
sscanf( params.c_str(), "%s %i %i", objName, &state1, &state2 );
auto instance = std::dynamic_pointer_cast< PublicContent >( player.getCurrentTerritory() );
if( !instance )
return;
auto obj = instance->getEObjByName( objName );
if( !obj )
{
player.sendDebug( "No eobj found." );
return;
}
obj->setAnimationFlag( state1, state2 );
}
}

View file

@ -53,6 +53,7 @@ namespace Sapphire::World::Manager
void instance( char* data, Entity::Player& player, std::shared_ptr< DebugCommand > command );
void questBattle( char* data, Entity::Player& player, std::shared_ptr< DebugCommand > command );
void pc( char* data, Entity::Player& player, std::shared_ptr< DebugCommand > command );
void housing( char* data, Entity::Player& player, std::shared_ptr< DebugCommand > command) ;

View file

@ -74,6 +74,13 @@ std::string Sapphire::World::Manager::EventMgr::getEventName( uint32_t eventId )
name[ 0 ] = toupper( name[ 0 ] );
return name;
}
case Event::EventHandler::EventHandlerType::PublicContentDirector:
{
auto pcInfo = exdData.get< Sapphire::Data::PublicContent >( eventId & 0x0000FFFF );
if( !pcInfo )
return "unknown";
return pcInfo->name;
}
case Event::EventHandler::EventHandlerType::Warp:

View file

@ -13,6 +13,7 @@
#include "Territory/ZonePosition.h"
#include "Territory/InstanceContent.h"
#include "Territory/QuestBattle.h"
#include "Territory/PublicContent.h"
#include "TerritoryMgr.h"
#include "HousingMgr.h"
@ -316,7 +317,7 @@ Sapphire::TerritoryPtr Sapphire::World::Manager::TerritoryMgr::createQuestBattle
Logger::debug( "Starting instance for QuestBattle id: {0} ({1})", questBattleId, pQuestInfo->name );
auto pZone = make_QuestBattle( pQuestBattleInfo, pContentFinderCondition->territoryType, getNextInstanceId(),
pTeri->name, pQuestInfo->name, questBattleId );
pTeri->name, pQuestInfo->name, questBattleId, contentFinderConditionId );
pZone->init();
m_questBattleIdToInstanceMap[ questBattleId ][ pZone->getGuId() ] = pZone;
@ -350,7 +351,7 @@ Sapphire::TerritoryPtr Sapphire::World::Manager::TerritoryMgr::createInstanceCon
Logger::debug( "Starting instance for InstanceContent id: {0} ({1})", instanceContentId, pContentFinderCondition->name );
auto pZone = make_InstanceContent( pInstanceContent, pContentFinderCondition->territoryType, getNextInstanceId(),
pTeri->name, pContentFinderCondition->name, instanceContentId );
pTeri->name, pContentFinderCondition->name, instanceContentId, contentFinderConditionId );
pZone->init();
m_instanceContentIdToInstanceMap[ instanceContentId ][ pZone->getGuId() ] = pZone;
@ -360,6 +361,68 @@ Sapphire::TerritoryPtr Sapphire::World::Manager::TerritoryMgr::createInstanceCon
return pZone;
}
Sapphire::TerritoryPtr Sapphire::World::Manager::TerritoryMgr::createPublicContent( uint32_t contentFinderConditionId )
{
auto& exdData = Common::Service< Data::ExdDataGenerated >::ref();
auto pContentFinderCondition = exdData.get< Sapphire::Data::ContentFinderCondition >( contentFinderConditionId );
if( !pContentFinderCondition )
return nullptr;
auto contentId = pContentFinderCondition->content;
auto pPublicContent = exdData.get< Sapphire::Data::PublicContent >( contentId );
if( !pPublicContent )
return nullptr;
auto pTeri = getTerritoryDetail( pContentFinderCondition->territoryType );
if( !pTeri || pContentFinderCondition->name.empty() )
return nullptr;
Logger::debug( "Starting instance for PublicContent id: {0} ({1})", contentId, pContentFinderCondition->name );
auto pZone = make_PublicContent( pPublicContent, pContentFinderCondition->territoryType, getNextInstanceId(),
pTeri->name, pContentFinderCondition->name, contentId, contentFinderConditionId );
pZone->init();
m_publicContentIdToInstanceMap[ contentId ][ pZone->getGuId() ] = pZone;
m_guIdToTerritoryPtrMap[ pZone->getGuId() ] = pZone;
m_instanceZoneSet.insert( pZone );
return pZone;
}
Sapphire::TerritoryPtr Sapphire::World::Manager::TerritoryMgr::createPublicContent( uint16_t contentId, uint16_t territoryId )
{
auto& exdData = Common::Service< Data::ExdDataGenerated >::ref();
auto pPublicContent = exdData.get< Sapphire::Data::PublicContent >( contentId );
if( !pPublicContent )
return nullptr;
if( pPublicContent->contentFinderCondition > 0 )
{
Logger::warn( "the public content {} has a ContentFinderCondition value of {}, create the instance using it instead.", contentId, pPublicContent->contentFinderCondition );
return nullptr;
}
auto pTeri = getTerritoryDetail( territoryId );
if( !pTeri )
return nullptr;
Logger::debug( "Starting instance for PublicContent id: {0} ({1})", contentId, pPublicContent->name );
auto pZone = make_PublicContent( pPublicContent, territoryId, getNextInstanceId(), pTeri->name, pPublicContent->name, contentId, 0 );
pZone->init();
m_publicContentIdToInstanceMap[ contentId ][ pZone->getGuId() ] = pZone;
m_guIdToTerritoryPtrMap[ pZone->getGuId() ] = pZone;
m_instanceZoneSet.insert( pZone );
return pZone;
}
Sapphire::TerritoryPtr Sapphire::World::Manager::TerritoryMgr::findOrCreateHousingInterior( const Common::LandIdent landIdent )
{
// check if zone already spawned first
@ -444,11 +507,21 @@ bool Sapphire::World::Manager::TerritoryMgr::removeTerritoryInstance( uint32_t g
m_instanceZoneSet.erase( pZone );
m_territorySet.erase( pZone );
if( isInstanceContentTerritory( pZone->getTerritoryTypeId() ) )
if( pZone->getAsInstanceContent() )
{
auto instance = std::dynamic_pointer_cast< InstanceContent >( pZone );
m_instanceContentIdToInstanceMap[ instance->getInstanceContentId() ].erase( pZone->getGuId() );
}
else if( pZone->getAsPublicContent() )
{
auto instance = std::dynamic_pointer_cast< PublicContent >( pZone );
m_publicContentIdToInstanceMap[ instance->getContentId() ].erase( pZone->getGuId() );
}
else if( pZone->getAsQuestBattle() )
{
auto instance = std::dynamic_pointer_cast< QuestBattle >( pZone );
m_questBattleIdToInstanceMap[ instance->getQuestBattleId() ].erase( pZone->getGuId() );
}
else
m_territoryTypeIdToInstanceGuidMap[ pZone->getTerritoryTypeId() ].erase( pZone->getGuId() );
@ -616,7 +689,7 @@ bool Sapphire::World::Manager::TerritoryMgr::movePlayer( TerritoryPtr pZone, Sap
if( pHousing )
pPlayer->setTerritoryId( pHousing->getLandSetId() );
}
else if( isInstanceContentTerritory( pZone->getTerritoryTypeId() ) )
else if( pZone->getAsInstanceContent() || pZone->getAsQuestBattle() || pZone->getAsPublicContent() )
{
pPlayer->setTerritoryId( pZone->getGuId() );
}

View file

@ -118,6 +118,9 @@ namespace Sapphire::World::Manager
TerritoryPtr createQuestBattle( uint32_t contentFinderConditionId );
TerritoryPtr createPublicContent( uint32_t contentFinderConditionId );
TerritoryPtr createPublicContent( uint16_t contentId, uint16_t territoryId );
void createAndJoinQuestBattle( Entity::Player& player, uint16_t contentFinderConditionId );
TerritoryPtr findOrCreateHousingInterior( const Common::LandIdent landIdent );
@ -179,6 +182,7 @@ namespace Sapphire::World::Manager
using InstanceContentIdToInstanceMap = std::unordered_map< uint16_t, InstanceIdToTerritoryPtrMap >;
using QuestBattleIdToInstanceMap = std::unordered_map< uint16_t, InstanceIdToTerritoryPtrMap >;
using QuestBattleIdToContentFinderCondMap = std::unordered_map< uint16_t, uint16_t >;
using PublicContentIdToInstanceMap = std::unordered_map< uint16_t, InstanceIdToTerritoryPtrMap >;
using PlayerIdToInstanceIdMap = std::unordered_map< uint32_t, uint32_t >;
using PositionMap = std::unordered_map< int32_t, ZonePositionPtr >;
using InstanceIdList = std::vector< uint32_t >;
@ -196,9 +200,12 @@ namespace Sapphire::World::Manager
/*! map holding actual instances of InstanceContent */
InstanceContentIdToInstanceMap m_instanceContentIdToInstanceMap;
/*! map holding actual instances of InstanceContent */
/*! map holding actual instances of QuestBattle */
QuestBattleIdToInstanceMap m_questBattleIdToInstanceMap;
/*! map holding actual instances of PublicContent */
PublicContentIdToInstanceMap m_publicContentIdToInstanceMap;
/*! flat map for easier lookup of instances by guid */
InstanceIdToTerritoryPtrMap m_guIdToTerritoryPtrMap;

View file

@ -106,6 +106,8 @@ Sapphire::Network::GameConnection::GameConnection( Sapphire::Network::HivePtr pH
setZoneHandler( ClientZoneIpcType::TradeReturnEventHandler, "TradeReturnEventHandler",
&GameConnection::eventHandlerReturn );
setZoneHandler( ClientZoneIpcType::TradeReturnEventHandler2, "TradeReturnEventHandler2", &GameConnection::eventHandlerReturn );
setZoneHandler( ClientZoneIpcType::EventYieldHandler, "EventYieldHandler", &GameConnection::eventYieldHandler );
setZoneHandler( ClientZoneIpcType::EventYield16Handler, "EventYield16Handler", &GameConnection::eventYieldHandler );
setZoneHandler( ClientZoneIpcType::ShopEventHandler, "ShopEventHandler",
&GameConnection::eventHandlerShop );

View file

@ -194,6 +194,8 @@ namespace Sapphire::Network
DECLARE_HANDLER( worldInteractionhandler );
DECLARE_HANDLER( diveHandler );
DECLARE_HANDLER( eventYieldHandler );
};
}

View file

@ -103,7 +103,6 @@ void Sapphire::Network::GameConnection::cfDutyAccepted( const Packets::FFXIVARR_
player.prepareZoning( pInstance->getTerritoryTypeId(), true, 1, 0, 0, 1, 9 );
auto sourceZoneGuId = player.getCurrentTerritory()->getGuId();
player.setInstance( instance );
}
}

View file

@ -494,6 +494,11 @@ void Sapphire::Network::GameConnection::clientTriggerHandler( const Packets::FFX
player.sendDebug( "event battle p1: {0}, p11: {1}, p12: {2}, p2: {3}, p3: {4}, p4: {5}, p5: {6}", param1, param11, param12, param2, param3, param4, param5 );
break;
}
case ClientTriggerType::CutscenePlayed:
{
player.sendDebug( "cutscene: {}", param1 );
break;
}
case ClientTriggerType::OpenPerformInstrumentUI:
{
//param11 = instrument, 0 = end

View file

@ -23,6 +23,7 @@
#include "Territory/InstanceContent.h"
#include "Territory/QuestBattle.h"
#include "Territory/PublicContent.h"
#include "Session.h"
@ -59,6 +60,14 @@ void Sapphire::Network::GameConnection::eventHandlerTalk( const Packets::FFXIVAR
{
instance->onTalk( player, eventId, actorId );
}
else if( auto instance = player.getCurrentQuestBattle() )
{
instance->onTalk( player, eventId, actorId );
}
else if( auto instance = player.getCurrentPublicContent() )
{
instance->onTalk( player, eventId, actorId );
}
else if( !scriptMgr.onTalk( player, actorId, eventId ) &&
eventType == Event::EventHandler::EventHandlerType::Quest )
{
@ -180,6 +189,11 @@ void Sapphire::Network::GameConnection::eventHandlerEnterTerritory( const Packet
player.eventStart( player.getId(), eventId, Event::EventHandler::EnterTerritory, 1, player.getZoneId() );
instance->onEnterTerritory( player, eventId, param1, param2 );
}
else if( auto instance = player.getCurrentPublicContent() )
{
player.eventStart( player.getId(), eventId, Event::EventHandler::EnterTerritory, 1, player.getZoneId() );
instance->onEnterTerritory( player, eventId, param1, param2 );
}
else
{
player.eventStart( player.getId(), eventId, Event::EventHandler::EnterTerritory, 0, player.getZoneId() );
@ -273,5 +287,39 @@ void Sapphire::Network::GameConnection::eventHandlerShop( const Packets::FFXIVAR
scriptMgr.onTalk( player, player.getId(), eventId );
}
void Sapphire::Network::GameConnection::eventYieldHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket, Entity::Player& player )
{
auto& scriptMgr = Common::Service< Scripting::ScriptMgr >::ref();
auto& eventMgr = Common::Service< World::Manager::EventMgr >::ref();
auto opcode = *reinterpret_cast< const uint16_t* >( &inPacket.data[ 2 ] );
auto eventId = *reinterpret_cast< const uint32_t* >( &inPacket.data[ 0x10 + 0 ] );
auto scene = *reinterpret_cast< const uint16_t* >( &inPacket.data[ 0x10 + 4 ] );
auto pParam = reinterpret_cast< const uint32_t* >( &inPacket.data[ 0x10 + 8 ] );
std::vector< uint32_t > param;
switch( opcode )
{
case EventYield16Handler:
{
for( int i = 0; i < 16; i++ )
{
param.push_back( pParam[ i ] );
}
break;
}
}
std::string eventName = "onEventYield";
std::string objName = eventMgr.getEventName( eventId );
player.sendDebug( "Calling: {0}.{1} - {2} scene: {3}", objName, eventName, eventId, scene );
scriptMgr.onEventYield( player, eventId, scene, param );
auto response = makeZonePacket< FFXIVIpcEventContinue >( player.getId() );
response->data().eventId = eventId;
response->data().scene = scene;
player.queuePacket( response );
}

View file

@ -387,6 +387,8 @@ void Sapphire::Network::GameConnection::pingHandler( const Packets::FFXIVARR_PAC
void Sapphire::Network::GameConnection::finishLoadingHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket,
Entity::Player& player )
{
if( player.isLogin() )
{
player.sendQuestInfo();
// TODO: load and save this data instead of hardcoding
@ -396,6 +398,7 @@ void Sapphire::Network::GameConnection::finishLoadingHandler( const Packets::FFX
gcPacket->data().gcRank[ 1 ] = player.getGcRankArray()[ 1 ];
gcPacket->data().gcRank[ 2 ] = player.getGcRankArray()[ 2 ];
player.queuePacket( gcPacket );
}
player.getCurrentTerritory()->onFinishLoading( player );

View file

@ -22,15 +22,15 @@ namespace Sapphire::Network::Packets::Server
uint32_t param3 = 0,
uint32_t param4 = 0,
uint32_t param5 = 0,
uint32_t padding1 = 0 ) :
uint32_t param6 = 0 ) :
ZoneChannelPacket< FFXIVIpcActorControlSelf >( actorId, actorId )
{
initialize( category, param1, param2, param3, param4, param5 );
initialize( category, param1, param2, param3, param4, param5, param6 );
};
private:
void initialize( uint16_t category, uint32_t param1, uint32_t param2, uint32_t param3, uint32_t param4,
uint32_t param5 )
uint32_t param5, uint32_t param6 )
{
m_data.padding = 0;
m_data.category = category;
@ -39,6 +39,7 @@ namespace Sapphire::Network::Packets::Server
m_data.param3 = param3;
m_data.param4 = param4;
m_data.param5 = param5;
m_data.param6 = param6;
};
};

View file

@ -8,6 +8,8 @@
#include "Forwards.h"
#include "Inventory/Item.h"
#include "StatusEffect/StatusEffect.h"
#include "Territory/Territory.h"
#include "Event/Director.h"
namespace Sapphire::Network::Packets::Server
{
@ -143,6 +145,10 @@ namespace Sapphire::Network::Packets::Server
m_data.effect[ effect.first ].param = effect.second->getParam();
}
if( auto d = player.getCurrentTerritory()->getAsDirector() )
{
m_data.directorId = d->getDirectorId();
}
};
};

View file

@ -134,6 +134,10 @@ namespace Sapphire::ScriptAPI
{
}
void EventScript::onEventYield( Sapphire::Entity::Player& player, uint16_t scene, std::vector< uint32_t > param )
{
}
///////////////////////////////////////////////////////////////////
EventObjectScript::EventObjectScript( uint32_t eobjId ) :
@ -216,5 +220,31 @@ namespace Sapphire::ScriptAPI
{
}
PublicContentScript::PublicContentScript( uint32_t contentId ) :
ScriptObject( uint32_t{ 0x8004 } << 16 | contentId, typeid( PublicContentScript ).hash_code() )
{
}
void PublicContentScript::onInit( PublicContent& instance )
{
}
void PublicContentScript::onUpdate( PublicContent& instance, uint64_t tickCount )
{
}
void PublicContentScript::onPlayerZoneIn( PublicContent& instance, Entity::Player& player )
{
}
void PublicContentScript::onLeaveTerritory( PublicContent& instance, Entity::Player& player )
{
}
void PublicContentScript::onEnterTerritory( PublicContent& instance, Entity::Player& player, uint32_t eventId,
uint16_t param1, uint16_t param2 )
{
}
}

View file

@ -166,6 +166,8 @@ namespace Sapphire::ScriptAPI
uint32_t catalogId );
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 );
};
/*!
@ -237,6 +239,23 @@ namespace Sapphire::ScriptAPI
uint16_t param1, uint16_t param2 );
};
class PublicContentScript : public ScriptObject
{
public:
explicit PublicContentScript( uint32_t contentId );
virtual void onInit( Sapphire::PublicContent& instance );
virtual void onUpdate( Sapphire::PublicContent& instance, uint64_t tickCount );
virtual void onPlayerZoneIn( Sapphire::PublicContent& instance, Sapphire::Entity::Player& player );
virtual void onLeaveTerritory( Sapphire::PublicContent& instance, Sapphire::Entity::Player& player );
virtual void onEnterTerritory( Sapphire::PublicContent& instance, Sapphire::Entity::Player& player, uint32_t eventId,
uint16_t param1, uint16_t param2 );
};
}
#endif

View file

@ -7,6 +7,7 @@
#include "Territory/Territory.h"
#include "Territory/InstanceContent.h"
#include "Territory/QuestBattle.h"
#include "Territory/PublicContent.h"
#include "Actor/Player.h"
#include "Actor/EventObject.h"
#include "ServerMgr.h"
@ -530,8 +531,7 @@ Sapphire::Scripting::NativeScriptMgr& Sapphire::Scripting::ScriptMgr::getNativeS
return *m_nativeScriptMgr;
}
bool
Sapphire::Scripting::ScriptMgr::onDutyComplete( Sapphire::QuestBattlePtr instance, Sapphire::Entity::Player& player )
bool Sapphire::Scripting::ScriptMgr::onDutyComplete( Sapphire::QuestBattlePtr instance, Sapphire::Entity::Player& player )
{
auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::QuestBattleScript >( instance->getDirectorId() );
if( script )
@ -542,3 +542,77 @@ Sapphire::Scripting::ScriptMgr::onDutyComplete( Sapphire::QuestBattlePtr instanc
return false;
}
bool Sapphire::Scripting::ScriptMgr::onEventYield( Sapphire::Entity::Player& player, uint32_t eventId, uint16_t scene, std::vector< uint32_t > param )
{
auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::EventScript >( eventId );
if( script )
{
script->onEventYield( player, scene, param );
return true;
}
return false;
}
bool Sapphire::Scripting::ScriptMgr::onPublicContentInit( PublicContentPtr instance )
{
auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::PublicContentScript >( instance->getDirectorId() );
if( script )
{
script->onInit( *instance );
return true;
}
return false;
}
bool Sapphire::Scripting::ScriptMgr::onPublicContentUpdate( PublicContentPtr instance, uint64_t tickCount )
{
auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::PublicContentScript >( instance->getDirectorId() );
if( script )
{
script->onUpdate( *instance, tickCount );
return true;
}
return false;
}
bool Sapphire::Scripting::ScriptMgr::onPublicContentPlayerZoneIn( PublicContentPtr instance, Entity::Player& player )
{
auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::PublicContentScript >( instance->getDirectorId() );
if( script )
{
script->onPlayerZoneIn( *instance, player );
return true;
}
return false;
}
bool Sapphire::Scripting::ScriptMgr::onPublicContentLeaveTerritory( PublicContentPtr instance, Entity::Player& player )
{
auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::PublicContentScript >( instance->getDirectorId() );
if( script )
{
script->onLeaveTerritory( *instance, player );
return true;
}
return false;
}
bool Sapphire::Scripting::ScriptMgr::onPublicContentEnterTerritory( PublicContentPtr instance, Entity::Player& player,
uint32_t eventId, uint16_t param1, uint16_t param2 )
{
auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::PublicContentScript >( instance->getDirectorId() );
if( script )
{
script->onEnterTerritory( *instance, player, eventId, param1, param2 );
return true;
}
return false;
}

View file

@ -112,6 +112,18 @@ namespace Sapphire::Scripting
bool onDutyComplete( QuestBattlePtr instance, Entity::Player& player );
bool onEventYield( Entity::Player& player, uint32_t eventId, uint16_t scene, std::vector< uint32_t > param );
bool onPublicContentInit( PublicContentPtr instance );
bool onPublicContentUpdate( PublicContentPtr instance, uint64_t tickCount );
bool onPublicContentPlayerZoneIn( PublicContentPtr instance, Entity::Player& player );
bool onPublicContentLeaveTerritory( PublicContentPtr instance, Entity::Player& player );
bool onPublicContentEnterTerritory( PublicContentPtr instance, Entity::Player& player, uint32_t eventId, uint16_t param1, uint16_t param2 );
bool loadDir( const std::string& dirname, std::set< std::string >& files, const std::string& ext );
NativeScriptMgr& getNativeScriptHandler();

View file

@ -32,9 +32,9 @@ Sapphire::InstanceContent::InstanceContent( std::shared_ptr< Sapphire::Data::Ins
uint32_t guId,
const std::string& internalName,
const std::string& contentName,
uint32_t instanceContentId ) :
uint32_t instanceContentId, uint16_t contentFinderConditionId ) :
Territory( static_cast< uint16_t >( territoryType ), guId, internalName, contentName ),
Director( Event::Director::InstanceContent, instanceContentId ),
Director( Event::Director::InstanceContent, instanceContentId, contentFinderConditionId ),
m_instanceConfiguration( pInstanceConfiguration ),
m_instanceContentId( instanceContentId ),
m_state( Created ),
@ -310,6 +310,8 @@ void Sapphire::InstanceContent::onRegisterEObj( Entity::EventObjectPtr object )
m_eventObjectMap[ object->getName() ] = object;
if( object->getObjectId() == 2000182 ) // start
m_pEntranceEObj = object;
if( m_pEntranceEObj == nullptr && object->getName() == "Entrance" )
m_pEntranceEObj = object;
auto& exdData = Common::Service< Data::ExdDataGenerated >::ref();
auto objData = exdData.get< Sapphire::Data::EObj >( object->getObjectId() );
@ -375,7 +377,7 @@ void Sapphire::InstanceContent::onTalk( Sapphire::Entity::Player& player, uint32
return;
if( auto onTalk = it->second->getOnTalkHandler() )
onTalk( player, it->second, getAsInstanceContent(), actorId );
onTalk( player, it->second, getAsInstanceContent(), eventId, actorId );
else
player.sendDebug( "No onTalk handler found for interactable eobj with EObjID#{0}, eventId#{1} ",
it->second->getObjectId(), eventId );

View file

@ -28,7 +28,7 @@ namespace Sapphire
uint32_t guId,
const std::string& internalName,
const std::string& contentName,
uint32_t instanceContentId );
uint32_t instanceContentId, uint16_t contentFinderConditionId = 0 );
virtual ~InstanceContent();

View file

@ -0,0 +1,271 @@
#include <Common.h>
#include <Logging/Logger.h>
#include <Util/Util.h>
#include <Util/UtilMath.h>
#include <Exd/ExdDataGenerated.h>
#include <Network/CommonActorControl.h>
#include <Service.h>
#include "Actor/Player.h"
#include "Actor/EventObject.h"
#include "Event/Director.h"
#include "Event/EventDefs.h"
#include "Event/EventHandler.h"
#include "Script/ScriptMgr.h"
#include "Network/PacketWrappers/ActorControlPacket.h"
#include "Network/PacketWrappers/ActorControlSelfPacket.h"
#include "PublicContent.h"
using namespace Sapphire::Common;
using namespace Sapphire::Network::Packets;
using namespace Sapphire::Network::Packets::Server;
using namespace Sapphire::Network::ActorControl;
Sapphire::PublicContent::PublicContent( std::shared_ptr< Sapphire::Data::PublicContent > pConfiguration,
uint16_t territoryType,
uint32_t guId,
const std::string& internalName,
const std::string& contentName,
uint32_t contentId, uint16_t contentFinderConditionId ) :
Territory( static_cast< uint16_t >( territoryType ), guId, internalName, contentName ),
Director( Event::Director::PublicContent, contentId, contentFinderConditionId ),
m_Configuration( pConfiguration ),
m_ContentId( contentId )
{
}
bool Sapphire::PublicContent::init()
{
if( !Territory::init() )
return false;
auto& scriptMgr = Common::Service< Scripting::ScriptMgr >::ref();
scriptMgr.onPublicContentInit( getAsPublicContent() );
return true;
}
Sapphire::PublicContent::~PublicContent()
{
}
uint32_t Sapphire::PublicContent::getContentId() const
{
return m_ContentId;
}
Sapphire::Data::ExdDataGenerated::PublicContentPtr Sapphire::PublicContent::getConfiguration() const
{
return m_Configuration;
}
void Sapphire::PublicContent::onPlayerZoneIn( Entity::Player& player )
{
Logger::debug( "PublicContent::onPlayerZoneIn: Territory#{0}|{1}, Entity#{2}", getGuId(), getTerritoryTypeId(), player.getId() );
sendDirectorInit( player );
auto& scriptMgr = Common::Service< Scripting::ScriptMgr >::ref();
scriptMgr.onPublicContentPlayerZoneIn( getAsPublicContent(), player );
}
void Sapphire::PublicContent::onLeaveTerritory( Entity::Player& player )
{
Logger::debug( "PublicContent::onLeaveTerritory: Territory#{0}|{1}, Entity#{2}", getGuId(), getTerritoryTypeId(), player.getId() );
clearDirector( player );
auto& scriptMgr = Common::Service< Scripting::ScriptMgr >::ref();
scriptMgr.onPublicContentLeaveTerritory( getAsPublicContent(), player );
}
void Sapphire::PublicContent::onUpdate( uint64_t tickCount )
{
updateBNpcs( tickCount );
auto& scriptMgr = Common::Service< Scripting::ScriptMgr >::ref();
scriptMgr.onPublicContentUpdate( getAsPublicContent(), tickCount );
}
void Sapphire::PublicContent::onFinishLoading( Entity::Player& player )
{
sendDirectorInit( player );
}
void Sapphire::PublicContent::onInitDirector( Entity::Player& player )
{
sendDirectorVars( player );
player.setDirectorInitialized( true );
}
void Sapphire::PublicContent::onDirectorSync( Entity::Player& player )
{
player.queuePacket( makeActorControlSelf( player.getId(), DirectorUpdate, 0x00110001, 0x80000000, 1 ) );
}
void Sapphire::PublicContent::onBeforePlayerZoneIn( Sapphire::Entity::Player& player )
{
/*if( m_pEntranceEObj != nullptr )
{
player.setRot( PI );
player.setPos( m_pEntranceEObj->getPos() );
}
else
{
player.setRot( PI );
player.setPos( { 0.f, 0.f, 0.f } );
}*/
player.resetObjSpawnIndex();
}
void Sapphire::PublicContent::onEnterTerritory( Entity::Player& player, uint32_t eventId, uint16_t param1, uint16_t param2 )
{
auto& scriptMgr = Common::Service< Scripting::ScriptMgr >::ref();
scriptMgr.onPublicContentEnterTerritory( getAsPublicContent(), player, eventId, param1, param2 );
}
void Sapphire::PublicContent::onRegisterEObj( Entity::EventObjectPtr object )
{
if( object->getName() != "none" )
m_eventObjectMap[ object->getName() ] = object;
if( object->getObjectId() == 2000182 ) // start
m_pEntranceEObj = object;
if( m_pEntranceEObj == nullptr && object->getName() == "Entrance" )
m_pEntranceEObj = object;
auto& exdData = Common::Service< Data::ExdDataGenerated >::ref();
auto objData = exdData.get< Sapphire::Data::EObj >( object->getObjectId() );
if( objData )
m_eventIdToObjectMap[ objData->data ] = object;
else
Logger::error( "PublicContent::onRegisterEObj Territory " +
m_internalName + ": No EObj data found for EObj with ID: " +
std::to_string( object->getObjectId() ) );
}
Sapphire::Entity::EventObjectPtr Sapphire::PublicContent::getEObjByName( const std::string& name )
{
auto it = m_eventObjectMap.find( name );
if( it == m_eventObjectMap.end() )
return nullptr;
return it->second;
}
void Sapphire::PublicContent::clearDirector( Entity::Player& player )
{
sendDirectorClear( player );
player.setDirectorInitialized( false );
}
void Sapphire::PublicContent::onTalk( Sapphire::Entity::Player& player, uint32_t eventId, uint64_t actorId )
{
auto it = m_eventIdToObjectMap.find( eventId );
if( it == m_eventIdToObjectMap.end() )
return;
if( auto onTalk = it->second->getOnTalkHandler() )
onTalk( player, it->second, getAsPublicContent(), eventId, actorId );
else
player.sendDebug( "No onTalk handler found for interactable eobj with EObjID#{0}, eventId#{1} ",
it->second->getObjectId(), eventId );
}
void Sapphire::PublicContent::setVar( uint8_t index, uint8_t value )
{
if( index > 19 )
return;
switch( index )
{
case 0:
setDirectorUI8AL( value );
break;
case 1:
setDirectorUI8AH( value );
break;
case 2:
setDirectorUI8BL( value );
break;
case 3:
setDirectorUI8BH( value );
break;
case 4:
setDirectorUI8CL( value );
break;
case 5:
setDirectorUI8CH( value );
break;
case 6:
setDirectorUI8DL( value );
break;
case 7:
setDirectorUI8DH( value );
break;
case 8:
setDirectorUI8EL( value );
break;
case 9:
setDirectorUI8EH( value );
break;
case 10:
setDirectorUI8FL( value );
break;
case 11:
setDirectorUI8FH( value );
break;
case 12:
setDirectorUI8GL( value );
break;
case 13:
setDirectorUI8GH( value );
break;
case 14:
setDirectorUI8HL( value );
break;
case 15:
setDirectorUI8HH( value );
break;
case 16:
setDirectorUI8IL( value );
break;
case 17:
setDirectorUI8IH( value );
break;
case 18:
setDirectorUI8JL( value );
break;
case 19:
setDirectorUI8JH( value );
break;
}
// todo: genericise this?
for( const auto& playerIt : m_playerMap )
{
sendDirectorVars( *playerIt.second );
}
}
void Sapphire::PublicContent::setSequence( uint8_t value )
{
setDirectorSequence( value );
for( const auto& playerIt : m_playerMap )
{
sendDirectorVars( *playerIt.second );
}
}
void Sapphire::PublicContent::setBranch( uint8_t value )
{
setDirectorBranch( value );
for( const auto& playerIt : m_playerMap )
{
sendDirectorVars( *playerIt.second );
}
}

View file

@ -0,0 +1,72 @@
#ifndef SAPPHIRE_PUBLICCONTENT_H
#define SAPPHIRE_PUBLICCONTENT_H
#include "Territory.h"
#include "Event/Director.h"
#include "Forwards.h"
namespace Sapphire::Data
{
struct PublicContent;
}
namespace Sapphire
{
class PublicContent : public Event::Director, public Territory
{
public:
PublicContent( std::shared_ptr< Sapphire::Data::PublicContent > pConfiguration,
uint16_t territoryType,
uint32_t guId,
const std::string& internalName,
const std::string& contentName,
uint32_t contentId, uint16_t contentFinderConditionId = 0 );
virtual ~PublicContent();
bool init() override;
void onBeforePlayerZoneIn( Entity::Player& player ) override;
void onPlayerZoneIn( Entity::Player& player ) override;
void onLeaveTerritory( Entity::Player& player ) override;
void onUpdate( uint64_t tickCount ) override;
void onFinishLoading( Entity::Player& player ) override;
void onInitDirector( Entity::Player& player ) override;
void onDirectorSync( Entity::Player& player ) override;
void onEnterTerritory( Entity::Player& player, uint32_t eventId, uint16_t param1, uint16_t param2 ) override;
void onRegisterEObj( Entity::EventObjectPtr object ) override;
std::shared_ptr< Sapphire::Data::PublicContent > getConfiguration() const;
uint32_t getContentId() const;
Entity::EventObjectPtr getEObjByName( const std::string& name );
void clearDirector( Entity::Player& player );
void onTalk( Entity::Player& player, uint32_t eventId, uint64_t actorId );
void setSequence( uint8_t value );
void setBranch( uint8_t value );
void setVar( uint8_t index, uint8_t value );
private:
std::shared_ptr< Sapphire::Data::PublicContent > m_Configuration;
uint32_t m_ContentId;
Entity::EventObjectPtr m_pEntranceEObj;
std::map< std::string, Entity::EventObjectPtr > m_eventObjectMap;
std::unordered_map< uint32_t, Entity::EventObjectPtr > m_eventIdToObjectMap;
};
}
#endif //SAPPHIRE_PUBLICCONTENT_H

View file

@ -34,9 +34,9 @@ Sapphire::QuestBattle::QuestBattle( std::shared_ptr< Sapphire::Data::QuestBattle
uint32_t guId,
const std::string& internalName,
const std::string& contentName,
uint32_t questBattleId ) :
uint32_t questBattleId, uint16_t contentFinderConditionId ) :
Territory( static_cast< uint16_t >( territoryType ), guId, internalName, contentName ),
Director( Event::Director::QuestBattle, questBattleId ),
Director( Event::Director::QuestBattle, questBattleId, contentFinderConditionId ),
m_pBattleDetails( pBattleDetails ),
m_questBattleId( questBattleId ),
m_state( Created ),
@ -330,7 +330,7 @@ void Sapphire::QuestBattle::onTalk( Sapphire::Entity::Player& player, uint32_t e
return;
if( auto onTalkHandler = it->second->getOnTalkHandler() )
onTalkHandler( player, it->second, getAsQuestBattle(), actorId );
onTalkHandler( player, it->second, getAsQuestBattle(), eventId, actorId );
else
player.sendDebug( "No onTalk handler found for interactable eobj with EObjID#{0}, eventId#{1} ",
it->second->getObjectId(), eventId );

View file

@ -20,7 +20,7 @@ namespace Sapphire
uint32_t guId,
const std::string& internalName,
const std::string& contentName,
uint32_t questBattleId );
uint32_t questBattleId, uint16_t contentFinderConditionId = 0 );
virtual ~QuestBattle() = default;

View file

@ -19,6 +19,7 @@
#include "Territory.h"
#include "InstanceContent.h"
#include "QuestBattle.h"
#include "PublicContent.h"
#include "Manager/TerritoryMgr.h"
#include "Navi/NaviProvider.h"
@ -780,6 +781,11 @@ Sapphire::Entity::EventObjectPtr Sapphire::Territory::getEObj( uint32_t objId )
return obj->second;
}
Sapphire::Event::DirectorPtr Sapphire::Territory::getAsDirector()
{
return std::dynamic_pointer_cast< Event::Director, Territory >( shared_from_this() );
}
Sapphire::InstanceContentPtr Sapphire::Territory::getAsInstanceContent()
{
return std::dynamic_pointer_cast< InstanceContent, Territory >( shared_from_this() );
@ -790,6 +796,11 @@ Sapphire::QuestBattlePtr Sapphire::Territory::getAsQuestBattle()
return std::dynamic_pointer_cast< QuestBattle, Territory >( shared_from_this() );
}
Sapphire::PublicContentPtr Sapphire::Territory::getAsPublicContent()
{
return std::dynamic_pointer_cast< PublicContent, Territory >( shared_from_this() );
}
uint32_t Sapphire::Territory::getNextEObjId()
{
return ++m_nextEObjId;
@ -1044,3 +1055,18 @@ void Sapphire::Territory::processEffectResults( uint64_t tickCount )
it = m_effectResults.erase( it );
}
}
Sapphire::Entity::PlayerPtr Sapphire::Territory::getPlayer( uint32_t charId )
{
return m_playerMap[ charId ];
}
void Sapphire::Territory::foreachPlayer( std::function< void( Sapphire::Entity::PlayerPtr player ) > callback )
{
if( !callback )
return;
for( auto entry : m_playerMap )
{
callback( entry.second );
}
}

View file

@ -166,10 +166,14 @@ namespace Sapphire
Entity::EventObjectPtr getEObj( uint32_t objId );
Event::DirectorPtr getAsDirector();
InstanceContentPtr getAsInstanceContent();
QuestBattlePtr getAsQuestBattle();
PublicContentPtr getAsPublicContent();
void updateSpawnPoints();
uint32_t getNextEffectSequence();
@ -179,6 +183,10 @@ namespace Sapphire
void addEffectResult( World::Action::EffectResultPtr result );
void processEffectResults( uint64_t tickCount );
Entity::PlayerPtr getPlayer( uint32_t charId );
void foreachPlayer( std::function< void( Entity::PlayerPtr player ) > callback );
};
}