diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/server/game/Accounts/RBAC.h | 2 | ||||
-rw-r--r-- | src/server/game/Instances/InstanceScript.h | 2 | ||||
-rw-r--r-- | src/server/scripts/Commands/cs_debug.cpp | 111 |
3 files changed, 114 insertions, 1 deletions
diff --git a/src/server/game/Accounts/RBAC.h b/src/server/game/Accounts/RBAC.h index c90a86b7f3a..aef00f3d236 100644 --- a/src/server/game/Accounts/RBAC.h +++ b/src/server/game/Accounts/RBAC.h @@ -776,7 +776,7 @@ enum RBACPermissions RBAC_PERM_COMMAND_MODIFY_POWER = 868, RBAC_PERM_COMMAND_DEBUG_SEND_PLAYER_CHOICE = 869, RBAC_PERM_COMMAND_DEBUG_THREATINFO = 870, - RBAC_PERM_COMMAND_DEBUG_INSTANCESPAWN = 871, // reserved + RBAC_PERM_COMMAND_DEBUG_INSTANCESPAWN = 871, RBAC_PERM_COMMAND_SERVER_DEBUG = 872, RBAC_PERM_COMMAND_RELOAD_CREATURE_MOVEMENT_OVERRIDE = 873, // 874 previously used, do not reuse diff --git a/src/server/game/Instances/InstanceScript.h b/src/server/game/Instances/InstanceScript.h index 3350c2775c3..cba5fa03936 100644 --- a/src/server/game/Instances/InstanceScript.h +++ b/src/server/game/Instances/InstanceScript.h @@ -349,6 +349,8 @@ class TC_GAME_API InstanceScript : public ZoneScript // Strong reference to the associated script module std::shared_ptr<ModuleReference> module_reference; #endif // #ifndef TRINITY_API_USE_DYNAMIC_LINKING + + friend class debug_commandscript; }; #endif // TRINITY_INSTANCE_DATA_H diff --git a/src/server/scripts/Commands/cs_debug.cpp b/src/server/scripts/Commands/cs_debug.cpp index 2d53688e2e5..9bb19db3910 100644 --- a/src/server/scripts/Commands/cs_debug.cpp +++ b/src/server/scripts/Commands/cs_debug.cpp @@ -33,6 +33,7 @@ EndScriptData */ #include "Conversation.h" #include "GossipDef.h" #include "GridNotifiersImpl.h" +#include "InstanceScript.h" #include "Language.h" #include "Log.h" #include "M2Stores.h" @@ -107,6 +108,7 @@ public: { "boundary", rbac::RBAC_PERM_COMMAND_DEBUG_BOUNDARY, false, &HandleDebugBoundaryCommand, "" }, { "raidreset", rbac::RBAC_PERM_COMMAND_INSTANCE_UNBIND, false, &HandleDebugRaidResetCommand, "" }, { "neargraveyard", rbac::RBAC_PERM_COMMAND_NEARGRAVEYARD, false, &HandleDebugNearGraveyard, "" }, + { "instancespawn", rbac::RBAC_PERM_COMMAND_DEBUG_INSTANCESPAWN, false, &HandleDebugInstanceSpawns, "" }, { "conversation" , rbac::RBAC_PERM_COMMAND_DEBUG_CONVERSATION, false, &HandleDebugConversationCommand, "" }, { "worldstate" , rbac::RBAC_PERM_COMMAND_DEBUG, false, &HandleDebugWorldStateCommand, "" }, { "wsexpression" , rbac::RBAC_PERM_COMMAND_DEBUG, false, &HandleDebugWSExpressionCommand, "" }, @@ -1484,6 +1486,115 @@ public: return true; } + static bool HandleDebugInstanceSpawns(ChatHandler* handler, char const* args) + { + Player const* const player = handler->GetSession()->GetPlayer(); + if (!player) + return false; + + bool explain = false; + uint32 groupID = 0; + if (!stricmp(args, "explain")) + explain = true; + else + groupID = atoi(args); + + if (groupID && !sObjectMgr->GetSpawnGroupData(groupID)) + { + handler->PSendSysMessage("There is no spawn group with ID %u.", groupID); + handler->SetSentErrorMessage(true); + return false; + } + + Map const* const map = player->GetMap(); + char const* const mapName = map->GetMapName(); + InstanceScript const* const instance = player->GetInstanceScript(); + if (!instance) + { + handler->PSendSysMessage("%s has no instance script.", mapName); + handler->SetSentErrorMessage(true); + return false; + } + if (!instance->_instanceSpawnGroups || instance->_instanceSpawnGroups->empty()) + { + handler->PSendSysMessage("%s's instance script does not manage any spawn groups.", mapName); + handler->SetSentErrorMessage(true); + return false; + } + auto const& spawnGroups = *instance->_instanceSpawnGroups; + std::unordered_map<uint32, std::set<std::tuple<bool, uint8, uint8>>> store; + for (InstanceSpawnGroupInfo const& info : spawnGroups) + { + if (groupID && info.SpawnGroupId != groupID) + continue; + + bool isSpawn; + if (info.Flags & InstanceSpawnGroupInfo::FLAG_BLOCK_SPAWN) + isSpawn = false; + else if (info.Flags & InstanceSpawnGroupInfo::FLAG_ACTIVATE_SPAWN) + isSpawn = true; + else + continue; + + store[info.SpawnGroupId].emplace(isSpawn, info.BossStateId, info.BossStates); + } + + if (groupID && store.find(groupID) == store.end()) + { + handler->PSendSysMessage("%s's instance script does not manage group '%s'.", mapName, sObjectMgr->GetSpawnGroupData(groupID)->name.c_str()); + handler->SetSentErrorMessage(true); + return false; + } + + if (!groupID) + handler->PSendSysMessage("Spawn groups managed by %s (%u):", mapName, map->GetId()); + + for (auto const& pair : store) + { + SpawnGroupTemplateData const* groupData = sObjectMgr->GetSpawnGroupData(pair.first); + assert(groupData); // checked by objectmgr on load + if (explain) + { + handler->PSendSysMessage(" |-- '%s' (%u)", groupData->name, pair.first); + bool isBlocked = false, isSpawned = false; + for (auto const& tuple : pair.second) + { + bool const isSpawn = std::get<0>(tuple); + uint8 const bossStateId = std::get<1>(tuple); + EncounterState const actualState = instance->GetBossState(bossStateId); + if (std::get<2>(tuple) & (1 << actualState)) + { + if (isSpawn) + { + isSpawned = true; + if (isBlocked) + handler->PSendSysMessage(" | |-- '%s' would be allowed to spawn by boss state %u being %s, but this is overruled", groupData->name, bossStateId, InstanceScript::GetBossStateName(actualState)); + else + handler->PSendSysMessage(" | |-- '%s' is allowed to spawn because boss state %u is %s.", groupData->name, bossStateId, InstanceScript::GetBossStateName(bossStateId)); + } + else + { + isBlocked = true; + handler->PSendSysMessage(" | |-- '%s' is blocked from spawning because boss state %u is %s.", groupData->name, bossStateId, InstanceScript::GetBossStateName(bossStateId)); + } + } + else + handler->PSendSysMessage(" | |-- '%s' could've been %s if boss state %u matched mask %u; but it is %s -> %u, which does not match.", + groupData->name, isSpawn ? "allowed to spawn" : "blocked from spawning", bossStateId, std::get<2>(tuple), InstanceScript::GetBossStateName(actualState), (1 << actualState)); + } + if (isBlocked) + handler->PSendSysMessage(" | |=> '%s' is not active due to a blocking rule being matched", groupData->name); + else if (isSpawned) + handler->PSendSysMessage(" | |=> '%s' is active due to a spawn rule being matched", groupData->name); + else + handler->PSendSysMessage(" | |=> '%s' is not active due to none of its rules being matched", groupData->name); + } + else + handler->PSendSysMessage(" - '%s' (%u) is %sactive", groupData->name, pair.first, map->IsSpawnGroupActive(pair.first) ? "" : "not "); + } + return true; + } + static bool HandleDebugConversationCommand(ChatHandler* handler, char const* args) { if (!*args) |