mirror of
https://github.com/araxiaonline/TrinityCore.git
synced 2026-06-18 14:10:18 -04:00
Core/Game: Rewrote the ScriptMgr to support script reloading.
* Finally this commit enables dynamic script hotswapping and finished the PR #15671. * Split the storage layout to use optimized storages for database bound and unbound scripts. * Add several unload workers to reload scripts correctly -> Requires further investigation. * Fixes memory leaks in ScriptMgr when dropping invalid scripts. * Fixes VehicleScripts * Makes OutdoorPvP scripts reloadable * Makes InstanceMapScripts reloadable * Makes CommandScripts reloadable
This commit is contained in:
@@ -33,18 +33,19 @@
|
||||
#include "ChatLink.h"
|
||||
#include "Group.h"
|
||||
|
||||
bool ChatHandler::load_command_table = true;
|
||||
// Lazy loading of the command table cache from commands and the
|
||||
// ScriptMgr should be thread safe since the player commands,
|
||||
// cli commands and ScriptMgr updates are all dispatched one after
|
||||
// one inside the world update loop.
|
||||
static Optional<std::vector<ChatCommand>> commandTableCache;
|
||||
|
||||
std::vector<ChatCommand> const& ChatHandler::getCommandTable()
|
||||
{
|
||||
static std::vector<ChatCommand> commandTableCache;
|
||||
|
||||
if (LoadCommandTable())
|
||||
if (!commandTableCache)
|
||||
{
|
||||
SetLoadCommandTable(false);
|
||||
|
||||
std::vector<ChatCommand> cmds = sScriptMgr->GetChatCommands();
|
||||
commandTableCache.swap(cmds);
|
||||
// We need to initialize this at top since SetDataForCommandInTable
|
||||
// calls getCommandTable() recursively.
|
||||
commandTableCache = sScriptMgr->GetChatCommands();
|
||||
|
||||
PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_COMMANDS);
|
||||
PreparedQueryResult result = WorldDatabase.Query(stmt);
|
||||
@@ -55,13 +56,18 @@ std::vector<ChatCommand> const& ChatHandler::getCommandTable()
|
||||
Field* fields = result->Fetch();
|
||||
std::string name = fields[0].GetString();
|
||||
|
||||
SetDataForCommandInTable(commandTableCache, name.c_str(), fields[1].GetUInt16(), fields[2].GetString(), name);
|
||||
SetDataForCommandInTable(*commandTableCache, name.c_str(), fields[1].GetUInt16(), fields[2].GetString(), name);
|
||||
}
|
||||
while (result->NextRow());
|
||||
}
|
||||
}
|
||||
|
||||
return commandTableCache;
|
||||
return *commandTableCache;
|
||||
}
|
||||
|
||||
void ChatHandler::invalidateCommandTable()
|
||||
{
|
||||
commandTableCache.reset();
|
||||
}
|
||||
|
||||
char const* ChatHandler::GetTrinityString(uint32 entry) const
|
||||
|
||||
@@ -89,6 +89,7 @@ class TC_GAME_API ChatHandler
|
||||
bool ParseCommands(const char* text);
|
||||
|
||||
static std::vector<ChatCommand> const& getCommandTable();
|
||||
static void invalidateCommandTable();
|
||||
|
||||
bool isValidChatMessage(const char* msg);
|
||||
void SendGlobalSysMessage(const char *str);
|
||||
@@ -136,8 +137,6 @@ class TC_GAME_API ChatHandler
|
||||
GameObject* GetObjectGlobalyWithGuidOrNearWithDbGuid(ObjectGuid::LowType lowguid, uint32 entry);
|
||||
bool HasSentErrorMessage() const { return sentErrorMessage; }
|
||||
void SetSentErrorMessage(bool val){ sentErrorMessage = val; }
|
||||
static bool LoadCommandTable() { return load_command_table; }
|
||||
static void SetLoadCommandTable(bool val) { load_command_table = val; }
|
||||
|
||||
bool ShowHelpForCommand(std::vector<ChatCommand> const& table, const char* cmd);
|
||||
protected:
|
||||
@@ -150,7 +149,6 @@ class TC_GAME_API ChatHandler
|
||||
WorldSession* m_session; // != NULL for chat command call and NULL for CLI command
|
||||
|
||||
// common global flag
|
||||
static bool load_command_table;
|
||||
bool sentErrorMessage;
|
||||
};
|
||||
|
||||
|
||||
@@ -40,8 +40,6 @@ namespace lfg
|
||||
LFGMgr::LFGMgr(): m_QueueTimer(0), m_lfgProposalId(1),
|
||||
m_options(sWorld->getIntConfig(CONFIG_LFG_OPTIONSMASK))
|
||||
{
|
||||
new LFGPlayerScript();
|
||||
new LFGGroupScript();
|
||||
}
|
||||
|
||||
LFGMgr::~LFGMgr()
|
||||
|
||||
@@ -241,4 +241,10 @@ void LFGGroupScript::OnInviteMember(Group* group, ObjectGuid guid)
|
||||
sLFGMgr->LeaveLfg(leader);
|
||||
}
|
||||
|
||||
void AddSC_LFGScripts()
|
||||
{
|
||||
new LFGPlayerScript();
|
||||
new LFGGroupScript();
|
||||
}
|
||||
|
||||
} // namespace lfg
|
||||
|
||||
@@ -53,4 +53,6 @@ class TC_GAME_API LFGGroupScript : public GroupScript
|
||||
void OnInviteMember(Group* group, ObjectGuid guid) override;
|
||||
};
|
||||
|
||||
/*keep private*/ void AddSC_LFGScripts();
|
||||
|
||||
} // namespace lfg
|
||||
|
||||
@@ -792,6 +792,24 @@ void Creature::DoFleeToGetAssistance()
|
||||
}
|
||||
}
|
||||
|
||||
bool Creature::AIM_Destroy()
|
||||
{
|
||||
if (m_AI_locked)
|
||||
{
|
||||
TC_LOG_DEBUG("scripts", "AIM_Destroy: failed to destroy, locked.");
|
||||
return false;
|
||||
}
|
||||
|
||||
ASSERT(!i_disabledAI,
|
||||
"The disabled AI wasn't cleared!");
|
||||
|
||||
delete i_AI;
|
||||
i_AI = nullptr;
|
||||
|
||||
IsAIEnabled = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Creature::AIM_Initialize(CreatureAI* ai)
|
||||
{
|
||||
// make sure nothing can change the AI during AI update
|
||||
@@ -801,12 +819,12 @@ bool Creature::AIM_Initialize(CreatureAI* ai)
|
||||
return false;
|
||||
}
|
||||
|
||||
UnitAI* oldAI = i_AI;
|
||||
AIM_Destroy();
|
||||
|
||||
Motion_Initialize();
|
||||
|
||||
i_AI = ai ? ai : FactorySelector::selectAI(this);
|
||||
delete oldAI;
|
||||
|
||||
IsAIEnabled = true;
|
||||
i_AI->InitializeAI();
|
||||
// Initialize vehicle
|
||||
|
||||
@@ -519,6 +519,7 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma
|
||||
|
||||
bool IsInEvadeMode() const { return HasUnitState(UNIT_STATE_EVADE); }
|
||||
|
||||
bool AIM_Destroy();
|
||||
bool AIM_Initialize(CreatureAI* ai = NULL);
|
||||
void Motion_Initialize();
|
||||
|
||||
|
||||
@@ -74,9 +74,15 @@ GameObject::~GameObject()
|
||||
// CleanupsBeforeDelete();
|
||||
}
|
||||
|
||||
bool GameObject::AIM_Initialize()
|
||||
void GameObject::AIM_Destroy()
|
||||
{
|
||||
delete m_AI;
|
||||
m_AI = nullptr;
|
||||
}
|
||||
|
||||
bool GameObject::AIM_Initialize()
|
||||
{
|
||||
AIM_Destroy();
|
||||
|
||||
m_AI = FactorySelector::SelectGameObjectAI(this);
|
||||
|
||||
|
||||
@@ -1086,8 +1086,10 @@ class TC_GAME_API GameObject : public WorldObject, public GridObject<GameObject>
|
||||
uint16 GetAIAnimKitId() const override { return _animKitId; }
|
||||
void SetAnimKitId(uint16 animKitId, bool oneshot);
|
||||
|
||||
protected:
|
||||
void AIM_Destroy();
|
||||
bool AIM_Initialize();
|
||||
|
||||
protected:
|
||||
GameObjectModel* CreateModel();
|
||||
void UpdateModel(); // updates model in case displayId were changed
|
||||
uint32 m_spellId;
|
||||
|
||||
@@ -5044,7 +5044,7 @@ void ObjectMgr::LoadSpellScriptNames()
|
||||
}
|
||||
while (spellInfo)
|
||||
{
|
||||
_spellScriptsStore.insert(SpellScriptsContainer::value_type(spellInfo->Id, GetScriptId(scriptName)));
|
||||
_spellScriptsStore.insert(SpellScriptsContainer::value_type(spellInfo->Id, std::make_pair(GetScriptId(scriptName), true)));
|
||||
spellInfo = spellInfo->GetNextRankSpell();
|
||||
}
|
||||
}
|
||||
@@ -5053,7 +5053,7 @@ void ObjectMgr::LoadSpellScriptNames()
|
||||
if (spellInfo->IsRanked())
|
||||
TC_LOG_ERROR("sql.sql", "Scriptname: `%s` spell (Id: %d) is ranked spell. Perhaps not all ranks are assigned to this script.", scriptName.c_str(), spellId);
|
||||
|
||||
_spellScriptsStore.insert(SpellScriptsContainer::value_type(spellInfo->Id, GetScriptId(scriptName)));
|
||||
_spellScriptsStore.insert(SpellScriptsContainer::value_type(spellInfo->Id, std::make_pair(GetScriptId(scriptName), true)));
|
||||
}
|
||||
|
||||
++count;
|
||||
@@ -5075,45 +5075,48 @@ void ObjectMgr::ValidateSpellScripts()
|
||||
|
||||
uint32 count = 0;
|
||||
|
||||
for (SpellScriptsContainer::iterator itr = _spellScriptsStore.begin(); itr != _spellScriptsStore.end();)
|
||||
for (auto spell : _spellScriptsStore)
|
||||
{
|
||||
SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(itr->first);
|
||||
std::vector<std::pair<SpellScriptLoader *, SpellScriptsContainer::iterator> > SpellScriptLoaders;
|
||||
sScriptMgr->CreateSpellScriptLoaders(itr->first, SpellScriptLoaders);
|
||||
itr = _spellScriptsStore.upper_bound(itr->first);
|
||||
SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(spell.first);
|
||||
|
||||
for (std::vector<std::pair<SpellScriptLoader *, SpellScriptsContainer::iterator> >::iterator sitr = SpellScriptLoaders.begin(); sitr != SpellScriptLoaders.end(); ++sitr)
|
||||
auto const bounds = sObjectMgr->GetSpellScriptsBounds(spell.first);
|
||||
|
||||
for (auto itr = bounds.first; itr != bounds.second; ++itr)
|
||||
{
|
||||
SpellScript* spellScript = sitr->first->GetSpellScript();
|
||||
AuraScript* auraScript = sitr->first->GetAuraScript();
|
||||
bool valid = true;
|
||||
if (!spellScript && !auraScript)
|
||||
if (SpellScriptLoader* spellScriptLoader = sScriptMgr->GetSpellScriptLoader(itr->second.first))
|
||||
{
|
||||
TC_LOG_ERROR("scripts", "Functions GetSpellScript() and GetAuraScript() of script `%s` do not return objects - script skipped", GetScriptName(sitr->second->second).c_str());
|
||||
valid = false;
|
||||
}
|
||||
if (spellScript)
|
||||
{
|
||||
spellScript->_Init(&sitr->first->GetName(), spellEntry->Id);
|
||||
spellScript->_Register();
|
||||
if (!spellScript->_Validate(spellEntry))
|
||||
valid = false;
|
||||
delete spellScript;
|
||||
}
|
||||
if (auraScript)
|
||||
{
|
||||
auraScript->_Init(&sitr->first->GetName(), spellEntry->Id);
|
||||
auraScript->_Register();
|
||||
if (!auraScript->_Validate(spellEntry))
|
||||
valid = false;
|
||||
delete auraScript;
|
||||
}
|
||||
if (!valid)
|
||||
{
|
||||
_spellScriptsStore.erase(sitr->second);
|
||||
++count;
|
||||
|
||||
std::unique_ptr<SpellScript> spellScript(spellScriptLoader->GetSpellScript());
|
||||
std::unique_ptr<AuraScript> auraScript(spellScriptLoader->GetAuraScript());
|
||||
|
||||
if (!spellScript && !auraScript)
|
||||
{
|
||||
TC_LOG_ERROR("scripts", "Functions GetSpellScript() and GetAuraScript() of script `%s` do not return objects - script skipped", GetScriptName(itr->second.first).c_str());
|
||||
|
||||
itr->second.second = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (spellScript)
|
||||
{
|
||||
spellScript->_Init(&spellScriptLoader->GetName(), spellEntry->Id);
|
||||
spellScript->_Register();
|
||||
|
||||
if (!spellScript->_Validate(spellEntry))
|
||||
itr->second.second = false;
|
||||
}
|
||||
|
||||
if (auraScript)
|
||||
{
|
||||
auraScript->_Init(&spellScriptLoader->GetName(), spellEntry->Id);
|
||||
auraScript->_Register();
|
||||
|
||||
if (!auraScript->_Validate(spellEntry))
|
||||
itr->second.second = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
++count;
|
||||
}
|
||||
|
||||
TC_LOG_INFO("server.loading", ">> Validated %u scripts in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
@@ -8569,6 +8572,8 @@ void ObjectMgr::LoadScriptNames()
|
||||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
|
||||
// We insert an empty placeholder here so we can use the
|
||||
// script id 0 as dummy for "no script found".
|
||||
_scriptNamesStore.emplace_back("");
|
||||
|
||||
QueryResult result = WorldDatabase.Query(
|
||||
@@ -8610,18 +8615,18 @@ void ObjectMgr::LoadScriptNames()
|
||||
|
||||
std::sort(_scriptNamesStore.begin(), _scriptNamesStore.end());
|
||||
|
||||
#ifdef SCRIPTS
|
||||
for (size_t i = 1; i < _scriptNamesStore.size(); ++i)
|
||||
UnusedScriptNames.push_back(_scriptNamesStore[i]);
|
||||
#endif
|
||||
|
||||
TC_LOG_INFO("server.loading", ">> Loaded " SZFMTD " ScriptNames in %u ms", _scriptNamesStore.size(), GetMSTimeDiffToNow(oldMSTime));
|
||||
}
|
||||
|
||||
ObjectMgr::ScriptNameContainer const& ObjectMgr::GetAllScriptNames() const
|
||||
{
|
||||
return _scriptNamesStore;
|
||||
}
|
||||
|
||||
std::string const& ObjectMgr::GetScriptName(uint32 id) const
|
||||
{
|
||||
static std::string const empty = "";
|
||||
return id < _scriptNamesStore.size() ? _scriptNamesStore[id] : empty;
|
||||
return (id < _scriptNamesStore.size()) ? _scriptNamesStore[id] : empty;
|
||||
}
|
||||
|
||||
uint32 ObjectMgr::GetScriptId(std::string const& name)
|
||||
|
||||
@@ -374,7 +374,7 @@ struct ScriptInfo
|
||||
|
||||
typedef std::multimap<uint32, ScriptInfo> ScriptMap;
|
||||
typedef std::map<uint32, ScriptMap > ScriptMapMap;
|
||||
typedef std::multimap<uint32, uint32> SpellScriptsContainer;
|
||||
typedef std::multimap<uint32 /*spell id*/, std::pair<uint32 /*script id*/, bool /*disabled*/>> SpellScriptsContainer;
|
||||
typedef std::pair<SpellScriptsContainer::iterator, SpellScriptsContainer::iterator> SpellScriptsBounds;
|
||||
TC_GAME_API extern ScriptMapMap sSpellScripts;
|
||||
TC_GAME_API extern ScriptMapMap sEventScripts;
|
||||
@@ -1281,6 +1281,7 @@ class TC_GAME_API ObjectMgr
|
||||
bool IsVendorItemValid(uint32 vendor_entry, uint32 id, int32 maxcount, uint32 ptime, uint32 ExtendedCost, uint8 type, Player* player = NULL, std::set<uint32>* skip_vendors = NULL, uint32 ORnpcflag = 0) const;
|
||||
|
||||
void LoadScriptNames();
|
||||
ScriptNameContainer const& GetAllScriptNames() const;
|
||||
std::string const& GetScriptName(uint32 id) const;
|
||||
uint32 GetScriptId(std::string const& name);
|
||||
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
#include "Pet.h"
|
||||
#include "WorldSession.h"
|
||||
#include "Opcodes.h"
|
||||
#include "ScriptReloadMgr.h"
|
||||
#include "ScriptMgr.h"
|
||||
|
||||
BossBoundaryData::~BossBoundaryData()
|
||||
{
|
||||
@@ -36,6 +38,18 @@ BossBoundaryData::~BossBoundaryData()
|
||||
delete it->Boundary;
|
||||
}
|
||||
|
||||
InstanceScript::InstanceScript(Map* map) : instance(map), completedEncounters(0)
|
||||
{
|
||||
#ifdef TRINITY_API_USE_DYNAMIC_LINKING
|
||||
uint32 scriptId = sObjectMgr->GetInstanceTemplate(map->GetId())->ScriptId;
|
||||
auto const scriptname = sObjectMgr->GetScriptName(scriptId);
|
||||
ASSERT(!scriptname.empty());
|
||||
// Acquire a strong reference from the script module
|
||||
// to keep it loaded until this object is destroyed.
|
||||
module_reference = sScriptMgr->AcquireModuleReferenceOfScriptName(scriptname);
|
||||
#endif // #ifndef TRINITY_API_USE_DYNAMIC_LINKING
|
||||
}
|
||||
|
||||
void InstanceScript::SaveToDB()
|
||||
{
|
||||
std::string data = GetSaveData();
|
||||
|
||||
@@ -37,6 +37,7 @@ class Unit;
|
||||
class Player;
|
||||
class GameObject;
|
||||
class Creature;
|
||||
class ModuleReference;
|
||||
|
||||
enum EncounterFrameType
|
||||
{
|
||||
@@ -141,7 +142,7 @@ typedef std::map<uint32 /*entry*/, uint32 /*type*/> ObjectInfoMap;
|
||||
class TC_GAME_API InstanceScript : public ZoneScript
|
||||
{
|
||||
public:
|
||||
explicit InstanceScript(Map* map) : instance(map), completedEncounters(0) { }
|
||||
explicit InstanceScript(Map* map);
|
||||
|
||||
virtual ~InstanceScript() { }
|
||||
|
||||
@@ -296,6 +297,11 @@ class TC_GAME_API InstanceScript : public ZoneScript
|
||||
ObjectInfoMap _gameObjectInfo;
|
||||
ObjectGuidMap _objectGuids;
|
||||
uint32 completedEncounters; // completed encounter mask, bit indexes are DungeonEncounter.dbc boss numbers, used for packets
|
||||
|
||||
#ifdef TRINITY_API_USE_DYNAMIC_LINKING
|
||||
// Strong reference to the associated script module
|
||||
std::shared_ptr<ModuleReference> module_reference;
|
||||
#endif // #ifndef TRINITY_API_USE_DYNAMIC_LINKING
|
||||
};
|
||||
|
||||
template<class AI, class T>
|
||||
|
||||
@@ -33,8 +33,14 @@ void OutdoorPvPMgr::Die()
|
||||
for (OutdoorPvPSet::iterator itr = m_OutdoorPvPSet.begin(); itr != m_OutdoorPvPSet.end(); ++itr)
|
||||
delete *itr;
|
||||
|
||||
m_OutdoorPvPSet.clear();
|
||||
|
||||
for (OutdoorPvPDataMap::iterator itr = m_OutdoorPvPDatas.begin(); itr != m_OutdoorPvPDatas.end(); ++itr)
|
||||
delete itr->second;
|
||||
|
||||
m_OutdoorPvPDatas.clear();
|
||||
|
||||
m_OutdoorPvPMap.clear();
|
||||
}
|
||||
|
||||
OutdoorPvPMgr* OutdoorPvPMgr::instance()
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -46,6 +46,7 @@ class InstanceMap;
|
||||
class InstanceScript;
|
||||
class Item;
|
||||
class Map;
|
||||
class ModuleReference;
|
||||
class OutdoorPvP;
|
||||
class Player;
|
||||
class Quest;
|
||||
@@ -156,14 +157,8 @@ class TC_GAME_API ScriptObject
|
||||
|
||||
protected:
|
||||
|
||||
ScriptObject(const char* name)
|
||||
: _name(name)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~ScriptObject()
|
||||
{
|
||||
}
|
||||
ScriptObject(const char* name);
|
||||
virtual ~ScriptObject();
|
||||
|
||||
private:
|
||||
|
||||
@@ -337,7 +332,8 @@ class TC_GAME_API WorldMapScript : public ScriptObject, public MapScript<Map>
|
||||
WorldMapScript(const char* name, uint32 mapId);
|
||||
};
|
||||
|
||||
class TC_GAME_API InstanceMapScript : public ScriptObject, public MapScript<InstanceMap>
|
||||
class TC_GAME_API InstanceMapScript
|
||||
: public ScriptObject, public MapScript<InstanceMap>
|
||||
{
|
||||
protected:
|
||||
|
||||
@@ -833,13 +829,6 @@ class TC_GAME_API GroupScript : public ScriptObject
|
||||
virtual void OnDisband(Group* /*group*/) { }
|
||||
};
|
||||
|
||||
|
||||
// namespace
|
||||
// {
|
||||
typedef std::list<std::string> UnusedScriptNamesContainer;
|
||||
TC_GAME_API extern UnusedScriptNamesContainer UnusedScriptNames;
|
||||
// }
|
||||
|
||||
// Manages registration, loading, and execution of scripts.
|
||||
class TC_GAME_API ScriptMgr
|
||||
{
|
||||
@@ -852,14 +841,14 @@ class TC_GAME_API ScriptMgr
|
||||
void FillSpellSummary();
|
||||
void LoadDatabase();
|
||||
|
||||
void IncreaseScriptCount() { ++_scriptCount; }
|
||||
void DecreaseScriptCount() { --_scriptCount; }
|
||||
|
||||
public: /* Initialization */
|
||||
static ScriptMgr* instance();
|
||||
|
||||
void Initialize();
|
||||
|
||||
const char* ScriptsVersion() const { return "Integrated Trinity Scripts"; }
|
||||
|
||||
void IncrementScriptCount() { ++_scriptCount; }
|
||||
uint32 GetScriptCount() const { return _scriptCount; }
|
||||
|
||||
typedef void(*ScriptLoaderCallbackType)();
|
||||
@@ -872,10 +861,25 @@ class TC_GAME_API ScriptMgr
|
||||
}
|
||||
|
||||
public: /* Script contexts */
|
||||
void BeginScriptContext(std::string const& context);
|
||||
void FinishScriptContext();
|
||||
|
||||
/// Set the current script context, which allows the ScriptMgr
|
||||
/// to accept new scripts in this context.
|
||||
/// Requires a SwapScriptContext() call afterwards to load the new scripts.
|
||||
void SetScriptContext(std::string const& context);
|
||||
/// Returns the current script context.
|
||||
std::string const& GetCurrentScriptContext() const { return _currentContext; }
|
||||
/// Releases all scripts associated with the given script context immediately.
|
||||
/// Requires a SwapScriptContext() call afterwards to finish the unloading.
|
||||
void ReleaseScriptContext(std::string const& context);
|
||||
/// Executes all changed introduced by SetScriptContext and ReleaseScriptContext.
|
||||
/// It is possible to combine multiple SetScriptContext and ReleaseScriptContext
|
||||
/// calls for better performance (bulk changes).
|
||||
void SwapScriptContext(bool initialize = false);
|
||||
|
||||
/// Acquires a strong module reference to the module containing the given script name,
|
||||
/// which prevents the shared library which contains the script from unloading.
|
||||
/// The shared library is lazy unloaded as soon as all references to it are released.
|
||||
std::shared_ptr<ModuleReference> AcquireModuleReferenceOfScriptName(
|
||||
std::string const& scriptname) const;
|
||||
|
||||
public: /* Unloading */
|
||||
|
||||
@@ -885,7 +889,7 @@ class TC_GAME_API ScriptMgr
|
||||
|
||||
void CreateSpellScripts(uint32 spellId, std::list<SpellScript*>& scriptVector);
|
||||
void CreateAuraScripts(uint32 spellId, std::list<AuraScript*>& scriptVector);
|
||||
void CreateSpellScriptLoaders(uint32 spellId, std::vector<std::pair<SpellScriptLoader*, std::multimap<uint32, uint32>::iterator> >& scriptVector);
|
||||
SpellScriptLoader* GetSpellScriptLoader(uint32 scriptId);
|
||||
|
||||
public: /* ServerScript */
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
*/
|
||||
|
||||
#include "Spell.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "SpellAuras.h"
|
||||
#include "SpellScript.h"
|
||||
|
||||
@@ -50,6 +51,12 @@ void _SpellScript::_Init(std::string const* scriptname, uint32 spellId)
|
||||
m_currentScriptState = SPELL_SCRIPT_STATE_NONE;
|
||||
m_scriptName = scriptname;
|
||||
m_scriptSpellId = spellId;
|
||||
|
||||
#ifdef TRINITY_API_USE_DYNAMIC_LINKING
|
||||
// Acquire a strong reference to the binary code
|
||||
// to keep it loaded until all spells are destroyed.
|
||||
m_moduleReference = sScriptMgr->AcquireModuleReferenceOfScriptName(*scriptname);
|
||||
#endif // #ifndef TRINITY_API_USE_DYNAMIC_LINKING
|
||||
}
|
||||
|
||||
std::string const* _SpellScript::_GetScriptName() const
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "SharedDefines.h"
|
||||
#include "SpellAuraDefines.h"
|
||||
#include "Spell.h"
|
||||
#include "ScriptReloadMgr.h"
|
||||
#include <stack>
|
||||
|
||||
class Unit;
|
||||
@@ -105,6 +106,16 @@ class TC_GAME_API _SpellScript
|
||||
uint8 m_currentScriptState;
|
||||
std::string const* m_scriptName;
|
||||
uint32 m_scriptSpellId;
|
||||
|
||||
private:
|
||||
|
||||
#ifdef TRINITY_API_USE_DYNAMIC_LINKING
|
||||
|
||||
// Strong reference to keep the binary code loaded
|
||||
std::shared_ptr<ModuleReference> m_moduleReference;
|
||||
|
||||
#endif // #ifndef TRINITY_API_USE_DYNAMIC_LINKING
|
||||
|
||||
public:
|
||||
//
|
||||
// SpellScript/AuraScript interface base
|
||||
|
||||
@@ -1971,7 +1971,6 @@ void World::SetInitialWorldSettings()
|
||||
TC_LOG_INFO("server.loading", "Initializing Scripts...");
|
||||
sScriptMgr->Initialize();
|
||||
sScriptMgr->OnConfigLoad(false); // must be done after the ScriptMgr has been properly initialized
|
||||
sScriptReloadMgr->Initialize();
|
||||
|
||||
TC_LOG_INFO("server.loading", "Validating spell scripts...");
|
||||
sObjectMgr->ValidateSpellScripts();
|
||||
|
||||
@@ -391,7 +391,7 @@ public:
|
||||
|
||||
static bool HandleReloadCommandCommand(ChatHandler* handler, const char* /*args*/)
|
||||
{
|
||||
handler->SetLoadCommandTable(true);
|
||||
ChatHandler::invalidateCommandTable();
|
||||
handler->SendGlobalGMSysMessage("DB table `command` will be reloaded at next chat command use.");
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user