aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sql/base/auth_database.sql6
-rw-r--r--sql/updates/auth/master/2021_10_22_00_auth.sql7
-rw-r--r--sql/updates/world/master/2021_10_21_05_world.sql3
-rw-r--r--src/server/game/AI/CoreAI/AreaTriggerAI.cpp4
-rw-r--r--src/server/game/AI/CoreAI/AreaTriggerAI.h9
-rw-r--r--src/server/game/AI/CoreAI/CombatAI.cpp6
-rw-r--r--src/server/game/AI/CoreAI/CombatAI.h12
-rw-r--r--src/server/game/AI/CoreAI/GameObjectAI.cpp8
-rw-r--r--src/server/game/AI/CoreAI/GameObjectAI.h12
-rw-r--r--src/server/game/AI/CoreAI/GuardAI.cpp4
-rw-r--r--src/server/game/AI/CoreAI/GuardAI.h2
-rw-r--r--src/server/game/AI/CoreAI/PassiveAI.cpp6
-rw-r--r--src/server/game/AI/CoreAI/PassiveAI.h11
-rw-r--r--src/server/game/AI/CoreAI/PetAI.cpp2
-rw-r--r--src/server/game/AI/CoreAI/PetAI.h2
-rw-r--r--src/server/game/AI/CoreAI/ReactorAI.h2
-rw-r--r--src/server/game/AI/CoreAI/TotemAI.cpp2
-rw-r--r--src/server/game/AI/CoreAI/TotemAI.h2
-rw-r--r--src/server/game/AI/CreatureAI.cpp6
-rw-r--r--src/server/game/AI/CreatureAI.h7
-rw-r--r--src/server/game/AI/CreatureAIFactory.h8
-rw-r--r--src/server/game/AI/CreatureAIRegistry.cpp4
-rw-r--r--src/server/game/AI/CreatureAISelector.cpp72
-rw-r--r--src/server/game/AI/CreatureAISelector.h7
-rw-r--r--src/server/game/AI/GameObjectAIFactory.h7
-rw-r--r--src/server/game/AI/ScriptedAI/ScriptedCreature.cpp4
-rw-r--r--src/server/game/AI/ScriptedAI/ScriptedCreature.h1
-rw-r--r--src/server/game/AI/SelectableAI.h13
-rw-r--r--src/server/game/AI/SmartScripts/SmartAI.cpp2
-rw-r--r--src/server/game/AI/SmartScripts/SmartAI.h4
-rw-r--r--src/server/game/Accounts/RBAC.h1
-rw-r--r--src/server/game/Entities/AreaTrigger/AreaTrigger.cpp8
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp5
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp149
-rw-r--r--src/server/game/Globals/ObjectMgr.h27
-rw-r--r--src/server/game/Scripting/ScriptMgr.cpp215
-rw-r--r--src/server/game/Scripting/ScriptMgr.h10
-rw-r--r--src/server/game/World/World.cpp6
-rw-r--r--src/server/scripts/Commands/cs_reload.cpp27
39 files changed, 470 insertions, 213 deletions
diff --git a/sql/base/auth_database.sql b/sql/base/auth_database.sql
index 27a1bac8a77..d4b80f1ee22 100644
--- a/sql/base/auth_database.sql
+++ b/sql/base/auth_database.sql
@@ -2166,7 +2166,8 @@ INSERT INTO `rbac_permissions` VALUES
(871,'Command: debug instancespawn'),
(872,'Command: server debug'),
(873,'Command: reload creature_movement_override'),
-(881,'Command: reload vehicle_template');
+(881,'Command: reload vehicle_template'),
+(882,'Command: reload spell_script_names');
/*!40000 ALTER TABLE `rbac_permissions` ENABLE KEYS */;
UNLOCK TABLES;
@@ -2460,7 +2461,8 @@ INSERT INTO `updates` VALUES
('2021_10_13_00_auth.sql','220E63385CACCBCEC36C57717DE369F2FCABCAAF','ARCHIVED','2021-10-13 21:15:05',0),
('2021_10_15_00_auth.sql','C8AA212AB2BB2DB5B3C2C9622A3874475AEFBD7B','ARCHIVED','2021-10-15 10:11:47',0),
('2021_10_15_01_auth.sql','72A0437F0ADEC59FF9D6839DF845C473F693CA5B','RELEASED','2021-10-16 00:15:25',0),
-('2021_10_16_00_auth.sql','FDC45C7BEFBAFC9BCE6C77377B026A59AE52EE21','RELEASED','2021-10-16 11:24:39',0);
+('2021_10_16_00_auth.sql','FDC45C7BEFBAFC9BCE6C77377B026A59AE52EE21','RELEASED','2021-10-16 11:24:39',0),
+('2021_10_22_00_auth.sql','6F55BAD44B9299BE23F79DB09AA90CB42AA63A00','RELEASED','2021-10-10 17:23:09',0);
/*!40000 ALTER TABLE `updates` ENABLE KEYS */;
UNLOCK TABLES;
diff --git a/sql/updates/auth/master/2021_10_22_00_auth.sql b/sql/updates/auth/master/2021_10_22_00_auth.sql
new file mode 100644
index 00000000000..1bd7830845f
--- /dev/null
+++ b/sql/updates/auth/master/2021_10_22_00_auth.sql
@@ -0,0 +1,7 @@
+DELETE FROM `rbac_permissions` WHERE `id` = 882;
+INSERT INTO `rbac_permissions` (`id`, `name`) VALUES
+(882, 'Command: reload spell_script_names');
+
+DELETE FROM `rbac_linked_permissions` WHERE `linkedId` = 882;
+INSERT INTO `rbac_linked_permissions` (`id`, `linkedId`) VALUES
+(196, 882);
diff --git a/sql/updates/world/master/2021_10_21_05_world.sql b/sql/updates/world/master/2021_10_21_05_world.sql
new file mode 100644
index 00000000000..ed62f4a765d
--- /dev/null
+++ b/sql/updates/world/master/2021_10_21_05_world.sql
@@ -0,0 +1,3 @@
+DELETE FROM `command` WHERE `permission` = 882;
+INSERT INTO `command` (`name`,`permission`,`help`) VALUES
+('reload spell_script_names', 882, 'Syntax: .reload spell_script_names\nReload spell_script_names table.');
diff --git a/src/server/game/AI/CoreAI/AreaTriggerAI.cpp b/src/server/game/AI/CoreAI/AreaTriggerAI.cpp
index 6abe091bd02..73fc3ddcb6c 100644
--- a/src/server/game/AI/CoreAI/AreaTriggerAI.cpp
+++ b/src/server/game/AI/CoreAI/AreaTriggerAI.cpp
@@ -15,10 +15,12 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include "AreaTrigger.h"
#include "AreaTriggerAI.h"
-AreaTriggerAI::AreaTriggerAI(AreaTrigger* a) : at(a)
+AreaTriggerAI::AreaTriggerAI(AreaTrigger* a, uint32 scriptId) : _scriptId(scriptId ? scriptId : a->GetScriptId()), at(a)
{
+ ASSERT(_scriptId, "A AreaTriggerAI was initialized with an invalid scriptId!");
}
AreaTriggerAI::~AreaTriggerAI()
diff --git a/src/server/game/AI/CoreAI/AreaTriggerAI.h b/src/server/game/AI/CoreAI/AreaTriggerAI.h
index c0f33caad86..2153d577107 100644
--- a/src/server/game/AI/CoreAI/AreaTriggerAI.h
+++ b/src/server/game/AI/CoreAI/AreaTriggerAI.h
@@ -25,10 +25,12 @@ class Unit;
class TC_GAME_API AreaTriggerAI
{
+ uint32 _scriptId;
+
protected:
AreaTrigger* const at;
public:
- explicit AreaTriggerAI(AreaTrigger* a);
+ explicit AreaTriggerAI(AreaTrigger* a, uint32 scriptId = {});
virtual ~AreaTriggerAI();
// Called when the AreaTrigger has just been initialized, just before added to map
@@ -54,12 +56,15 @@ class TC_GAME_API AreaTriggerAI
// Called when the AreaTrigger is removed
virtual void OnRemove() { }
+
+ // Gets the id of the AI (script id)
+ uint32 GetId() { return _scriptId; }
};
class NullAreaTriggerAI : public AreaTriggerAI
{
public:
- explicit NullAreaTriggerAI(AreaTrigger* areaTrigger) : AreaTriggerAI(areaTrigger) { }
+ using AreaTriggerAI::AreaTriggerAI;
};
#endif
diff --git a/src/server/game/AI/CoreAI/CombatAI.cpp b/src/server/game/AI/CoreAI/CombatAI.cpp
index 5559408e387..f0696db80f3 100644
--- a/src/server/game/AI/CoreAI/CombatAI.cpp
+++ b/src/server/game/AI/CoreAI/CombatAI.cpp
@@ -188,7 +188,7 @@ void CasterAI::UpdateAI(uint32 diff)
// ArcherAI
//////////////
-ArcherAI::ArcherAI(Creature* c) : CreatureAI(c)
+ArcherAI::ArcherAI(Creature* c, uint32 scriptId) : CreatureAI(c, scriptId)
{
if (!me->m_spells[0])
TC_LOG_ERROR("misc", "ArcherAI set for creature (entry = %u) with spell1=0. AI will do nothing", me->GetEntry());
@@ -237,7 +237,7 @@ void ArcherAI::UpdateAI(uint32 /*diff*/)
// TurretAI
//////////////
-TurretAI::TurretAI(Creature* c) : CreatureAI(c)
+TurretAI::TurretAI(Creature* c, uint32 scriptId) : CreatureAI(c, scriptId)
{
if (!me->m_spells[0])
TC_LOG_ERROR("misc", "TurretAI set for creature (entry = %u) with spell1=0. AI will do nothing", me->GetEntry());
@@ -275,7 +275,7 @@ void TurretAI::UpdateAI(uint32 /*diff*/)
// VehicleAI
//////////////
-VehicleAI::VehicleAI(Creature* creature) : CreatureAI(creature), m_HasConditions(false), m_ConditionsTimer(VEHICLE_CONDITION_CHECK_TIME)
+VehicleAI::VehicleAI(Creature* creature, uint32 scriptId) : CreatureAI(creature, scriptId), m_HasConditions(false), m_ConditionsTimer(VEHICLE_CONDITION_CHECK_TIME)
{
LoadConditions();
m_DoDismiss = false;
diff --git a/src/server/game/AI/CoreAI/CombatAI.h b/src/server/game/AI/CoreAI/CombatAI.h
index 27d80e38280..58a6414b00e 100644
--- a/src/server/game/AI/CoreAI/CombatAI.h
+++ b/src/server/game/AI/CoreAI/CombatAI.h
@@ -25,7 +25,7 @@ class Creature;
class TC_GAME_API AggressorAI : public CreatureAI
{
public:
- explicit AggressorAI(Creature* c) : CreatureAI(c) { }
+ using CreatureAI::CreatureAI;
void UpdateAI(uint32) override;
static int32 Permissible(Creature const* creature);
@@ -36,7 +36,7 @@ typedef std::vector<uint32> SpellVct;
class TC_GAME_API CombatAI : public CreatureAI
{
public:
- explicit CombatAI(Creature* c) : CreatureAI(c) { }
+ using CreatureAI::CreatureAI;
void InitializeAI() override;
void Reset() override;
@@ -55,7 +55,7 @@ class TC_GAME_API CombatAI : public CreatureAI
class TC_GAME_API CasterAI : public CombatAI
{
public:
- explicit CasterAI(Creature* c) : CombatAI(c) { m_attackDist = MELEE_RANGE; }
+ explicit CasterAI(Creature* c, uint32 scriptId = {}) : CombatAI(c, scriptId) { m_attackDist = MELEE_RANGE; }
void InitializeAI() override;
void AttackStart(Unit* victim) override { AttackStartCaster(victim, m_attackDist); }
void UpdateAI(uint32 diff) override;
@@ -67,7 +67,7 @@ class TC_GAME_API CasterAI : public CombatAI
struct TC_GAME_API ArcherAI : public CreatureAI
{
public:
- explicit ArcherAI(Creature* c);
+ explicit ArcherAI(Creature* c, uint32 scriptId = {});
void AttackStart(Unit* who) override;
void UpdateAI(uint32 diff) override;
@@ -80,7 +80,7 @@ struct TC_GAME_API ArcherAI : public CreatureAI
struct TC_GAME_API TurretAI : public CreatureAI
{
public:
- explicit TurretAI(Creature* c);
+ explicit TurretAI(Creature* c, uint32 scriptId = {});
bool CanAIAttack(Unit const* who) const override;
void AttackStart(Unit* who) override;
void UpdateAI(uint32 diff) override;
@@ -97,7 +97,7 @@ struct TC_GAME_API TurretAI : public CreatureAI
struct TC_GAME_API VehicleAI : public CreatureAI
{
public:
- explicit VehicleAI(Creature* creature);
+ explicit VehicleAI(Creature* creature, uint32 scriptId = {});
void UpdateAI(uint32 diff) override;
void MoveInLineOfSight(Unit*) override { }
diff --git a/src/server/game/AI/CoreAI/GameObjectAI.cpp b/src/server/game/AI/CoreAI/GameObjectAI.cpp
index 7ce811275f2..4dca8fbd59d 100644
--- a/src/server/game/AI/CoreAI/GameObjectAI.cpp
+++ b/src/server/game/AI/CoreAI/GameObjectAI.cpp
@@ -19,6 +19,12 @@
#include "CreatureAI.h"
#include "GameObject.h"
#include "QuestDef.h"
+#include "Errors.h"
+
+GameObjectAI::GameObjectAI(GameObject* g, uint32 scriptId) : _scriptId(scriptId ? scriptId : g->GetScriptId()), me(g)
+{
+ ASSERT(_scriptId, "A GameObjectAI was initialized with an invalid scriptId!");
+}
int32 GameObjectAI::Permissible(GameObject const* /*go*/)
{
@@ -30,8 +36,6 @@ Optional<QuestGiverStatus> GameObjectAI::GetDialogStatus(Player* /*player*/)
return {};
}
-NullGameObjectAI::NullGameObjectAI(GameObject* g) : GameObjectAI(g) { }
-
int32 NullGameObjectAI::Permissible(GameObject const* /*go*/)
{
return PERMIT_BASE_IDLE;
diff --git a/src/server/game/AI/CoreAI/GameObjectAI.h b/src/server/game/AI/CoreAI/GameObjectAI.h
index 41c29d93366..a44d8b1f3c6 100644
--- a/src/server/game/AI/CoreAI/GameObjectAI.h
+++ b/src/server/game/AI/CoreAI/GameObjectAI.h
@@ -33,12 +33,20 @@ enum class QuestGiverStatus : uint32;
class TC_GAME_API GameObjectAI
{
+ private:
+ // Script Id
+ uint32 const _scriptId;
+
protected:
GameObject* const me;
+
public:
- explicit GameObjectAI(GameObject* g) : me(g) { }
+ explicit GameObjectAI(GameObject* g, uint32 scriptId = {});
virtual ~GameObjectAI() { }
+ // Gets the id of the AI (script id)
+ uint32 GetId() const { return _scriptId; }
+
virtual void UpdateAI(uint32 /*diff*/) { }
virtual void InitializeAI() { Reset(); }
@@ -99,7 +107,7 @@ class TC_GAME_API GameObjectAI
class TC_GAME_API NullGameObjectAI : public GameObjectAI
{
public:
- explicit NullGameObjectAI(GameObject* g);
+ using GameObjectAI::GameObjectAI;
void UpdateAI(uint32 /*diff*/) override { }
diff --git a/src/server/game/AI/CoreAI/GuardAI.cpp b/src/server/game/AI/CoreAI/GuardAI.cpp
index 2288c06122d..b455fdfab32 100644
--- a/src/server/game/AI/CoreAI/GuardAI.cpp
+++ b/src/server/game/AI/CoreAI/GuardAI.cpp
@@ -22,10 +22,6 @@
#include "MotionMaster.h"
#include "Player.h"
-GuardAI::GuardAI(Creature* creature) : ScriptedAI(creature)
-{
-}
-
int32 GuardAI::Permissible(Creature const* creature)
{
if (creature->IsGuard())
diff --git a/src/server/game/AI/CoreAI/GuardAI.h b/src/server/game/AI/CoreAI/GuardAI.h
index 037094cff4b..5cfc245de61 100644
--- a/src/server/game/AI/CoreAI/GuardAI.h
+++ b/src/server/game/AI/CoreAI/GuardAI.h
@@ -25,7 +25,7 @@ class Creature;
class TC_GAME_API GuardAI : public ScriptedAI
{
public:
- explicit GuardAI(Creature* creature);
+ using ScriptedAI::ScriptedAI;
static int32 Permissible(Creature const* creature);
void UpdateAI(uint32 diff) override;
diff --git a/src/server/game/AI/CoreAI/PassiveAI.cpp b/src/server/game/AI/CoreAI/PassiveAI.cpp
index 61d66422dac..02f54b13cd3 100644
--- a/src/server/game/AI/CoreAI/PassiveAI.cpp
+++ b/src/server/game/AI/CoreAI/PassiveAI.cpp
@@ -18,9 +18,9 @@
#include "PassiveAI.h"
#include "Creature.h"
-PassiveAI::PassiveAI(Creature* c) : CreatureAI(c) { me->SetReactState(REACT_PASSIVE); }
-PossessedAI::PossessedAI(Creature* c) : CreatureAI(c) { me->SetReactState(REACT_PASSIVE); }
-NullCreatureAI::NullCreatureAI(Creature* c) : CreatureAI(c) { me->SetReactState(REACT_PASSIVE); }
+PassiveAI::PassiveAI(Creature* c, uint32 scriptId) : CreatureAI(c, scriptId) { me->SetReactState(REACT_PASSIVE); }
+PossessedAI::PossessedAI(Creature* c, uint32 scriptId) : CreatureAI(c, scriptId) { me->SetReactState(REACT_PASSIVE); }
+NullCreatureAI::NullCreatureAI(Creature* c, uint32 scriptId) : CreatureAI(c, scriptId) { me->SetReactState(REACT_PASSIVE); }
int32 NullCreatureAI::Permissible(Creature const* creature)
{
diff --git a/src/server/game/AI/CoreAI/PassiveAI.h b/src/server/game/AI/CoreAI/PassiveAI.h
index 41d4c2bfb12..9dc33ec02b9 100644
--- a/src/server/game/AI/CoreAI/PassiveAI.h
+++ b/src/server/game/AI/CoreAI/PassiveAI.h
@@ -23,7 +23,7 @@
class TC_GAME_API PassiveAI : public CreatureAI
{
public:
- explicit PassiveAI(Creature* c);
+ explicit PassiveAI(Creature* c, uint32 scriptId = {});
void MoveInLineOfSight(Unit*) override { }
void AttackStart(Unit*) override { }
@@ -35,7 +35,7 @@ class TC_GAME_API PassiveAI : public CreatureAI
class TC_GAME_API PossessedAI : public CreatureAI
{
public:
- explicit PossessedAI(Creature* c);
+ explicit PossessedAI(Creature* c, uint32 scriptId = {});
void MoveInLineOfSight(Unit*) override { }
void AttackStart(Unit* target) override;
@@ -53,7 +53,7 @@ class TC_GAME_API PossessedAI : public CreatureAI
class TC_GAME_API NullCreatureAI : public CreatureAI
{
public:
- explicit NullCreatureAI(Creature* c);
+ explicit NullCreatureAI(Creature* c, uint32 scriptId = {});
void MoveInLineOfSight(Unit*) override { }
void AttackStart(Unit*) override { }
@@ -67,7 +67,7 @@ class TC_GAME_API NullCreatureAI : public CreatureAI
class TC_GAME_API CritterAI : public PassiveAI
{
public:
- explicit CritterAI(Creature* c) : PassiveAI(c) { }
+ using PassiveAI::PassiveAI;
void DamageTaken(Unit* done_by, uint32& /*damage*/) override;
void EnterEvadeMode(EvadeReason why) override;
@@ -78,7 +78,8 @@ class TC_GAME_API CritterAI : public PassiveAI
class TC_GAME_API TriggerAI : public NullCreatureAI
{
public:
- explicit TriggerAI(Creature* c) : NullCreatureAI(c) { }
+ using NullCreatureAI::NullCreatureAI;
+
void IsSummonedBy(Unit* summoner) override;
static int32 Permissible(Creature const* creature);
diff --git a/src/server/game/AI/CoreAI/PetAI.cpp b/src/server/game/AI/CoreAI/PetAI.cpp
index 701bee39d35..de6c5c2308c 100644
--- a/src/server/game/AI/CoreAI/PetAI.cpp
+++ b/src/server/game/AI/CoreAI/PetAI.cpp
@@ -44,7 +44,7 @@ int32 PetAI::Permissible(Creature const* creature)
return PERMIT_BASE_NO;
}
-PetAI::PetAI(Creature* c) : CreatureAI(c), i_tracker(TIME_INTERVAL_LOOK)
+PetAI::PetAI(Creature* c, uint32 scriptId) : CreatureAI(c, scriptId), i_tracker(TIME_INTERVAL_LOOK)
{
if (!me->GetCharmInfo())
throw InvalidAIException("Creature doesn't have a valid charm info");
diff --git a/src/server/game/AI/CoreAI/PetAI.h b/src/server/game/AI/CoreAI/PetAI.h
index e243d06debc..57cbc9ca404 100644
--- a/src/server/game/AI/CoreAI/PetAI.h
+++ b/src/server/game/AI/CoreAI/PetAI.h
@@ -30,7 +30,7 @@ class TC_GAME_API PetAI : public CreatureAI
{
public:
- explicit PetAI(Creature* c);
+ explicit PetAI(Creature* c, uint32 scriptId = {});
void UpdateAI(uint32) override;
static int32 Permissible(Creature const* creature);
diff --git a/src/server/game/AI/CoreAI/ReactorAI.h b/src/server/game/AI/CoreAI/ReactorAI.h
index be76f855781..08e89b10912 100644
--- a/src/server/game/AI/CoreAI/ReactorAI.h
+++ b/src/server/game/AI/CoreAI/ReactorAI.h
@@ -24,7 +24,7 @@ class TC_GAME_API ReactorAI : public CreatureAI
{
public:
- explicit ReactorAI(Creature* c) : CreatureAI(c) { }
+ using CreatureAI::CreatureAI;
void MoveInLineOfSight(Unit*) override { }
void UpdateAI(uint32 diff) override;
diff --git a/src/server/game/AI/CoreAI/TotemAI.cpp b/src/server/game/AI/CoreAI/TotemAI.cpp
index fc499414587..7f36ae8e5bf 100644
--- a/src/server/game/AI/CoreAI/TotemAI.cpp
+++ b/src/server/game/AI/CoreAI/TotemAI.cpp
@@ -32,7 +32,7 @@ int32 TotemAI::Permissible(Creature const* creature)
return PERMIT_BASE_NO;
}
-TotemAI::TotemAI(Creature* c) : CreatureAI(c), i_victimGuid()
+TotemAI::TotemAI(Creature* c, uint32 scriptId) : CreatureAI(c, scriptId), i_victimGuid()
{
ASSERT(c->IsTotem());
}
diff --git a/src/server/game/AI/CoreAI/TotemAI.h b/src/server/game/AI/CoreAI/TotemAI.h
index fd25ca86df6..e4efea9dc7e 100644
--- a/src/server/game/AI/CoreAI/TotemAI.h
+++ b/src/server/game/AI/CoreAI/TotemAI.h
@@ -28,7 +28,7 @@ class TC_GAME_API TotemAI : public CreatureAI
{
public:
- explicit TotemAI(Creature* c);
+ explicit TotemAI(Creature* c, uint32 scriptId = {});
void MoveInLineOfSight(Unit* who) override;
void AttackStart(Unit* victim) override;
diff --git a/src/server/game/AI/CreatureAI.cpp b/src/server/game/AI/CreatureAI.cpp
index e3f3cabb5ef..e6d7dc2d1df 100644
--- a/src/server/game/AI/CreatureAI.cpp
+++ b/src/server/game/AI/CreatureAI.cpp
@@ -21,6 +21,7 @@
#include "Creature.h"
#include "CreatureAIImpl.h"
#include "CreatureTextMgr.h"
+#include "Errors.h"
#include "Language.h"
#include "Log.h"
#include "Map.h"
@@ -48,8 +49,11 @@ AISpellInfoType* GetAISpellInfo(uint32 spellId, Difficulty difficulty)
return Trinity::Containers::MapGetValuePtr(UnitAI::AISpellInfo, { spellId, difficulty });
}
-CreatureAI::CreatureAI(Creature* creature) : UnitAI(creature), me(creature), _boundary(nullptr), _negateBoundary(false), m_MoveInLineOfSight_locked(false)
+CreatureAI::CreatureAI(Creature* creature, uint32 scriptId)
+ : UnitAI(creature), me(creature), _boundary(nullptr),
+ _negateBoundary(false), _scriptId(scriptId ? scriptId : creature->GetScriptId()), m_MoveInLineOfSight_locked(false)
{
+ ASSERT(_scriptId, "A CreatureAI was initialized with an invalid scriptId!");
}
CreatureAI::~CreatureAI()
diff --git a/src/server/game/AI/CreatureAI.h b/src/server/game/AI/CreatureAI.h
index fe557f76529..1c6943a245c 100644
--- a/src/server/game/AI/CreatureAI.h
+++ b/src/server/game/AI/CreatureAI.h
@@ -67,10 +67,13 @@ class TC_GAME_API CreatureAI : public UnitAI
EVADE_REASON_OTHER
};
- explicit CreatureAI(Creature* creature);
+ explicit CreatureAI(Creature* creature, uint32 scriptId = {});
virtual ~CreatureAI();
+ // Gets the id of the AI (script id)
+ uint32 GetId() const { return _scriptId; }
+
void Talk(uint8 id, WorldObject const* whisperTarget = nullptr);
/// == Reactions At =================================
@@ -230,6 +233,8 @@ class TC_GAME_API CreatureAI : public UnitAI
bool _negateBoundary;
private:
+ uint32 const _scriptId;
+
bool m_MoveInLineOfSight_locked;
void _OnOwnerCombatInteraction(Unit* target);
};
diff --git a/src/server/game/AI/CreatureAIFactory.h b/src/server/game/AI/CreatureAIFactory.h
index d8d9c5ea828..3d269416902 100644
--- a/src/server/game/AI/CreatureAIFactory.h
+++ b/src/server/game/AI/CreatureAIFactory.h
@@ -18,6 +18,7 @@
#ifndef TRINITY_CREATUREAIFACTORY_H
#define TRINITY_CREATUREAIFACTORY_H
+#include "ObjectMgr.h"
#include "ObjectRegistry.h"
#include "SelectableAI.h"
@@ -25,13 +26,14 @@ class Creature;
class CreatureAI;
template <class REAL_AI, bool is_db_allowed = true>
-struct CreatureAIFactory : public SelectableAI<Creature, CreatureAI, is_db_allowed>
+struct CreatureAIFactory : public SelectableAI<Creature, CreatureAI>
{
- CreatureAIFactory(std::string const& name) : SelectableAI<Creature, CreatureAI, is_db_allowed>(name) { }
+ CreatureAIFactory(std::string const& name)
+ : SelectableAI<Creature, CreatureAI>(name, sObjectMgr->GetScriptId(name, false), is_db_allowed) { }
inline CreatureAI* Create(Creature* c) const override
{
- return new REAL_AI(c);
+ return new REAL_AI(c, this->GetScriptId());
}
int32 Permit(Creature const* c) const override
diff --git a/src/server/game/AI/CreatureAIRegistry.cpp b/src/server/game/AI/CreatureAIRegistry.cpp
index 2ae35369966..a1a2d3dbdb5 100644
--- a/src/server/game/AI/CreatureAIRegistry.cpp
+++ b/src/server/game/AI/CreatureAIRegistry.cpp
@@ -25,6 +25,7 @@
#include "ReactorAI.h"
#include "SmartAI.h"
#include "TotemAI.h"
+#include "ObjectMgr.h"
#include "MovementGenerator.h"
@@ -37,6 +38,7 @@ namespace AIRegistry
(new CreatureAIFactory<AggressorAI>("AggressorAI"))->RegisterSelf();
(new CreatureAIFactory<ReactorAI>("ReactorAI"))->RegisterSelf();
(new CreatureAIFactory<PassiveAI>("PassiveAI"))->RegisterSelf();
+ (new CreatureAIFactory<PossessedAI, false>("PossessedAI"))->RegisterSelf();
(new CreatureAIFactory<CritterAI>("CritterAI"))->RegisterSelf();
(new CreatureAIFactory<GuardAI>("GuardAI"))->RegisterSelf();
(new CreatureAIFactory<PetAI, false>("PetAI"))->RegisterSelf();
@@ -54,5 +56,7 @@ namespace AIRegistry
(new IdleMovementFactory())->RegisterSelf();
(new RandomMovementFactory())->RegisterSelf();
(new WaypointMovementFactory())->RegisterSelf();
+
+ (void)sObjectMgr->GetScriptId("NullAreaTriggerAI", false);
}
}
diff --git a/src/server/game/AI/CreatureAISelector.cpp b/src/server/game/AI/CreatureAISelector.cpp
index 99eb3b05ff6..2da8ec2631b 100644
--- a/src/server/game/AI/CreatureAISelector.cpp
+++ b/src/server/game/AI/CreatureAISelector.cpp
@@ -16,6 +16,7 @@
*/
#include "AIException.h"
+#include "AreaTrigger.h"
#include "Creature.h"
#include "CreatureAISelector.h"
#include "CreatureAIFactory.h"
@@ -25,6 +26,8 @@
#include "GameObject.h"
#include "GameObjectAIFactory.h"
+#include "AreaTriggerAI.h"
+
#include "ScriptMgr.h"
namespace FactorySelector
@@ -53,7 +56,7 @@ namespace FactorySelector
};
template <class AI, class T>
- inline FactoryHolder<AI, T> const* SelectFactory(T* obj)
+ inline FactoryHolder<AI, T> const* SelectFactory(T const* obj)
{
static_assert(std::is_same<AI, CreatureAI>::value || std::is_same<AI, GameObjectAI>::value, "Invalid template parameter");
static_assert(std::is_same<AI, CreatureAI>::value == std::is_same<T, Creature>::value, "Incompatible AI for type");
@@ -98,6 +101,31 @@ namespace FactorySelector
return SelectFactory<CreatureAI>(creature)->Create(creature);
}
+ uint32 GetSelectedAIId(Creature const* creature)
+ {
+ if (creature->IsPet())
+ {
+ auto const* registry = ASSERT_NOTNULL(sCreatureAIRegistry->GetRegistryItem("PetAI"));
+ auto const* factory = dynamic_cast<SelectableAI<Creature, CreatureAI> const*>(registry);
+ ASSERT(factory);
+
+ return factory->GetScriptId();
+ }
+
+ if (uint32 id = creature->GetScriptId())
+ {
+ if (sScriptMgr->CanCreateCreatureAI(id))
+ {
+ return id;
+ }
+ }
+
+ auto const* factory = dynamic_cast<SelectableAI<Creature, CreatureAI> const*>(SelectFactory<CreatureAI>(creature));
+ ASSERT(factory);
+
+ return factory->GetScriptId();
+ }
+
MovementGenerator* SelectMovementGenerator(Unit* unit)
{
MovementGeneratorType type = unit->GetDefaultMovementType();
@@ -117,4 +145,46 @@ namespace FactorySelector
return SelectFactory<GameObjectAI>(go)->Create(go);
}
+
+ uint32 GetSelectedAIId(GameObject const* go)
+ {
+ if (uint32 id = go->GetScriptId())
+ {
+ if (sScriptMgr->CanCreateGameObjectAI(id))
+ {
+ return id;
+ }
+ }
+
+ auto const* factory = dynamic_cast<SelectableAI<GameObject, GameObjectAI> const*>(SelectFactory<GameObjectAI>(go));
+ ASSERT(factory);
+
+ return factory->GetScriptId();
+ }
+
+ static uint32 GetNullAreaTriggerAIScriptId()
+ {
+ return sObjectMgr->GetScriptId("NullAreaTriggerAI", false);
+ }
+
+ AreaTriggerAI* SelectAreaTriggerAI(AreaTrigger* at)
+ {
+ if (AreaTriggerAI* ai = sScriptMgr->GetAreaTriggerAI(at))
+ return ai;
+ else
+ return new NullAreaTriggerAI(at, GetNullAreaTriggerAIScriptId());
+ }
+
+ uint32 GetSelectedAIId(AreaTrigger const* at)
+ {
+ if (uint32 id = at->GetScriptId())
+ {
+ if (sScriptMgr->CanCreateAreaTriggerAI(id))
+ {
+ return id;
+ }
+ }
+
+ return GetNullAreaTriggerAIScriptId();
+ }
}
diff --git a/src/server/game/AI/CreatureAISelector.h b/src/server/game/AI/CreatureAISelector.h
index b4046a5e982..d8447f6f350 100644
--- a/src/server/game/AI/CreatureAISelector.h
+++ b/src/server/game/AI/CreatureAISelector.h
@@ -24,11 +24,18 @@ class MovementGenerator;
class Unit;
class GameObjectAI;
class GameObject;
+class AreaTriggerAI;
+class AreaTrigger;
namespace FactorySelector
{
TC_GAME_API CreatureAI* SelectAI(Creature* creature);
TC_GAME_API MovementGenerator* SelectMovementGenerator(Unit* unit);
TC_GAME_API GameObjectAI* SelectGameObjectAI(GameObject* go);
+ TC_GAME_API AreaTriggerAI* SelectAreaTriggerAI(AreaTrigger* at);
+
+ TC_GAME_API uint32 GetSelectedAIId(Creature const* creature);
+ TC_GAME_API uint32 GetSelectedAIId(GameObject const* go);
+ TC_GAME_API uint32 GetSelectedAIId(AreaTrigger const* at);
}
#endif
diff --git a/src/server/game/AI/GameObjectAIFactory.h b/src/server/game/AI/GameObjectAIFactory.h
index 99d3214b5de..6a66a59f967 100644
--- a/src/server/game/AI/GameObjectAIFactory.h
+++ b/src/server/game/AI/GameObjectAIFactory.h
@@ -25,13 +25,14 @@ class GameObject;
class GameObjectAI;
template <class REAL_GO_AI, bool is_db_allowed = true>
-struct GameObjectAIFactory : public SelectableAI<GameObject, GameObjectAI, is_db_allowed>
+struct GameObjectAIFactory : public SelectableAI<GameObject, GameObjectAI>
{
- GameObjectAIFactory(std::string const& name) : SelectableAI<GameObject, GameObjectAI, is_db_allowed>(name) { }
+ GameObjectAIFactory(std::string const& name)
+ : SelectableAI<GameObject, GameObjectAI>(name, sObjectMgr->GetScriptId(name, false), is_db_allowed) { }
GameObjectAI* Create(GameObject* go) const override
{
- return new REAL_GO_AI(go);
+ return new REAL_GO_AI(go, GetScriptId());
}
int32 Permit(GameObject const* go) const override
diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp
index 5042dcd6144..7c13e6e26ff 100644
--- a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp
+++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp
@@ -116,7 +116,9 @@ void SummonList::DoActionImpl(int32 action, StorageType const& summons)
}
}
-ScriptedAI::ScriptedAI(Creature* creature) : CreatureAI(creature),
+ScriptedAI::ScriptedAI(Creature* creature) : ScriptedAI(creature, creature->GetScriptId()) { }
+
+ScriptedAI::ScriptedAI(Creature* creature, uint32 scriptId) : CreatureAI(creature, scriptId),
IsFleeing(false),
_isCombatMovementAllowed(true)
{
diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.h b/src/server/game/AI/ScriptedAI/ScriptedCreature.h
index b30bcd6a83b..3dfb133a916 100644
--- a/src/server/game/AI/ScriptedAI/ScriptedCreature.h
+++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.h
@@ -134,6 +134,7 @@ class TC_GAME_API DummyEntryCheckPredicate
struct TC_GAME_API ScriptedAI : public CreatureAI
{
explicit ScriptedAI(Creature* creature);
+ explicit ScriptedAI(Creature* creature, uint32 scriptId);
virtual ~ScriptedAI() { }
// *************
diff --git a/src/server/game/AI/SelectableAI.h b/src/server/game/AI/SelectableAI.h
index 7b28049ffd5..fc6ec88af5c 100644
--- a/src/server/game/AI/SelectableAI.h
+++ b/src/server/game/AI/SelectableAI.h
@@ -27,12 +27,19 @@ class DBPermit
virtual bool IsScriptNameAllowedInDB() const = 0;
};
-template <class O, class AI, bool is_db_allowed = true>
+template <class O, class AI>
struct SelectableAI : public FactoryHolder<AI, O>, public Permissible<O>, public DBPermit
{
- SelectableAI(std::string const& name) : FactoryHolder<AI, O>(name), Permissible<O>(), DBPermit() { }
+ SelectableAI(std::string const& name, uint32 scriptId, bool isDBAllowed)
+ : FactoryHolder<AI, O>(name), Permissible<O>(), DBPermit(), _scriptId(scriptId), _isDBAllowed(isDBAllowed) { }
- bool IsScriptNameAllowedInDB() const final override { return is_db_allowed; }
+ bool IsScriptNameAllowedInDB() const final override { return _isDBAllowed; }
+
+ uint32 GetScriptId() const { return _scriptId; }
+
+private:
+ uint32 _scriptId;
+ bool _isDBAllowed;
};
diff --git a/src/server/game/AI/SmartScripts/SmartAI.cpp b/src/server/game/AI/SmartScripts/SmartAI.cpp
index ca3d95e5aeb..9ab05c55271 100644
--- a/src/server/game/AI/SmartScripts/SmartAI.cpp
+++ b/src/server/game/AI/SmartScripts/SmartAI.cpp
@@ -30,7 +30,7 @@
#include "ScriptMgr.h"
#include "Vehicle.h"
-SmartAI::SmartAI(Creature* creature) : CreatureAI(creature), mIsCharmed(false), mFollowCreditType(0), mFollowArrivedTimer(0), mFollowCredit(0), mFollowArrivedEntry(0), mFollowDist(0.f), mFollowAngle(0.f),
+SmartAI::SmartAI(Creature* creature, uint32 scriptId) : CreatureAI(creature, scriptId), mIsCharmed(false), mFollowCreditType(0), mFollowArrivedTimer(0), mFollowCredit(0), mFollowArrivedEntry(0), mFollowDist(0.f), mFollowAngle(0.f),
_escortState(SMART_ESCORT_NONE), _escortNPCFlags(0), _escortInvokerCheckTimer(1000), _currentWaypointNode(0), _waypointReached(false), _waypointPauseTimer(0), _waypointPauseForced(false), _repeatWaypointPath(false),
_OOCReached(false), _waypointPathEnded(false), mRun(true), mEvadeDisabled(false), mCanAutoAttack(true), mCanCombatMove(true), mInvincibilityHpLevel(0), mDespawnTime(0), mDespawnState(0), mConditionsTimer(0),
_gossipReturn(false), mEscortQuestID(0)
diff --git a/src/server/game/AI/SmartScripts/SmartAI.h b/src/server/game/AI/SmartScripts/SmartAI.h
index f0967af9109..6c40f429c13 100644
--- a/src/server/game/AI/SmartScripts/SmartAI.h
+++ b/src/server/game/AI/SmartScripts/SmartAI.h
@@ -44,7 +44,7 @@ class TC_GAME_API SmartAI : public CreatureAI
{
public:
~SmartAI() { }
- explicit SmartAI(Creature* c);
+ explicit SmartAI(Creature* c, uint32 scriptId = {});
// core related
static int32 Permissible(Creature const* /*creature*/) { return PERMIT_BASE_NO; }
@@ -247,7 +247,7 @@ class TC_GAME_API SmartAI : public CreatureAI
class TC_GAME_API SmartGameObjectAI : public GameObjectAI
{
public:
- SmartGameObjectAI(GameObject* g) : GameObjectAI(g), _gossipReturn(false) { }
+ SmartGameObjectAI(GameObject* g, uint32 scriptId = {}) : GameObjectAI(g, scriptId), _gossipReturn(false) { }
~SmartGameObjectAI() { }
void UpdateAI(uint32 diff) override;
diff --git a/src/server/game/Accounts/RBAC.h b/src/server/game/Accounts/RBAC.h
index aef00f3d236..e01b9034cd8 100644
--- a/src/server/game/Accounts/RBAC.h
+++ b/src/server/game/Accounts/RBAC.h
@@ -786,6 +786,7 @@ enum RBACPermissions
// 878-879 previously used, do not reuse
RBAC_PERM_COMMAND_PDUMP_COPY = 880,
RBAC_PERM_COMMAND_RELOAD_VEHICLE_TEMPLATE = 881,
+ RBAC_PERM_COMMAND_RELOAD_SPELL_SCRIPT_NAMES = 882,
//
// IF YOU ADD NEW PERMISSIONS, ADD THEM IN 3.3.5 BRANCH AS WELL!
//
diff --git a/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp b/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp
index ae69a5ed902..cd4c495b64e 100644
--- a/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp
+++ b/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp
@@ -21,6 +21,7 @@
#include "AreaTriggerPackets.h"
#include "CellImpl.h"
#include "Chat.h"
+#include "CreatureAISelector.h"
#include "DB2Stores.h"
#include "GridNotifiersImpl.h"
#include "Language.h"
@@ -948,11 +949,7 @@ void AreaTrigger::DebugVisualizePosition()
void AreaTrigger::AI_Initialize()
{
AI_Destroy();
- AreaTriggerAI* ai = sScriptMgr->GetAreaTriggerAI(this);
- if (!ai)
- ai = new NullAreaTriggerAI(this);
-
- _ai.reset(ai);
+ _ai.reset(FactorySelector::SelectAreaTriggerAI(this));
_ai->OnInitialize();
}
@@ -961,6 +958,7 @@ void AreaTrigger::AI_Destroy()
_ai.reset();
}
+
void AreaTrigger::BuildValuesCreate(ByteBuffer* data, Player const* target) const
{
UF::UpdateFieldFlag flags = GetUpdateFieldFlagsFor(target);
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index bf2a9a1fc1f..f1c7b99c186 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -34,6 +34,7 @@
#include "Creature.h"
#include "CreatureAI.h"
#include "CreatureAIImpl.h"
+#include "CreatureAIFactory.h"
#include "CreatureGroups.h"
#include "DB2Stores.h"
#include "Formulas.h"
@@ -9181,9 +9182,9 @@ void Unit::UpdateCharmAI()
{
i_disabledAI = i_AI;
if (isPossessed() || IsVehicle())
- i_AI = new PossessedAI(ToCreature());
+ i_AI = ASSERT_NOTNULL(sCreatureAIRegistry->GetRegistryItem("PossessedAI"))->Create(ToCreature());
else
- i_AI = new PetAI(ToCreature());
+ i_AI = ASSERT_NOTNULL(sCreatureAIRegistry->GetRegistryItem("PetAI"))->Create(ToCreature());
}
}
break;
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp
index b033d6b7896..b1bf17ec7d7 100644
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -53,6 +53,7 @@
#include "Random.h"
#include "ReputationMgr.h"
#include "ScriptMgr.h"
+#include "ScriptReloadMgr.h"
#include "SpellInfo.h"
#include "SpellMgr.h"
#include "SpellScript.h"
@@ -64,6 +65,7 @@
#include "World.h"
#include <G3D/g3dmath.h>
#include <numeric>
+#include <limits>
ScriptMapMap sSpellScripts;
ScriptMapMap sEventScripts;
@@ -9492,16 +9494,39 @@ bool ObjectMgr::IsVendorItemValid(uint32 vendor_entry, VendorItem const& vItem,
return true;
}
+ObjectMgr::ScriptNameContainer::ScriptNameContainer()
+{
+ // We insert an empty placeholder here so we can use the
+ // script id 0 as dummy for "no script found".
+ uint32 const id = insert("", false);
+
+ ASSERT(id == 0);
+ (void)id;
+}
+
void ObjectMgr::ScriptNameContainer::reserve(size_t capacity)
{
IndexToName.reserve(capacity);
}
-void ObjectMgr::ScriptNameContainer::insert(std::string&& scriptName)
+uint32 ObjectMgr::ScriptNameContainer::insert(std::string const& scriptName, bool isScriptNameBound)
{
- auto insertResult = NameToIndex.insert({ std::move(scriptName), NameToIndex.size() });
- if (insertResult.second)
- IndexToName.push_back(insertResult.first);
+ // c++17 try_emplace
+ auto const itr = NameToIndex.find(scriptName);
+ if (itr != NameToIndex.end())
+ {
+ return itr->second.Id;
+ }
+ else
+ {
+ ASSERT(NameToIndex.size() < std::numeric_limits<uint32>::max());
+ uint32 const id = static_cast<uint32>(NameToIndex.size());
+
+ auto result = NameToIndex.insert({ scriptName, Entry{ id, isScriptNameBound } });
+ IndexToName.emplace_back(result.first);
+
+ return id;
+ }
}
size_t ObjectMgr::ScriptNameContainer::size() const
@@ -9509,111 +9534,75 @@ size_t ObjectMgr::ScriptNameContainer::size() const
return IndexToName.size();
}
-std::string const& ObjectMgr::ScriptNameContainer::operator[](size_t index) const
+ObjectMgr::ScriptNameContainer::NameMap::const_iterator ObjectMgr::ScriptNameContainer::find(size_t index) const
{
- static std::string const empty;
- return index < IndexToName.size() ? IndexToName[index]->first : empty;
+ return index < IndexToName.size() ? IndexToName[index] : end();
}
-uint32 ObjectMgr::ScriptNameContainer::operator[](std::string const& name) const
+ObjectMgr::ScriptNameContainer::NameMap::const_iterator ObjectMgr::ScriptNameContainer::find(std::string const& name) const
{
// assume "" is the first element
if (name.empty())
- return 0;
+ return end();
- if (uint32 const* id = Trinity::Containers::MapGetValuePtr(NameToIndex, name))
- return *id;
+ return NameToIndex.find(name);
+}
- return 0;
+ObjectMgr::ScriptNameContainer::NameMap::const_iterator ObjectMgr::ScriptNameContainer::end() const
+{
+ return NameToIndex.end();
}
-std::unordered_set<std::string> ObjectMgr::ScriptNameContainer::GetAllScriptNames() const
+std::unordered_set<std::string> ObjectMgr::ScriptNameContainer::GetAllDBScriptNames() const
{
std::unordered_set<std::string> scriptNames;
- std::transform(NameToIndex.begin(), NameToIndex.end(), std::inserter(scriptNames, scriptNames.end()),
- [](std::pair<std::string const, uint32> const& pair)
+
+ for (std::pair<std::string const, Entry> const& entry : NameToIndex)
{
- return pair.first;
- });
+ if (entry.second.IsScriptDatabaseBound)
+ {
+ scriptNames.insert(entry.first);
+ }
+ }
return scriptNames;
}
-void ObjectMgr::LoadScriptNames()
+std::unordered_set<std::string> ObjectMgr::GetAllDBScriptNames() const
{
- uint32 oldMSTime = getMSTime();
-
- // We insert an empty placeholder here so we can use the
- // script id 0 as dummy for "no script found".
- _scriptNamesStore.insert("");
-
- QueryResult result = WorldDatabase.Query(
- "SELECT DISTINCT(ScriptName) FROM battleground_template WHERE ScriptName <> '' "
- "UNION "
- "SELECT DISTINCT(ScriptName) FROM conversation_template WHERE ScriptName <> '' "
- "UNION "
- "SELECT DISTINCT(ScriptName) FROM creature WHERE ScriptName <> '' "
- "UNION "
- "SELECT DISTINCT(ScriptName) FROM creature_template WHERE ScriptName <> '' "
- "UNION "
- "SELECT DISTINCT(ScriptName) FROM criteria_data WHERE ScriptName <> '' AND type = 11 "
- "UNION "
- "SELECT DISTINCT(ScriptName) FROM gameobject WHERE ScriptName <> '' "
- "UNION "
- "SELECT DISTINCT(ScriptName) FROM gameobject_template WHERE ScriptName <> '' "
- "UNION "
- "SELECT DISTINCT(ScriptName) FROM item_script_names WHERE ScriptName <> '' "
- "UNION "
- "SELECT DISTINCT(ScriptName) FROM areatrigger_scripts WHERE ScriptName <> '' "
- "UNION "
- "SELECT DISTINCT(ScriptName) FROM areatrigger_template WHERE ScriptName <> '' "
- "UNION "
- "SELECT DISTINCT(ScriptName) FROM spell_script_names WHERE ScriptName <> '' "
- "UNION "
- "SELECT DISTINCT(ScriptName) FROM transports WHERE ScriptName <> '' "
- "UNION "
- "SELECT DISTINCT(ScriptName) FROM game_weather WHERE ScriptName <> '' "
- "UNION "
- "SELECT DISTINCT(ScriptName) FROM conditions WHERE ScriptName <> '' "
- "UNION "
- "SELECT DISTINCT(ScriptName) FROM outdoorpvp_template WHERE ScriptName <> '' "
- "UNION "
- "SELECT DISTINCT(ScriptName) FROM scene_template WHERE ScriptName <> '' "
- "UNION "
- "SELECT DISTINCT(ScriptName) FROM quest_template_addon WHERE ScriptName <> '' "
- "UNION "
- "SELECT DISTINCT(script) FROM instance_template WHERE script <> ''");
+ return _scriptNamesStore.GetAllDBScriptNames();
+}
- if (!result)
+std::string const& ObjectMgr::GetScriptName(uint32 id) const
+{
+ auto const itr = _scriptNamesStore.find(id);
+ if (itr != _scriptNamesStore.end())
{
- TC_LOG_INFO("server.loading", ">> Loaded empty set of Script Names!");
- return;
+ return itr->first;
}
-
- _scriptNamesStore.reserve(result->GetRowCount() + 1);
-
- do
+ else
{
- _scriptNamesStore.insert((*result)[0].GetString());
+ static std::string const empty;
+ return empty;
}
- while (result->NextRow());
-
- TC_LOG_INFO("server.loading", ">> Loaded " SZFMTD " ScriptNames in %u ms", _scriptNamesStore.size(), GetMSTimeDiffToNow(oldMSTime));
-}
-
-std::unordered_set<std::string> ObjectMgr::GetAllScriptNames() const
-{
- return _scriptNamesStore.GetAllScriptNames();
}
-std::string const& ObjectMgr::GetScriptName(uint32 id) const
+bool ObjectMgr::IsScriptDatabaseBound(uint32 id) const
{
- return _scriptNamesStore[id];
+ auto const itr = _scriptNamesStore.find(id);
+ if (itr != _scriptNamesStore.end())
+ {
+ return itr->second.IsScriptDatabaseBound;
+ }
+ else
+ {
+ return false;
+ }
}
-uint32 ObjectMgr::GetScriptId(std::string const& name)
+uint32 ObjectMgr::GetScriptId(std::string const& name, bool isDatabaseBound)
{
- return _scriptNamesStore[name];
+ return _scriptNamesStore.insert(name, isDatabaseBound);
}
CreatureBaseStats const* ObjectMgr::GetCreatureBaseStats(uint8 level, uint8 unitClass)
diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h
index b555dd2fa52..6d21323be11 100644
--- a/src/server/game/Globals/ObjectMgr.h
+++ b/src/server/game/Globals/ObjectMgr.h
@@ -1034,19 +1034,30 @@ class TC_GAME_API ObjectMgr
class ScriptNameContainer
{
- using NameMap = std::map<std::string, uint32>;
+ public:
+ struct Entry
+ {
+ uint32 Id;
+ bool IsScriptDatabaseBound;
+ };
+
+ private:
+ using NameMap = std::map<std::string, Entry>;
NameMap NameToIndex;
std::vector<NameMap::const_iterator> IndexToName;
public:
+ ScriptNameContainer();
+
void reserve(size_t capacity);
- void insert(std::string&& scriptName);
+ uint32 insert(std::string const& scriptName, bool isScriptNameBound = true);
size_t size() const;
- std::string const& operator[](size_t index) const;
- uint32 operator[](std::string const& name) const;
+ NameMap::const_iterator find(size_t index) const;
+ NameMap::const_iterator find(std::string const& name) const;
+ NameMap::const_iterator end() const;
- std::unordered_set<std::string> GetAllScriptNames() const;
+ std::unordered_set<std::string> GetAllDBScriptNames() const;
};
typedef std::map<uint32, uint32> CharacterConversionMap;
@@ -1602,10 +1613,10 @@ class TC_GAME_API ObjectMgr
bool RemoveVendorItem(uint32 entry, uint32 item, uint8 type, bool persist = true); // for event
bool IsVendorItemValid(uint32 vendor_entry, VendorItem const& vItem, Player* player = nullptr, std::set<uint32>* skip_vendors = nullptr, uint32 ORnpcflag = 0) const;
- void LoadScriptNames();
- std::unordered_set<std::string> GetAllScriptNames() const;
+ std::unordered_set<std::string> GetAllDBScriptNames() const;
std::string const& GetScriptName(uint32 id) const;
- uint32 GetScriptId(std::string const& name);
+ bool IsScriptDatabaseBound(uint32 id) const;
+ uint32 GetScriptId(std::string const& name, bool isDatabaseBound = true);
Trinity::IteratorPair<SpellClickInfoContainer::const_iterator> GetSpellClickInfoMapBounds(uint32 creature_id) const
{
diff --git a/src/server/game/Scripting/ScriptMgr.cpp b/src/server/game/Scripting/ScriptMgr.cpp
index f77b93c0d5e..b5e587eb149 100644
--- a/src/server/game/Scripting/ScriptMgr.cpp
+++ b/src/server/game/Scripting/ScriptMgr.cpp
@@ -23,6 +23,7 @@
#include "Creature.h"
#include "CreatureAI.h"
#include "CreatureAIImpl.h"
+#include "CreatureAISelector.h"
#include "DB2Stores.h"
#include "Errors.h"
#include "GameObject.h"
@@ -153,6 +154,9 @@ public:
/// Unloads the script registry.
virtual void Unload() = 0;
+
+ /// Updates the scripts to reflect the current id
+ virtual void SyncScriptNames() = 0;
};
template<class>
@@ -241,6 +245,12 @@ public:
registry->Unload();
}
+ void SyncScriptNames() final override
+ {
+ for (auto const registry : _registries)
+ registry->SyncScriptNames();
+ }
+
template<typename T>
void QueueForDelayedDelete(T&& any)
{
@@ -330,6 +340,9 @@ public:
/// Called before Unload
virtual void BeforeUnload() { }
+
+ /// Called manually to sync scriptnames
+ virtual void OnScriptNamesSync() { };
};
template<typename ScriptType, typename Base>
@@ -518,38 +531,84 @@ class CreatureGameObjectAreaTriggerScriptRegistrySwapHooks
return map->GetAreaTrigger(guid);
}
- template<typename T>
- static void VisitObjectsToSwapOnMap(Map* map, std::unordered_set<uint32> const& idsToRemove, T visitor)
+ static auto VisitObjectsToSwapOnMap(std::unordered_set<uint32> const& idsToRemove)
{
- auto evaluator = [&](std::unordered_map<ObjectGuid, ObjectType*>& objects)
+ return [&idsToRemove](Map* map, auto&& visitor)
{
- for (auto object : objects)
+ auto evaluator = [&](std::unordered_map<ObjectGuid, ObjectType*>& objects)
{
- // When the script Id of the script isn't removed in this
- // context change, do nothing.
- if (idsToRemove.find(object.second->GetScriptId()) != idsToRemove.end())
- visitor(object.second);
- }
+ for (auto object : objects)
+ {
+ // When the script Id of the script isn't removed in this
+ // context change, do nothing.
+ uint32 aiId = object.second->AI() ? object.second->AI()->GetId() : 0;
+ if (idsToRemove.find(aiId) != idsToRemove.end())
+ visitor(object.second);
+ }
+ };
+
+ AIFunctionMapWorker<typename std::decay<decltype(evaluator)>::type> worker(std::move(evaluator));
+ TypeContainerVisitor<decltype(worker), MapStoredObjectTypesContainer> containerVisitor(worker);
+
+ containerVisitor.Visit(map->GetObjectsStore());
};
+ }
- AIFunctionMapWorker<typename std::decay<decltype(evaluator)>::type> worker(std::move(evaluator));
- TypeContainerVisitor<decltype(worker), MapStoredObjectTypesContainer> containerVisitor(worker);
+ static auto VisitObjectsWhereIdWasUpdated()
+ {
+ return [](Map* map, auto&& visitor)
+ {
+ auto evaluator = [&](std::unordered_map<ObjectGuid, ObjectType*>& objects)
+ {
+ for (auto object : objects)
+ {
+ if (object.second->AI())
+ {
+ ASSERT(object.second->AI()->GetId());
+
+ uint32 aiId = object.second->AI()->GetId();
+ uint32 scriptId = FactorySelector::GetSelectedAIId(object.second);
+
+ ASSERT(scriptId);
+
+ if (aiId == scriptId)
+ {
+ // Skip if the ai id matches
+ continue;
+ }
+
+ if (!sObjectMgr->IsScriptDatabaseBound(scriptId)
+ && !sObjectMgr->IsScriptDatabaseBound(aiId))
+ {
+ // Skip if we are dealing with two selectable AI scripts
+ continue;
+ }
+
+ visitor(object.second);
+ }
+ else
+ visitor(object.second);
+ }
+ };
- containerVisitor.Visit(map->GetObjectsStore());
+ AIFunctionMapWorker<typename std::decay<decltype(evaluator)>::type> worker(std::move(evaluator));
+ TypeContainerVisitor<decltype(worker), MapStoredObjectTypesContainer> containerVisitor(worker);
+
+ containerVisitor.Visit(map->GetObjectsStore());
+ };
}
- static void DestroyScriptIdsFromSet(std::unordered_set<uint32> const& idsToRemove)
+ template<typename T>
+ static void DestroyScriptIdsWithVisitor(T&& visitor)
{
// First reset all swapped scripts safe by guid
- // Skip creatures and gameobjects with an empty guid
- // (that were not added to the world as of now)
sMapMgr->DoForAllMaps([&](Map* map)
{
std::vector<ObjectGuid> guidsToReset;
- VisitObjectsToSwapOnMap(map, idsToRemove, [&](ObjectType* object)
+ visitor(map, [&](ObjectType* object)
{
- if (object->AI() && !object->GetGUID().IsEmpty())
+ if (object->AI())
guidsToReset.push_back(object->GetGUID());
});
@@ -559,7 +618,7 @@ class CreatureGameObjectAreaTriggerScriptRegistrySwapHooks
UnloadResetScript(entity);
}
- VisitObjectsToSwapOnMap(map, idsToRemove, [&](ObjectType* object)
+ visitor(map, [&](ObjectType* object)
{
// Destroy the scripts instantly
UnloadDestroyScript(object);
@@ -567,15 +626,16 @@ class CreatureGameObjectAreaTriggerScriptRegistrySwapHooks
});
}
- static void InitializeScriptIdsFromSet(std::unordered_set<uint32> const& idsToRemove)
+ template<typename T>
+ static void InitializeScriptIdsWithVisitor(T&& visitor)
{
sMapMgr->DoForAllMaps([&](Map* map)
{
std::vector<ObjectGuid> guidsToReset;
- VisitObjectsToSwapOnMap(map, idsToRemove, [&](ObjectType* object)
+ visitor(map, [&](ObjectType* object)
{
- if (!object->AI() && !object->GetGUID().IsEmpty())
+ if (!object->AI())
{
// Initialize the script
LoadInitializeScript(object);
@@ -601,7 +661,7 @@ public:
void BeforeReleaseContext(std::string const& context) final override
{
auto idsToRemove = static_cast<Base*>(this)->GetScriptIDsToRemove(context);
- DestroyScriptIdsFromSet(idsToRemove);
+ DestroyScriptIdsWithVisitor(VisitObjectsToSwapOnMap(idsToRemove));
// Add the new ids which are removed to the global ids to remove set
ids_removed_.insert(idsToRemove.begin(), idsToRemove.end());
@@ -618,8 +678,9 @@ public:
ids_removed_.insert(static_cast<Base*>(this)->GetRecentlyAddedScriptIDs().begin(),
static_cast<Base*>(this)->GetRecentlyAddedScriptIDs().end());
- DestroyScriptIdsFromSet(ids_removed_);
- InitializeScriptIdsFromSet(ids_removed_);
+ auto const visitor = VisitObjectsToSwapOnMap(ids_removed_);
+ DestroyScriptIdsWithVisitor(visitor);
+ InitializeScriptIdsWithVisitor(visitor);
ids_removed_.clear();
}
@@ -629,6 +690,13 @@ public:
ASSERT(ids_removed_.empty());
}
+ void OnScriptNamesSync() final override
+ {
+ auto const visitor = VisitObjectsWhereIdWasUpdated();
+ DestroyScriptIdsWithVisitor(visitor);
+ InitializeScriptIdsWithVisitor(visitor);
+ }
+
private:
std::unordered_set<uint32> ids_removed_;
};
@@ -876,6 +944,11 @@ public:
_ids_of_contexts.clear();
}
+ void SyncScriptNames() final override
+ {
+ this->OnScriptNamesSync();
+ }
+
// Adds a database bound script
void AddScript(ScriptType* script)
{
@@ -886,46 +959,33 @@ public:
std::unique_ptr<ScriptType> script_ptr(script);
- // Get an ID for the script. An ID only exists if it's a script that is assigned in the database
- // through a script name (or similar).
- if (uint32 const id = sObjectMgr->GetScriptId(script->GetName()))
+ // Get an ID for the script.
+ uint32 const id = sObjectMgr->GetScriptId(script->GetName());
+
+ // Try to find an existing script.
+ for (auto const& stored_script : _scripts)
{
- // Try to find an existing script.
- for (auto const& stored_script : _scripts)
+ // If the script names match...
+ if (stored_script.second->GetName() == script->GetName())
{
- // If the script names match...
- if (stored_script.second->GetName() == script->GetName())
- {
- // If the script is already assigned -> delete it!
- TC_LOG_ERROR("scripts", "Script '%s' already assigned with the same script name, "
- "so the script can't work.", script->GetName().c_str());
-
- // Error that should be fixed ASAP.
- sScriptRegistryCompositum->QueueForDelayedDelete(std::move(script_ptr));
- ABORT();
- return;
- }
- }
-
- // If the script isn't assigned -> assign it!
- _scripts.insert(std::make_pair(id, std::move(script_ptr)));
- _ids_of_contexts.insert(std::make_pair(sScriptMgr->GetCurrentScriptContext(), id));
- _recently_added_ids.insert(id);
+ // If the script is already assigned -> delete it!
+ TC_LOG_ERROR("scripts", "Script '%s' already assigned with the same script name, "
+ "so the script can't work.", script->GetName().c_str());
- sScriptRegistryCompositum->SetScriptNameInContext(script->GetName(),
- sScriptMgr->GetCurrentScriptContext());
+ // Error that should be fixed ASAP.
+ sScriptRegistryCompositum->QueueForDelayedDelete(std::move(script_ptr));
+ ABORT();
+ return;
+ }
}
- else
- {
- // The script uses a script name from database, but isn't assigned to anything.
- TC_LOG_ERROR("sql.sql", "Script named '%s' does not have a script name assigned in database.",
- script->GetName().c_str());
- // Avoid calling "delete script;" because we are currently in the script constructor
- // In a valid scenario this will not happen because every script has a name assigned in the database
- sScriptRegistryCompositum->QueueForDelayedDelete(std::move(script_ptr));
- return;
- }
+ // If the script isn't assigned -> assign it!
+ _scripts.insert(std::make_pair(id, std::move(script_ptr)));
+ _ids_of_contexts.insert(std::make_pair(sScriptMgr->GetCurrentScriptContext(), id));
+ _recently_added_ids.insert(id);
+
+ sScriptRegistryCompositum->SetScriptNameInContext(script->GetName(),
+ sScriptMgr->GetCurrentScriptContext());
}
// Gets a script by its ID (assigned by ObjectMgr).
@@ -1034,6 +1094,10 @@ public:
_scripts.clear();
}
+ void SyncScriptNames() final override
+ {
+ }
+
// Adds a non database bound script
void AddScript(ScriptType* script)
{
@@ -1117,7 +1181,7 @@ ScriptObject::~ScriptObject()
}
ScriptMgr::ScriptMgr()
- : _scriptCount(0), _script_loader_callback(nullptr)
+ : _scriptCount(0), _scriptIdUpdated(false), _script_loader_callback(nullptr)
{
}
@@ -1165,7 +1229,7 @@ void ScriptMgr::Initialize()
sScriptMgr->SwapScriptContext(true);
// Print unused script names.
- std::unordered_set<std::string> unusedScriptNames = sObjectMgr->GetAllScriptNames();
+ std::unordered_set<std::string> unusedScriptNames = sObjectMgr->GetAllDBScriptNames();
// Remove the used scripts from the given container.
sScriptRegistryCompositum->RemoveUsedScriptsFromContainer(unusedScriptNames);
@@ -1185,6 +1249,20 @@ void ScriptMgr::Initialize()
GetScriptCount(), GetMSTimeDiffToNow(oldMSTime));
}
+void ScriptMgr::NotifyScriptIDUpdate()
+{
+ _scriptIdUpdated = true;
+}
+
+void ScriptMgr::SyncScripts()
+{
+ if (_scriptIdUpdated)
+ {
+ _scriptIdUpdated = false;
+ sScriptRegistryCompositum->SyncScriptNames();
+ }
+}
+
void ScriptMgr::SetScriptContext(std::string const& context)
{
_currentContext = context;
@@ -1598,6 +1676,11 @@ bool ScriptMgr::OnCastItemCombatSpell(Player* player, Unit* victim, SpellInfo co
return tmpscript->OnCastItemCombatSpell(player, victim, spellInfo, item);
}
+bool ScriptMgr::CanCreateCreatureAI(uint32 scriptId) const
+{
+ return !!ScriptRegistry<CreatureScript>::Instance()->GetScriptById(scriptId);
+}
+
CreatureAI* ScriptMgr::GetCreatureAI(Creature* creature)
{
ASSERT(creature);
@@ -1606,6 +1689,11 @@ CreatureAI* ScriptMgr::GetCreatureAI(Creature* creature)
return tmpscript->GetAI(creature);
}
+bool ScriptMgr::CanCreateGameObjectAI(uint32 scriptId) const
+{
+ return !!ScriptRegistry<GameObjectScript>::Instance()->GetScriptById(scriptId);
+}
+
GameObjectAI* ScriptMgr::GetGameObjectAI(GameObject* gameobject)
{
ASSERT(gameobject);
@@ -1614,6 +1702,11 @@ GameObjectAI* ScriptMgr::GetGameObjectAI(GameObject* gameobject)
return tmpscript->GetAI(gameobject);
}
+bool ScriptMgr::CanCreateAreaTriggerAI(uint32 scriptId) const
+{
+ return !!ScriptRegistry<AreaTriggerEntityScript>::Instance()->GetScriptById(scriptId);
+}
+
AreaTriggerAI* ScriptMgr::GetAreaTriggerAI(AreaTrigger* areatrigger)
{
ASSERT(areatrigger);
diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h
index 9b4bd01e2b6..863661022af 100644
--- a/src/server/game/Scripting/ScriptMgr.h
+++ b/src/server/game/Scripting/ScriptMgr.h
@@ -901,6 +901,12 @@ class TC_GAME_API ScriptMgr
_script_loader_callback = script_loader_callback;
}
+ public: /* Updating script ids */
+ /// Inform the ScriptMgr that an entity has a changed script id
+ void NotifyScriptIDUpdate();
+ /// Synchronize all scripts with their current ids
+ void SyncScripts();
+
public: /* Script contexts */
/// Set the current script context, which allows the ScriptMgr
/// to accept new scripts in this context.
@@ -989,10 +995,12 @@ class TC_GAME_API ScriptMgr
public: /* CreatureScript */
+ bool CanCreateCreatureAI(uint32 scriptId) const;
CreatureAI* GetCreatureAI(Creature* creature);
public: /* GameObjectScript */
+ bool CanCreateGameObjectAI(uint32 scriptId) const;
GameObjectAI* GetGameObjectAI(GameObject* go);
public: /* AreaTriggerScript */
@@ -1130,6 +1138,7 @@ class TC_GAME_API ScriptMgr
public: /* AreaTriggerEntityScript */
+ bool CanCreateAreaTriggerAI(uint32 scriptId) const;
AreaTriggerAI* GetAreaTriggerAI(AreaTrigger* areaTrigger);
public: /* ConversationScript */
@@ -1152,6 +1161,7 @@ class TC_GAME_API ScriptMgr
private:
uint32 _scriptCount;
+ bool _scriptIdUpdated;
ScriptLoaderCallbackType _script_loader_callback;
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index 212ae90e00b..717100a1f45 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -1781,9 +1781,6 @@ void World::SetInitialWorldSettings()
TC_LOG_INFO("server.loading", "Loading GameObject models...");
LoadGameObjectModelList(m_dataPath);
- TC_LOG_INFO("server.loading", "Loading Script Names...");
- sObjectMgr->LoadScriptNames();
-
TC_LOG_INFO("server.loading", "Loading Instance Template...");
sObjectMgr->LoadInstanceTemplate();
@@ -2546,6 +2543,9 @@ void World::Update(uint32 diff)
m_timers[WUPDATE_AHBOT].Reset();
}
+ /// Synchronize all scripts with their ids before updating the sScriptReloadMgr
+ sScriptMgr->SyncScripts();
+
/// <li> Handle file changes
if (m_timers[WUPDATE_CHECK_FILECHANGES].Passed())
{
diff --git a/src/server/scripts/Commands/cs_reload.cpp b/src/server/scripts/Commands/cs_reload.cpp
index 3e8a76b57c0..16bfea63ad5 100644
--- a/src/server/scripts/Commands/cs_reload.cpp
+++ b/src/server/scripts/Commands/cs_reload.cpp
@@ -41,6 +41,7 @@ EndScriptData */
#include "LootMgr.h"
#include "MapManager.h"
#include "ObjectMgr.h"
+#include "ScriptMgr.h"
#include "SkillDiscovery.h"
#include "SkillExtraItems.h"
#include "SmartAI.h"
@@ -152,6 +153,7 @@ public:
{ "spell_pet_auras", rbac::RBAC_PERM_COMMAND_RELOAD_SPELL_PET_AURAS, true, &HandleReloadSpellPetAurasCommand, "" },
{ "spell_proc", rbac::RBAC_PERM_COMMAND_RELOAD_SPELL_PROC, true, &HandleReloadSpellProcsCommand, "" },
{ "spell_scripts", rbac::RBAC_PERM_COMMAND_RELOAD_SPELL_SCRIPTS, true, &HandleReloadSpellScriptsCommand, "" },
+ { "spell_script_names", rbac::RBAC_PERM_COMMAND_RELOAD_SPELL_SCRIPT_NAMES, true, &HandleReloadSpellScriptNamesCommand, "" },
{ "spell_target_position", rbac::RBAC_PERM_COMMAND_RELOAD_SPELL_TARGET_POSITION, true, &HandleReloadSpellTargetPositionCommand, "" },
{ "spell_threats", rbac::RBAC_PERM_COMMAND_RELOAD_SPELL_THREATS, true, &HandleReloadSpellThreatsCommand, "" },
{ "spell_group_stack_rules", rbac::RBAC_PERM_COMMAND_RELOAD_SPELL_GROUP_STACK_RULES, true, &HandleReloadSpellGroupStackRulesCommand, "" },
@@ -276,6 +278,7 @@ public:
TC_LOG_INFO("misc", "Re-Loading Scripts...");
HandleReloadEventScriptsCommand(handler, "a");
HandleReloadSpellScriptsCommand(handler, "a");
+ HandleReloadSpellScriptNamesCommand(handler, "a");
handler->SendGlobalGMSysMessage("DB tables `*_scripts` reloaded.");
HandleReloadWpScriptsCommand(handler, "a");
HandleReloadWpCommand(handler, "a");
@@ -296,6 +299,7 @@ public:
HandleReloadSpellThreatsCommand(handler, "a");
HandleReloadSpellGroupStackRulesCommand(handler, "a");
HandleReloadSpellPetAurasCommand(handler, "a");
+ HandleReloadSpellScriptNamesCommand(handler, "a");
return true;
}
@@ -349,6 +353,7 @@ public:
{
TC_LOG_INFO("misc", "Re-Loading Additional Criteria Data...");
sCriteriaMgr->LoadCriteriaData();
+ sScriptMgr->NotifyScriptIDUpdate();
handler->SendGlobalGMSysMessage("DB table `criteria_data` reloaded.");
return true;
}
@@ -389,6 +394,7 @@ public:
{
TC_LOG_INFO("misc", "Re-Loading Battleground Templates...");
sBattlegroundMgr->LoadBattlegroundTemplates();
+ sScriptMgr->NotifyScriptIDUpdate();
handler->SendGlobalGMSysMessage("DB table `battleground_template` reloaded.");
return true;
}
@@ -461,6 +467,7 @@ public:
}
sObjectMgr->InitializeQueriesData(QUERY_DATA_CREATURES);
+ sScriptMgr->NotifyScriptIDUpdate();
handler->SendGlobalGMSysMessage("Creature template reloaded.");
return true;
}
@@ -550,6 +557,8 @@ public:
TC_LOG_INFO("misc", "Re-Loading GameObjects for quests...");
sObjectMgr->LoadGameObjectForQuests();
handler->SendGlobalGMSysMessage("Data GameObjects for quests reloaded.");
+ sScriptMgr->NotifyScriptIDUpdate();
+
return true;
}
@@ -974,6 +983,16 @@ public:
return true;
}
+ static bool HandleReloadSpellScriptNamesCommand(ChatHandler* handler, const char* /*args*/)
+ {
+ TC_LOG_INFO("misc", "Reloading spell_script_names table...");
+ sObjectMgr->LoadSpellScriptNames();
+ sScriptMgr->NotifyScriptIDUpdate();
+ sObjectMgr->ValidateSpellScripts();
+ handler->SendGlobalGMSysMessage("Spell scripts reloaded.");
+ return true;
+ }
+
static bool HandleReloadGameGraveyardZoneCommand(ChatHandler* handler, char const* /*args*/)
{
TC_LOG_INFO("misc", "Re-Loading Graveyard-zone links...");
@@ -1107,6 +1126,7 @@ public:
{
TC_LOG_INFO("misc", "Re-Loading Conditions...");
sConditionMgr->LoadConditions(true);
+ sScriptMgr->NotifyScriptIDUpdate();
handler->SendGlobalGMSysMessage("Conditions reloaded.");
return true;
}
@@ -1155,7 +1175,8 @@ public:
{
TC_LOG_INFO("misc", "Reloading areatrigger_template table...");
sAreaTriggerDataStore->LoadAreaTriggerTemplates();
- handler->SendGlobalGMSysMessage("AreaTrigger templates reloaded. Already spawned AT won't be affected. New scriptname need a reboot.");
+ sScriptMgr->NotifyScriptIDUpdate();
+ handler->SendGlobalGMSysMessage("AreaTrigger templates reloaded.");
return true;
}
@@ -1163,7 +1184,8 @@ public:
{
TC_LOG_INFO("misc", "Reloading scene_template table...");
sObjectMgr->LoadSceneTemplates();
- handler->SendGlobalGMSysMessage("Scenes templates reloaded. New scriptname need a reboot.");
+ sScriptMgr->NotifyScriptIDUpdate();
+ handler->SendGlobalGMSysMessage("Scenes templates reloaded.");
return true;
}
@@ -1171,6 +1193,7 @@ public:
{
TC_LOG_INFO("misc", "Reloading conversation_* tables...");
sConversationDataStore->LoadConversationTemplates();
+ sScriptMgr->NotifyScriptIDUpdate();
handler->SendGlobalGMSysMessage("Conversation templates reloaded.");
return true;
}