Integrate safe bot shutdown and automatic login recovery

Drain clientless sessions during normal shutdown with a 60-second grace and recovery audit. Recover invalid bot login states while preserving real transports and taxis.

Handle bounded database reconnect failures with controlled service termination and clear OutdoorPvP references before shutdown destruction. Prevent obsolete transport actions from overriding newer movement.

Add regression coverage, live validation notes and the updated parallel -j10 build workflow in AGENTS.md. Full build, twelve regression tests and live login/shutdown/database-fault checks passed.
This commit is contained in:
Nico committed 2026-11-04 13:00:26 +01:00
1 parent ba2a4e629c
commit d1aceaf583
29 files changed
+1721 -142

No files matched your search

+29 -1
View File
@@ -2,6 +2,7 @@
#include "ClientlessLuaEngine.h"
#include "AdventureRotationPolicy.h"
#include "ClientlessPlayerMgr.h"
#include "ClientlessLoginRecovery.h"
#include "ClientlessActionExecutorMgr.h"
#include "ClientlessTravelMgr.h"
#include "ClientlessTransportMgr.h"
@@ -220,9 +221,32 @@ std::vector<ClientlessWeightedMount> ReadMountDictionary(lua_State* L, int movem
class ClientlessAdventureLuaController final : public ClientlessPlayerController
{
public:
bool PrepareOnline(Player* player, uint32 diff) override
{
if (!_profileLoaded)
{
sClientlessLuaEngine->LoadAdventureProfile(player);
_profileLoaded=true;
}
return ClientlessLoginRecovery::Update(player,_recovery,diff);
}
void OnSafeLogoutRequested(Player* player) override
{
_resumeEnabled=sAdventureBehaviorMgr->PauseForLogout(player);
}
void OnSafeLogoutCancelled(Player* player) override
{
sAdventureBehaviorMgr->ResumeAfterLogoutPause(player,_resumeEnabled);
}
void UpdateForSafeLogout(Player* player, uint32 diff) override
{
if (sClientlessTransportMgr->ResumePassenger(player)) return;
if (player->IsInCombat() || sAdventureCombatMgr->Busy(player))
sAdventureCombatMgr->Update(player,diff);
}
void OnPlayerOnline(Player* player) override
{
sClientlessLuaEngine->LoadAdventureProfile(player);
if (!_profileLoaded) sClientlessLuaEngine->LoadAdventureProfile(player);
AdventureSocialActions::Prepare(player);
sClientlessLuaEngine->ExecuteAdventureScript(player);
sAdventureBehaviorMgr->Online(player);
@@ -256,6 +280,10 @@ public:
{sAdventureCombatMgr->Revived(player,when);}
void OnDamageTaken(Player* player, Unit* attacker, uint32 damage) override
{ sAdventureCombatMgr->DamageTaken(player, attacker, damage); }
private:
bool _profileLoaded=false, _resumeEnabled=false;
ClientlessLoginRecovery::State _recovery;
public:
void OnPlayerLogout(Player* player) override
{ sClientlessLuaEngine->ForgetWorldPresence(player->GetGUID().GetCounter()); sAdventurePopulationMgr->Offline(player); sAdventureInteractionMgr->Offline(player); sAdventureSupplyMgr->Offline(player); sAdventureCombatMgr->Offline(player); sAdventureBehaviorMgr->Offline(player); }
};