1
Fork 0
mirror of https://github.com/SapphireServer/Sapphire.git synced 2025-04-27 22:57:45 +00:00
sapphire/src/world/Script/ScriptMgr.cpp

507 lines
15 KiB
C++
Raw Normal View History

2018-03-06 22:22:19 +01:00
#include <Logging/Logger.h>
#include <Exd/ExdDataGenerated.h>
#include <watchdog/Watchdog.h>
2017-08-18 17:29:36 +02:00
#include "Territory/Zone.h"
#include "Territory/InstanceContent.h"
2019-03-31 11:27:11 +02:00
#include "Territory/QuestBattle.h"
#include "Actor/Player.h"
#include "Actor/EventObject.h"
2018-11-20 21:32:13 +01:00
#include "ServerMgr.h"
2018-01-09 23:50:54 +01:00
#include "Event/EventHandler.h"
2019-02-10 23:28:15 +11:00
#include "Action/Action.h"
2018-12-23 03:53:08 +01:00
#include "Manager/EventMgr.h"
#include "StatusEffect/StatusEffect.h"
#include "Network/PacketWrappers/ServerNoticePacket.h"
2017-08-18 17:29:36 +02:00
#include "Script/ScriptMgr.h"
2017-08-18 17:29:36 +02:00
#include "NativeScriptMgr.h"
2018-11-20 21:32:13 +01:00
#include "ServerMgr.h"
#include "Framework.h"
// enable the ambiguity fix for every platform to avoid #define nonsense
#define WIN_AMBIGUITY_FIX
2017-12-14 22:30:06 +11:00
namespace fs = std::experimental::filesystem;
2018-12-23 03:53:08 +01:00
Sapphire::Scripting::ScriptMgr::ScriptMgr( FrameworkPtr pFw ) :
World::Manager::BaseManager( pFw ),
m_firstScriptChangeNotificiation( false )
2017-08-18 17:29:36 +02:00
{
2018-12-23 03:53:08 +01:00
m_nativeScriptMgr = createNativeScriptMgr( pFw );
2017-08-18 17:29:36 +02:00
}
Sapphire::Scripting::ScriptMgr::~ScriptMgr()
2017-08-18 17:29:36 +02:00
{
Watchdog::unwatchAll();
2017-12-14 22:30:06 +11:00
}
2017-08-18 17:29:36 +02:00
void Sapphire::Scripting::ScriptMgr::update()
2017-12-14 22:30:06 +11:00
{
m_nativeScriptMgr->processLoadQueue();
2017-08-18 17:29:36 +02:00
}
bool Sapphire::Scripting::ScriptMgr::init()
{
std::set< std::string > files;
auto pServerMgr = framework()->get< World::ServerMgr >();
auto status = loadDir( pServerMgr->getConfig().scripts.path, files, m_nativeScriptMgr->getModuleExtension() );
if( !status )
{
Logger::error( "ScriptMgr: failed to load modules, the server will not function correctly without scripts loaded." );
return false;
}
uint32_t scriptsFound = 0;
uint32_t scriptsLoaded = 0;
2017-12-14 22:30:06 +11:00
for( auto itr = files.begin(); itr != files.end(); ++itr )
{
auto& path = *itr;
scriptsFound++;
2017-12-14 22:30:06 +11:00
if( m_nativeScriptMgr->loadScript( path ) )
scriptsLoaded++;
}
Logger::info( "ScriptMgr: Loaded {0}/{1} modules", scriptsLoaded, scriptsFound );
2017-12-14 22:30:06 +11:00
watchDirectories();
2017-12-14 22:30:06 +11:00
return true;
}
void Sapphire::Scripting::ScriptMgr::watchDirectories()
2017-12-14 22:30:06 +11:00
{
auto pServerMgr = framework()->get< World::ServerMgr >();
auto shouldWatch = pServerMgr->getConfig().scripts.hotSwap;
if( !shouldWatch )
return;
Watchdog::watchMany( pServerMgr->getConfig().scripts.path + "*" +
m_nativeScriptMgr->getModuleExtension(),
[ this ]( const std::vector< ci::fs::path >& paths )
{
if( !m_firstScriptChangeNotificiation )
{
// for whatever reason, the first time this runs, it detects every file as changed
// so we're always going to ignore the first notification
m_firstScriptChangeNotificiation = true;
return;
}
2018-12-23 03:53:08 +01:00
for( const auto& path : paths )
{
if( m_nativeScriptMgr->isModuleLoaded( path.stem().string() ) )
{
Logger::debug( "Reloading changed script: {0}", path.stem().string() );
m_nativeScriptMgr->queueScriptReload( path.stem().string() );
}
else
{
Logger::debug( "Loading new script: {0}", path.stem().string() );
m_nativeScriptMgr->loadScript( path.string() );
}
}
} );
2017-12-14 22:30:06 +11:00
}
bool Sapphire::Scripting::ScriptMgr::loadDir( const std::string& dirname, std::set< std::string >& files,
2018-12-02 02:01:41 +01:00
const std::string& ext )
2017-08-18 17:29:36 +02:00
{
Logger::info( "ScriptMgr: loading scripts from: {0}", dirname );
if( !fs::exists( dirname ) )
{
2018-12-23 03:53:08 +01:00
Logger::error( "ScriptMgr: scripts directory doesn't exist" );
return false;
}
fs::path targetDir( dirname );
fs::directory_iterator iter( targetDir );
2018-10-25 15:15:27 +02:00
for( const auto& i : iter )
2018-09-26 08:47:22 -04:00
{
2018-10-25 15:15:27 +02:00
if( fs::is_regular_file( i ) && fs::path( i ).extension() == ext )
2018-09-26 08:47:22 -04:00
{
2018-10-26 14:11:02 +02:00
files.insert( fs::path( i ).string() );
2018-09-26 08:47:22 -04:00
}
}
2018-12-23 03:53:08 +01:00
if( !files.empty() )
return true;
else
{
2018-12-23 03:53:08 +01:00
Logger::error( "ScriptMgr: couldn't find any script modules" );
return false;
}
2017-08-18 17:29:36 +02:00
}
void Sapphire::Scripting::ScriptMgr::onPlayerFirstEnterWorld( Entity::Player& player )
2017-08-18 17:29:36 +02:00
{
// try
// {
// std::string test = m_onFirstEnterWorld( player );
// }
// catch( const std::exception &e )
// {
// std::string what = e.what();
// }
2017-08-18 17:29:36 +02:00
}
bool Sapphire::Scripting::ScriptMgr::onTalk( Entity::Player& player, uint64_t actorId, uint32_t eventId )
2017-08-18 17:29:36 +02:00
{
// check if the actor is an eobj and call its script if we have one
auto zone = player.getCurrentZone();
if( auto eobj = zone->getEObj( actorId ) )
{
auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::EventObjectScript >( eobj->getObjectId() );
if( script )
{
script->onTalk( eventId, player, *eobj );
return true;
}
}
// check for a direct eventid match first, otherwise default to base type
auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::EventScript >( eventId );
if( script )
{
script->onTalk( eventId, player, actorId );
return true;
}
else
{
2018-12-02 02:01:41 +01:00
script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::EventScript >( eventId & 0xFFFF0000 );
if( !script )
return false;
script->onTalk( eventId, player, actorId );
return true;
}
2017-08-18 17:29:36 +02:00
}
bool Sapphire::Scripting::ScriptMgr::onEnterTerritory( Entity::Player& player, uint32_t eventId,
2018-12-02 02:01:41 +01:00
uint16_t param1, uint16_t param2 )
2017-08-18 17:29:36 +02:00
{
auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::EventScript >( eventId );
if( !script )
return false;
script->onEnterTerritory( player, eventId, param1, param2 );
return true;
2017-08-18 17:29:36 +02:00
}
bool Sapphire::Scripting::ScriptMgr::onWithinRange( Entity::Player& player, uint32_t eventId, uint32_t param1,
2018-12-02 02:01:41 +01:00
float x, float y, float z )
2017-08-18 17:29:36 +02:00
{
auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::EventScript >( eventId );
if( !script )
return false;
script->onWithinRange( player, eventId, param1, x, y, z );
return true;
2017-08-18 17:29:36 +02:00
}
bool Sapphire::Scripting::ScriptMgr::onOutsideRange( Entity::Player& player, uint32_t eventId, uint32_t param1,
2018-12-02 02:01:41 +01:00
float x, float y, float z )
2017-08-18 17:29:36 +02:00
{
auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::EventScript >( eventId );
if( !script )
return false;
script->onOutsideRange( player, eventId, param1, x, y, z );
return true;
2017-08-18 17:29:36 +02:00
}
bool Sapphire::Scripting::ScriptMgr::onEmote( Entity::Player& player, uint64_t actorId,
2018-12-02 02:01:41 +01:00
uint32_t eventId, uint8_t emoteId )
2017-08-18 17:29:36 +02:00
{
auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::EventScript >( eventId );
if( !script )
return false;
script->onEmote( actorId, eventId, emoteId, player );
return true;
2017-08-18 17:29:36 +02:00
}
bool Sapphire::Scripting::ScriptMgr::onEventHandlerReturn( Entity::Player& player, uint32_t eventId,
2018-12-02 02:01:41 +01:00
uint16_t subEvent, uint16_t param1, uint16_t param2,
uint16_t param3 )
2017-08-18 17:29:36 +02:00
{
return false;
2017-08-18 17:29:36 +02:00
}
bool Sapphire::Scripting::ScriptMgr::onEventHandlerTradeReturn( Entity::Player& player, uint32_t eventId,
2018-12-02 02:01:41 +01:00
uint16_t subEvent, uint16_t param, uint32_t catalogId )
2017-08-18 17:29:36 +02:00
{
auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::EventScript >( eventId );
if( script )
{
script->onEventHandlerTradeReturn( player, eventId, subEvent, param, catalogId );
return true;
}
return false;
2017-08-18 17:29:36 +02:00
}
bool Sapphire::Scripting::ScriptMgr::onEventItem( Entity::Player& player, uint32_t eventItemId,
2018-12-02 02:01:41 +01:00
uint32_t eventId, uint32_t castTime, uint64_t targetId )
2017-08-18 17:29:36 +02:00
{
2018-12-23 03:53:08 +01:00
auto pEventMgr = framework()->get< World::Manager::EventMgr >();
std::string eventName = "onEventItem";
2018-12-23 03:53:08 +01:00
std::string objName = pEventMgr->getEventName( eventId );
2019-01-05 12:32:10 +01:00
player.sendDebug( "Calling: {0}.{1} - {2}", objName, eventName, eventId );
auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::EventScript >( eventId );
if( script )
{
player.eventStart( targetId, eventId, Event::EventHandler::Item, 0, 0 );
script->onEventItem( player, eventItemId, eventId, castTime, targetId );
return true;
}
return false;
2017-08-18 17:29:36 +02:00
}
bool Sapphire::Scripting::ScriptMgr::onBNpcKill( Entity::Player& player, uint16_t nameId )
2017-08-18 17:29:36 +02:00
{
2018-12-23 03:53:08 +01:00
auto pEventMgr = framework()->get< World::Manager::EventMgr >();
2017-08-18 17:29:36 +02:00
// loop through all active quests and try to call available onBNpcKill callbacks
for( size_t i = 0; i < 30; i++ )
{
auto activeQuests = player.getQuestActive( static_cast< uint16_t >( i ) );
if( !activeQuests )
continue;
2017-08-18 17:29:36 +02:00
uint32_t questId = activeQuests->c.questId | Event::EventHandler::EventHandlerType::Quest << 16;
auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::EventScript >( questId );
if( script )
{
std::string objName = pEventMgr->getEventName( questId );
2017-08-18 17:29:36 +02:00
2019-02-03 18:37:58 +11:00
player.sendDebug( "Calling: {0}.onBnpcKill nameId#{1}", objName, nameId );
2017-08-18 17:29:36 +02:00
script->onBNpcKill( nameId, player );
}
}
2017-08-18 17:29:36 +02:00
return true;
2017-08-18 17:29:36 +02:00
}
bool Sapphire::Scripting::ScriptMgr::onEObjHit( Sapphire::Entity::Player& player, uint64_t actorId, uint32_t actionId )
2019-02-10 22:13:47 +11:00
{
auto pEventMgr = framework()->get< World::Manager::EventMgr >();
bool didCallScript = false;
2019-02-10 22:13:47 +11:00
for( size_t i = 0; i < 30; i++ )
{
auto activeQuests = player.getQuestActive( static_cast< uint16_t >( i ) );
if( !activeQuests )
continue;
uint32_t questId = activeQuests->c.questId | Event::EventHandler::EventHandlerType::Quest << 16;
auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::EventScript >( questId );
if( script )
{
didCallScript = true;
2019-02-10 22:13:47 +11:00
std::string objName = pEventMgr->getEventName( questId );
player.sendDebug( "Calling: {0}.onEObjHit actorId#{1}", objName, actorId );
script->onEObjHit( player, actorId, actionId );
2019-02-10 22:13:47 +11:00
}
}
return didCallScript;
2019-02-10 22:13:47 +11:00
}
bool Sapphire::Scripting::ScriptMgr::onExecute( Action::Action& action )
2017-08-18 17:29:36 +02:00
{
auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::ActionScript >( action.getId() );
if( script )
{
script->onExecute( action );
return true;
}
return false;
2019-02-10 23:28:15 +11:00
}
bool Sapphire::Scripting::ScriptMgr::onInterrupt( Action::Action& action )
2019-02-10 23:28:15 +11:00
{
auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::ActionScript >( action.getId() );
2019-02-10 23:28:15 +11:00
if( script )
{
script->onInterrupt( action );
return true;
}
return false;
2019-02-10 23:28:15 +11:00
}
bool Sapphire::Scripting::ScriptMgr::onStart( Action::Action& action )
2019-02-10 23:28:15 +11:00
{
auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::ActionScript >( action.getId() );
2019-02-10 23:28:15 +11:00
if( script )
{
script->onStart( action );
return true;
}
return false;
2017-08-18 17:29:36 +02:00
}
bool Sapphire::Scripting::ScriptMgr::onStatusReceive( Entity::CharaPtr pActor, uint32_t effectId )
2017-08-18 17:29:36 +02:00
{
auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::StatusEffectScript >( effectId );
if( script )
{
if( pActor->isPlayer() )
2019-01-05 12:32:10 +01:00
pActor->getAsPlayer()->sendDebug( "Calling status receive for statusid#{0}", effectId );
2017-08-18 17:29:36 +02:00
script->onApply( *pActor );
return true;
}
2017-08-18 17:29:36 +02:00
return false;
2017-08-18 17:29:36 +02:00
}
bool Sapphire::Scripting::ScriptMgr::onStatusTick( Entity::CharaPtr pChara, Sapphire::StatusEffect::StatusEffect& effect )
2017-08-18 17:29:36 +02:00
{
auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::StatusEffectScript >( effect.getId() );
if( script )
{
if( pChara->isPlayer() )
2019-01-05 12:32:10 +01:00
pChara->getAsPlayer()->sendDebug( "Calling status tick for statusid#{0}", effect.getId() );
2017-08-18 17:29:36 +02:00
script->onTick( *pChara );
return true;
}
2017-08-18 17:29:36 +02:00
return false;
2017-08-18 17:29:36 +02:00
}
bool Sapphire::Scripting::ScriptMgr::onStatusTimeOut( Entity::CharaPtr pChara, uint32_t effectId )
2017-08-18 17:29:36 +02:00
{
auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::StatusEffectScript >( effectId );
if( script )
{
if( pChara->isPlayer() )
2019-01-05 12:32:10 +01:00
pChara->getAsPlayer()->sendDebug( "Calling status timeout for statusid#{0}", effectId );
2017-08-18 17:29:36 +02:00
script->onExpire( *pChara );
return true;
}
2017-08-18 17:29:36 +02:00
return false;
2017-08-18 17:29:36 +02:00
}
bool Sapphire::Scripting::ScriptMgr::onZoneInit( ZonePtr pZone )
2017-08-18 17:29:36 +02:00
{
auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::ZoneScript >( pZone->getTerritoryTypeId() );
if( script )
{
script->onZoneInit();
return true;
}
return false;
2017-08-18 17:29:36 +02:00
}
bool Sapphire::Scripting::ScriptMgr::onInstanceInit( InstanceContentPtr instance )
2018-02-09 02:34:43 +11:00
{
auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::InstanceContentScript >( instance->getDirectorId() );
if( script )
{
script->onInit( *instance );
return true;
}
return false;
2018-02-09 02:34:43 +11:00
}
bool Sapphire::Scripting::ScriptMgr::onInstanceUpdate( InstanceContentPtr instance, uint32_t currTime )
2018-02-09 02:34:43 +11:00
{
auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::InstanceContentScript >( instance->getDirectorId() );
if( script )
{
script->onUpdate( *instance, currTime );
return true;
}
2018-02-09 02:34:43 +11:00
return false;
2018-02-09 02:34:43 +11:00
}
bool Sapphire::Scripting::ScriptMgr::onInstanceEnterTerritory( InstanceContentPtr instance, Entity::Player& player,
2018-12-02 02:01:41 +01:00
uint32_t eventId, uint16_t param1, uint16_t param2 )
2018-03-05 22:10:14 +11:00
{
auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::InstanceContentScript >( instance->getDirectorId() );
if( script )
{
script->onEnterTerritory( *instance, player, eventId, param1, param2 );
return true;
}
return false;
2018-03-05 22:10:14 +11:00
}
2019-03-31 11:27:11 +02:00
bool Sapphire::Scripting::ScriptMgr::onInstanceInit( QuestBattlePtr instance )
{
auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::QuestBattleScript >( instance->getDirectorId() );
if( script )
{
script->onInit( *instance );
return true;
}
return false;
}
bool Sapphire::Scripting::ScriptMgr::onInstanceUpdate( QuestBattlePtr instance, uint32_t currTime )
{
auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::QuestBattleScript >( instance->getDirectorId() );
if( script )
{
script->onUpdate( *instance, currTime );
return true;
}
return false;
}
bool Sapphire::Scripting::ScriptMgr::onInstanceEnterTerritory( QuestBattlePtr instance, Entity::Player& player,
uint32_t eventId, uint16_t param1, uint16_t param2 )
{
auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::QuestBattleScript >( instance->getDirectorId() );
if( script )
{
script->onEnterTerritory( *instance, player, eventId, param1, param2 );
return true;
}
return false;
}
Sapphire::Scripting::NativeScriptMgr& Sapphire::Scripting::ScriptMgr::getNativeScriptHandler()
{
return *m_nativeScriptMgr;
}