From 656694b383ad4a1bbc4a62edd88f212e24bfb9e2 Mon Sep 17 00:00:00 2001 From: Jelle Meeus Date: Mon, 30 Jun 2025 05:49:47 +0200 Subject: [PATCH] feat(Core/Command): add GM spectator to allow cross-faction `/follow` (#22393) --- .../rev_1751234046378828666.sql | 5 ++++ src/server/game/Entities/Player/Player.h | 4 +++ src/server/game/Entities/Unit/Unit.cpp | 4 +++ src/server/game/Miscellaneous/Language.h | 4 ++- src/server/scripts/Commands/cs_gm.cpp | 28 ++++++++++++++----- 5 files changed, 37 insertions(+), 8 deletions(-) create mode 100644 data/sql/updates/pending_db_world/rev_1751234046378828666.sql diff --git a/data/sql/updates/pending_db_world/rev_1751234046378828666.sql b/data/sql/updates/pending_db_world/rev_1751234046378828666.sql new file mode 100644 index 000000000..d20329423 --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1751234046378828666.sql @@ -0,0 +1,5 @@ +-- +DELETE FROM `acore_string` WHERE `entry` IN (6617, 6618); +INSERT INTO `acore_string` (`entry`, `content_default`) VALUES +(6617, 'GM Spectator is ON'), +(6618, 'GM Spectator is OFF'); diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 9ac8df486..24af62b65 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -597,6 +597,7 @@ enum PlayerExtraFlags PLAYER_EXTRA_SPECTATOR_ON = 0x0080, // Marks if player is spectactor PLAYER_EXTRA_PVP_DEATH = 0x0100, // store PvP death status until corpse creating. PLAYER_EXTRA_SHOW_DK_PET = 0x0400, // Marks if player should see ghoul on login screen + PLAYER_EXTRA_GM_SPECTATOR = 0x0800, }; // 2^n values @@ -1177,6 +1178,9 @@ public: void SetGameMaster(bool on); [[nodiscard]] bool isGMChat() const { return m_ExtraFlags & PLAYER_EXTRA_GM_CHAT; } void SetGMChat(bool on) { if (on) m_ExtraFlags |= PLAYER_EXTRA_GM_CHAT; else m_ExtraFlags &= ~PLAYER_EXTRA_GM_CHAT; } + [[nodiscard]] bool IsGMSpectator() const { return m_ExtraFlags & PLAYER_EXTRA_GM_SPECTATOR; } + void SetGMSpectator(bool on) { if (on) m_ExtraFlags |= PLAYER_EXTRA_GM_SPECTATOR; else m_ExtraFlags &= ~PLAYER_EXTRA_GM_SPECTATOR; } + [[nodiscard]] bool isTaxiCheater() const { return m_ExtraFlags & PLAYER_EXTRA_TAXICHEAT; } void SetTaxiCheater(bool on) { if (on) m_ExtraFlags |= PLAYER_EXTRA_TAXICHEAT; else m_ExtraFlags &= ~PLAYER_EXTRA_TAXICHEAT; } [[nodiscard]] bool isGMVisible() const { return !(m_ExtraFlags & PLAYER_EXTRA_GM_INVISIBLE); } diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 72fb816a4..3d45ed10d 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -20791,6 +20791,10 @@ void Unit::PatchValuesUpdate(ByteBuffer& valuesUpdateBuf, BuildValuesCachePosPoi { valuesUpdateBuf.put(posPointers.UnitFieldFactionTemplatePos, uint32(target->GetFaction())); } + else if (target->IsGMSpectator() && IsControlledByPlayer()) + { + valuesUpdateBuf.put(posPointers.UnitFieldFactionTemplatePos, uint32(target->GetFaction())); + } } sScriptMgr->OnPatchValuesUpdate(this, valuesUpdateBuf, posPointers, target); diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h index 801ad3a48..3565a6cce 100644 --- a/src/server/game/Miscellaneous/Language.h +++ b/src/server/game/Miscellaneous/Language.h @@ -1171,8 +1171,10 @@ enum AcoreStrings LANG_GM_ANNOUNCE_COLOR = 6615, LANG_GM_SILENCE = 6616, // "Silence is ON for %s" - Spell 1852 + LANG_GM_SPECTATOR_ON = 6617, + LANG_GM_SPECTATOR_OFF = 6618, - // Free strings 6617-7522 + // Free strings 6619-7522 LANG_WORLD_CLOSED = 7523, LANG_WORLD_OPENED = 7524, diff --git a/src/server/scripts/Commands/cs_gm.cpp b/src/server/scripts/Commands/cs_gm.cpp index 358d16b8b..302fb5803 100644 --- a/src/server/scripts/Commands/cs_gm.cpp +++ b/src/server/scripts/Commands/cs_gm.cpp @@ -38,13 +38,14 @@ public: { static ChatCommandTable gmCommandTable = { - { "chat", HandleGMChatCommand, SEC_GAMEMASTER, Console::No }, - { "fly", HandleGMFlyCommand, SEC_GAMEMASTER, Console::No }, - { "ingame", HandleGMListIngameCommand, SEC_PLAYER, Console::Yes }, - { "list", HandleGMListFullCommand, SEC_ADMINISTRATOR, Console::Yes }, - { "visible", HandleGMVisibleCommand, SEC_GAMEMASTER, Console::No }, - { "on", HandleGMOnCommand, SEC_MODERATOR, Console::No }, - { "off", HandleGMOffCommand, SEC_MODERATOR, Console::No } + { "chat", HandleGMChatCommand, SEC_GAMEMASTER, Console::No }, + { "fly", HandleGMFlyCommand, SEC_GAMEMASTER, Console::No }, + { "ingame", HandleGMListIngameCommand, SEC_PLAYER, Console::Yes }, + { "list", HandleGMListFullCommand, SEC_ADMINISTRATOR, Console::Yes }, + { "visible", HandleGMVisibleCommand, SEC_GAMEMASTER, Console::No }, + { "on", HandleGMOnCommand, SEC_MODERATOR, Console::No }, + { "off", HandleGMOffCommand, SEC_MODERATOR, Console::No }, + { "spectator", HandleGMSpectatorCommand, SEC_GAMEMASTER, Console::No }, }; static ChatCommandTable commandTable = { @@ -236,6 +237,19 @@ public: handler->SendNotification(LANG_GM_OFF); return true; } + + static bool HandleGMSpectatorCommand(ChatHandler* handler, Optional enable) + { + Player* player = handler->GetSession()->GetPlayer(); + + if (enable.has_value()) + player->SetGMSpectator(*enable); + else + player->SetGMSpectator(!player->IsGMSpectator()); + handler->SendNotification(player->IsGMSpectator() ? LANG_GM_SPECTATOR_ON : LANG_GM_SPECTATOR_OFF); + + return true; + } }; void AddSC_gm_commandscript()