core: add clientless player GM test adapter
GCC PCH / build (push) Canceled after 0s
clang PCH / build (push) Canceled after 0s

This commit is contained in:
Nico committed 2026-10-12 12:51:09 +00:00
1 parent fe96d310d6
commit 7013087bcd
1 file changed
+113
@@ -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 <cstdlib>
#include <string>
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 <characterGuid> or .clientless logout <characterGuid>");
return false;
}
while (*args == ' ' || *args == '\t')
++args;
if (!*args)
{
handler->SendSysMessage("Usage: .clientless login <characterGuid> or .clientless logout <characterGuid>");
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<ChatCommand> clientlessCommands =
{
{ "login", rbac::RBAC_PERM_COMMAND_GM, false, &HandleClientlessLogin, "" },
{ "logout", rbac::RBAC_PERM_COMMAND_GM, false, &HandleClientlessLogout, "" },
};
static std::vector<ChatCommand> commandTable =
{
{ "viano", rbac::RBAC_PERM_COMMAND_GM, false, nullptr, "", vianoCommands },
{ "clientless", rbac::RBAC_PERM_COMMAND_GM, false, nullptr, "", clientlessCommands },
};
return commandTable;