Harnais QA PlayerBot : 4 fixes du module bot + Z-fix et logs du runner artefacts

- PlayerBotSession : simulation de l ack MSG_MOVE_WORLDPORT pour un bot en jeu
  (IsBeingTeleportedFar) ; sans ca tout .tele name sur un bot restait bloque
- BotFieldAI : eviction hors instance gatee par la config pbotqa (harnais scenarios)
- Diagnostics QA-BOTLOG/QA-RUNLOG (login bot, holder async, cycle du runner)
- Runner artefacts : Z des spawns cale au sol via GetHeight avec repli sur l ancre,
  offsets resserres (plateformes type Skywall)
- Cause racine login bots : noms generes invalides (chiffres) rejetes par
  CheckPlayerName -> persos QA renommes en DB (Botqa/Botqb, compte 32)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
SylvaniaCore deploy
2026-07-22 12:57:14 +00:00
parent d3c0436ad5
commit f783cfd073
5 changed files with 54 additions and 6 deletions
@@ -16,6 +16,7 @@
*/ */
#include "BotFieldAI.h" #include "BotFieldAI.h"
#include "Config.h"
#include "MoveSplineInit.h" #include "MoveSplineInit.h"
#include "BotBGAIMovement.h" #include "BotBGAIMovement.h"
#include "PlayerBotMgr.h" #include "PlayerBotMgr.h"
@@ -269,8 +270,12 @@ bool BotFieldAI::ProcessGroupInvite()
return false; return false;
if (me->IsInWorld() && me->GetMap()->IsDungeon()) if (me->IsInWorld() && me->GetMap()->IsDungeon())
{ {
BotUtility::TryTeleportHome(this); // pbotqa=1 : harnais QA, autorise les bots field a rester en instance
return true; if (!sConfigMgr->GetIntDefault("pbotqa", 0))
{
BotUtility::TryTeleportHome(this);
return true;
}
} }
Group* pGroup = me->GetGroupInvite(); Group* pGroup = me->GetGroupInvite();
if (!pGroup) if (!pGroup)
@@ -870,14 +870,19 @@ void WorldSession::HandleContinuePlayerLogin()
std::shared_ptr<LoginQueryHolder> holder = std::make_shared<LoginQueryHolder>(GetAccountId(), m_playerLoading); std::shared_ptr<LoginQueryHolder> holder = std::make_shared<LoginQueryHolder>(GetAccountId(), m_playerLoading);
if (!holder->Initialize()) if (!holder->Initialize())
{ {
TC_LOG_ERROR("server.worldserver", "QA-BOTLOG2: holder Initialize KO compte %u", GetAccountId()); // QA-BOTLOG2
m_playerLoading.Clear(); m_playerLoading.Clear();
return; return;
} }
if (IsBotSession())
TC_LOG_ERROR("server.worldserver", "QA-BOTLOG2: holder pose compte %u", GetAccountId());
SendPacket(WorldPackets::Auth::ResumeComms(CONNECTION_TYPE_INSTANCE).Write()); SendPacket(WorldPackets::Auth::ResumeComms(CONNECTION_TYPE_INSTANCE).Write());
AddQueryHolderCallback(CharacterDatabase.DelayQueryHolder(holder)).AfterComplete([this](SQLQueryHolderBase const& holder) AddQueryHolderCallback(CharacterDatabase.DelayQueryHolder(holder)).AfterComplete([this](SQLQueryHolderBase const& holder)
{ {
if (IsBotSession())
TC_LOG_ERROR("server.worldserver", "QA-BOTLOG2: callback holder compte %u", GetAccountId());
HandlePlayerLogin(dynamic_cast<LoginQueryHolder const&>(holder)); HandlePlayerLogin(dynamic_cast<LoginQueryHolder const&>(holder));
}); });
} }
@@ -910,6 +915,7 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder const& holder)
// "GetAccountId() == db stored account id" checked in LoadFromDB (prevent login not own character using cheating tools) // "GetAccountId() == db stored account id" checked in LoadFromDB (prevent login not own character using cheating tools)
if (!pCurrChar->LoadFromDB(playerGuid, holder)) if (!pCurrChar->LoadFromDB(playerGuid, holder))
{ {
TC_LOG_ERROR("server.worldserver", "QA-BOTLOG3: LoadFromDB KO pour %s compte %u", playerGuid.ToString().c_str(), GetAccountId()); // QA-BOTLOG3
SetPlayer(NULL); SetPlayer(NULL);
KickPlayer(); // disconnect client, player no set to session and it will not deleted or saved at kick KickPlayer(); // disconnect client, player no set to session and it will not deleted or saved at kick
delete pCurrChar; // delete it manually delete pCurrChar; // delete it manually
@@ -1722,9 +1722,15 @@ bool PlayerBotMgr::LoginBotByAccountIndex(uint32 account, uint32 index)
#ifndef INCOMPLETE_BOT #ifndef INCOMPLETE_BOT
PlayerBotBaseInfo* botInfo = GetPlayerBotAccountInfo(account); PlayerBotBaseInfo* botInfo = GetPlayerBotAccountInfo(account);
if (!botInfo) if (!botInfo)
{
TC_LOG_ERROR("server.worldserver", "QA-BOTLOG: pas de botInfo pour compte %u", account); // QA-BOTLOG
return false; return false;
}
if (index >= botInfo->characters.size()) if (index >= botInfo->characters.size())
{
TC_LOG_ERROR("server.worldserver", "QA-BOTLOG: compte %u index %u >= %u persos", account, index, (uint32)botInfo->characters.size());
return false; return false;
}
for (auto itChar = botInfo->characters.begin(); for (auto itChar = botInfo->characters.begin();
itChar != botInfo->characters.end(); itChar != botInfo->characters.end();
itChar++) itChar++)
@@ -1738,7 +1744,15 @@ bool PlayerBotMgr::LoginBotByAccountIndex(uint32 account, uint32 index)
WorldSession* pWorldSession = sWorld->FindSession(account); WorldSession* pWorldSession = sWorld->FindSession(account);
PlayerBotSession* pSession = dynamic_cast<PlayerBotSession*>(pWorldSession); PlayerBotSession* pSession = dynamic_cast<PlayerBotSession*>(pWorldSession);
if (!pSession || pSession->PlayerLoading() || pSession->HasSchedules() || pSession->GetPlayer()) if (!pSession || pSession->PlayerLoading() || pSession->HasSchedules() || pSession->GetPlayer())
{
TC_LOG_ERROR("server.worldserver", "QA-BOTLOG: compte %u session=%d cast=%d loading=%d schedules=%d player=%d",
account, pWorldSession ? 1 : 0, pSession ? 1 : 0,
pSession ? (int)pSession->PlayerLoading() : -1,
pSession ? (int)pSession->HasSchedules() : -1,
(pSession && pSession->GetPlayer()) ? 1 : 0);
return false; return false;
}
TC_LOG_ERROR("server.worldserver", "QA-BOTLOG: schedule Online_GUID pousse pour guid %u", (uint32)charInfo.guid);
BotGlobleSchedule schedule1(BotGlobleScheduleType::BGSType_Online_GUID, charInfo.guid); BotGlobleSchedule schedule1(BotGlobleScheduleType::BGSType_Online_GUID, charInfo.guid);
pSession->PushScheduleToQueue(schedule1); pSession->PushScheduleToQueue(schedule1);
return true; return true;
@@ -163,6 +163,15 @@ void PlayerBotSession::ProcessNoWorld(uint32 diff)
if (!player) if (!player)
return; return;
// Un client reel confirme le changement de monde par MSG_MOVE_WORLDPORT_ACK ;
// sans cette simulation, un bot en jeu vise par .tele reste bloque sur le semaphore.
if (player->IsBeingTeleportedFar())
{
HandleMoveWorldportAck();
m_NoWorldTick = 500;
return;
}
if (player->IsInWorld()) if (player->IsInWorld())
{ {
m_NoWorldTick = 0; m_NoWorldTick = 0;
@@ -226,6 +235,7 @@ void PlayerBotSession::CastSchedule(uint32 diff)
break; break;
case BGSType_Online_GUID: case BGSType_Online_GUID:
result = ProcessOnlineByGUID(schedule); result = ProcessOnlineByGUID(schedule);
TC_LOG_ERROR("server.worldserver", "QA-BOTLOG: ProcessOnlineByGUID resultat=%d", (int)result); // QA-BOTLOG
break; break;
case BGSType_Offline: case BGSType_Offline:
result = ProcessOffline(schedule); result = ProcessOffline(schedule);
@@ -99,6 +99,7 @@ struct scenario_artifact_runner : public InstanceScript
{ {
SetBossNumber(12); SetBossNumber(12);
config = ArtifactRunner::GetConfig(instance->GetId()); config = ArtifactRunner::GetConfig(instance->GetId());
TC_LOG_ERROR("server.worldserver", "QA-RUNLOG: Initialize map %u config=%d", instance->GetId(), config ? 1 : 0); // QA-RUNLOG
stage = 0; stage = 0;
aliveCount = 0; aliveCount = 0;
introDone = false; introDone = false;
@@ -109,6 +110,7 @@ struct scenario_artifact_runner : public InstanceScript
InstanceScript::OnPlayerEnter(player); InstanceScript::OnPlayerEnter(player);
PhasingHandler::AddPhase(player, 169, true); PhasingHandler::AddPhase(player, 169, true);
TC_LOG_ERROR("server.worldserver", "QA-RUNLOG: OnPlayerEnter map %u introDone=%d config=%d", instance->GetId(), (int)introDone, config ? 1 : 0);
if (!introDone && config) if (!introDone && config)
{ {
introDone = true; introDone = true;
@@ -144,6 +146,7 @@ struct scenario_artifact_runner : public InstanceScript
return; return;
} }
TC_LOG_ERROR("server.worldserver", "QA-RUNLOG: StartStage %u map %u", (uint32)newStage, instance->GetId());
stage = newStage; stage = newStage;
aliveCount = 0; aliveCount = 0;
stageEntries.clear(); stageEntries.clear();
@@ -162,11 +165,21 @@ struct scenario_artifact_runner : public InstanceScript
} }
for (uint8 i = 0; i < s.count; ++i) for (uint8 i = 0; i < s.count; ++i)
{ {
float dx = (i % 3) * 6.0f - 6.0f; float dx = (i % 3) * 4.0f - 4.0f;
float dy = (i / 3) * 6.0f - 3.0f; float dy = (i / 3) * 4.0f - 2.0f;
Position pos = { s.x + dx + 12.0f, s.y + dy + 8.0f, s.z, s.o }; Position pos = { s.x + dx + 6.0f, s.y + dy + 4.0f, s.z, s.o };
if (TempSummon* summon = instance->SummonCreature(s.entry, pos)) // cale le Z au sol : les ancres sont sures mais les offsets peuvent sortir des plateformes
float gz = instance->GetHeight(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ() + 8.0f, true, 60.0f);
if (gz > INVALID_HEIGHT && std::abs(gz - s.z) < 25.0f)
pos.m_positionZ = gz + 0.5f;
else
pos.Relocate(s.x, s.y, s.z); // repli : pile sur l ancre officielle
TempSummon* summon = instance->SummonCreature(s.entry, pos);
if (!summon)
TC_LOG_ERROR("server.worldserver", "QA-RUNLOG: summon KO entry %u map %u", s.entry, instance->GetId());
if (summon)
{ {
TC_LOG_ERROR("server.worldserver", "QA-RUNLOG: summon POS entry %u (%.1f, %.1f, %.1f)", s.entry, summon->GetPositionX(), summon->GetPositionY(), summon->GetPositionZ());
if (s.level) if (s.level)
{ {
summon->SetLevel(s.level); summon->SetLevel(s.level);