From 7013087bcde6fca4e0f7027d8eb48692ea484316 Mon Sep 17 00:00:00 2001 From: nico Date: Mon, 12 Oct 2026 12:51:09 +0000 Subject: [PATCH] core: add clientless player GM test adapter --- .../scripts/Custom/viano_bot_commands.cpp | 115 +++++++++++++++++- 1 file changed, 114 insertions(+), 1 deletion(-) diff --git a/src/server/scripts/Custom/viano_bot_commands.cpp b/src/server/scripts/Custom/viano_bot_commands.cpp index fe0a143e2d..5537d42a62 100644 --- a/src/server/scripts/Custom/viano_bot_commands.cpp +++ b/src/server/scripts/Custom/viano_bot_commands.cpp @@ -11,6 +11,7 @@ #include "ScriptMgr.h" #include "Chat.h" +#include "DatabaseEnv.h" #include "Creature.h" #include "Group.h" #include "ObjectAccessor.h" @@ -20,7 +21,9 @@ #include "RBAC.h" #include "TemporarySummon.h" #include "Unit.h" +#include "World.h" +#include #include namespace VianoBotCommands @@ -571,6 +574,109 @@ namespace VianoBotCommands return true; } + // CLIENTLESS_PLAYER_CORE_C4_TEST_ADAPTER + // Temporary GM-only test surface for the generic clientless Player lifecycle. + // Final production GM commands will use a different command contract. + static bool ParseCharacterGuid(ChatHandler* handler, char const* args, uint32& characterGuid) + { + if (!args) + { + handler->SendSysMessage("Usage: .clientless login or .clientless logout "); + return false; + } + + while (*args == ' ' || *args == '\t') + ++args; + + if (!*args) + { + handler->SendSysMessage("Usage: .clientless login or .clientless logout "); + return false; + } + + char* end = nullptr; + unsigned long value = std::strtoul(args, &end, 10); + + while (end && (*end == ' ' || *end == '\t')) + ++end; + + if (!value || !end || *end != '\0' || value > 0xFFFFFFFFul) + { + handler->SendSysMessage("characterGuid must be a non-zero numeric low GUID."); + return false; + } + + characterGuid = uint32(value); + return true; + } + + static bool HandleClientlessLogin(ChatHandler* handler, char const* args) + { + uint32 characterGuid = 0; + if (!ParseCharacterGuid(handler, args, characterGuid)) + return true; + + QueryResult result = CharacterDatabase.PQuery( + "SELECT account, name FROM characters WHERE guid = %u", + characterGuid); + + if (!result) + { + handler->PSendSysMessage( + "No character found for GUID %u.", + characterGuid); + return true; + } + + Field* fields = result->Fetch(); + uint32 accountId = fields[0].GetUInt32(); + std::string characterName = fields[1].GetString(); + + if (!sWorld->CreateClientlessPlayerSession(accountId, characterGuid)) + { + handler->PSendSysMessage( + "Clientless login failed for '%s' (GUID %u, account %u). Check worldserver log for the rejection reason.", + characterName.c_str(), characterGuid, accountId); + return true; + } + + handler->PSendSysMessage( + "Clientless login started for '%s' (GUID %u, account %u).", + characterName.c_str(), characterGuid, accountId); + return true; + } + + static bool HandleClientlessLogout(ChatHandler* handler, char const* args) + { + uint32 characterGuid = 0; + if (!ParseCharacterGuid(handler, args, characterGuid)) + return true; + + WorldSession* session = sWorld->FindClientlessSession(characterGuid); + if (!session) + { + handler->PSendSysMessage( + "No clientless session is registered for character GUID %u.", + characterGuid); + return true; + } + + uint32 accountId = session->GetAccountId(); + + if (!sWorld->RemoveClientlessSession(characterGuid)) + { + handler->PSendSysMessage( + "Clientless logout failed for character GUID %u.", + characterGuid); + return true; + } + + handler->PSendSysMessage( + "Clientless session removed for character GUID %u (account %u).", + characterGuid, accountId); + return true; + } + class VianoBotCommandScript : public CommandScript { public: @@ -594,9 +700,16 @@ namespace VianoBotCommands { "bot", rbac::RBAC_PERM_COMMAND_GM, false, nullptr, "", botCommands }, }; + static std::vector clientlessCommands = + { + { "login", rbac::RBAC_PERM_COMMAND_GM, false, &HandleClientlessLogin, "" }, + { "logout", rbac::RBAC_PERM_COMMAND_GM, false, &HandleClientlessLogout, "" }, + }; + static std::vector commandTable = { - { "viano", rbac::RBAC_PERM_COMMAND_GM, false, nullptr, "", vianoCommands }, + { "viano", rbac::RBAC_PERM_COMMAND_GM, false, nullptr, "", vianoCommands }, + { "clientless", rbac::RBAC_PERM_COMMAND_GM, false, nullptr, "", clientlessCommands }, }; return commandTable;