Files
Viano-Core/tests/clientless/test_instance_browser_reentry.py
T
Nico 3aa780662e Complete AdventureBot navigation, instance travel and shutdown fixes
Finish capital waiting travel and adaptive flight entry up to 10,000 yards.
Preserve checked vertical climbs, recover blocked ground departures and find
validated dry landings. Retain group routes and Undercity arrival constraints.

Restore defense from native combat references, coordinate instance rendezvous
and browser reentry, finalize clientless sessions before map destruction and
transfer Halaa capture-point ownership safely.

Include the associated regression tests, investigation reports and reusable
diagnostic scripts. Keep generated runtime evidence and server binaries local
through scoped ignore rules. Validation/build/live evidence is recorded in the
session checkpoint and individual reports.
2026-11-05 10:35:34 +01:00

61 lines
3.9 KiB
Python

"""Execute production LFG re-entry path, including native denial and retry pacing."""
from pathlib import Path
import subprocess, tempfile
root = Path(__file__).resolve().parents[2]
s = (root/'src/server/game/World/AdventureEncounterMgr.cpp').read_text()
a = s.index('bool AdventureEncounterMgr::FollowIntoInstance(')
b = s.index(' AreaTriggerEntry const* entrance=', a)
# The physical-portal fallback is independent: exercise the complete browser
# branch and its real prerequisites without fabricating world/graph geometry.
code = r'''
#include <cassert>
#include <ctime>
#include <unordered_map>
using uint32=unsigned;
#define TC_LOG_INFO(...) ((void)0)
namespace GameTime{time_t now=100;time_t GetGameTime(){return now;}}
struct Guid{unsigned id;unsigned GetCounter(){return id;}};
struct Map{bool dungeon=false;bool IsDungeon(){return dungeon;}};
struct Player;
struct Ref{Player*p;Ref*following=nullptr;Player*GetSource(){return p;}Ref*next(){return following;}};
struct Group{bool lfg=true;Ref*first=nullptr;bool isLFGGroup(){return lfg;}Ref*GetFirstMember(){return first;}Guid GetGUID(){return {9};}}group;
struct Session{Player*p;bool bot=true;unsigned acks=0;bool IsClientless(){return bot;}void CompleteClientlessTeleport();};
struct Player{unsigned id,map=0,instance=0;bool combat=false,pending=false,alive=true;Map terrain;Session session{this};
bool IsInCombat(){return combat;}bool IsBeingTeleported(){return pending;}bool IsAlive(){return alive;}
Group*GetGroup(){return &group;}Guid GetGUID(){return {id};}unsigned GetMapId(){return map;}unsigned GetInstanceId(){return instance;}
Session*GetSession(){return &session;}Map*GetMap(){return &terrain;}
};
void Session::CompleteClientlessTeleport(){++acks;p->pending=false;p->map=645;p->instance=3;}
struct Dungeon{int map=645;}dungeon;
struct LFG{bool present=true,allowed=true;unsigned attempts=0;unsigned GetDungeon(Guid g){assert(g.id==9);return 123;}
Dungeon*GetLFGDungeon(unsigned id){assert(id==123);return present?&dungeon:nullptr;}
void TeleportPlayer(Player*p,bool out){assert(!out);++attempts;if(allowed)p->pending=true;}
}lfg;auto sLFGMgr=&lfg;
struct AdventureEncounterMgr{std::unordered_map<unsigned,time_t>_entryAttempts;bool mixed=true;
bool MixedGroup(Player*){return mixed;}bool FollowIntoInstance(Player*);
};
''' + s[a:b] + ' return false;\n}\n' + r'''
int main(){
Player bot{121},human{6};human.session.bot=false;human.map=645;human.terrain.dungeon=true;
Ref h{&human};group.first=&h;AdventureEncounterMgr mgr;
// Native LFG denial is respected; no administrator teleport bypass.
lfg.allowed=false;assert(mgr.FollowIntoInstance(&bot)&&lfg.attempts==1&&bot.map==0&&bot.session.acks==0);
assert(mgr.FollowIntoInstance(&bot)&&lfg.attempts==1);GameTime::now+=2;
assert(mgr.FollowIntoInstance(&bot)&&lfg.attempts==1);++GameTime::now;
lfg.allowed=true;assert(mgr.FollowIntoInstance(&bot)&&lfg.attempts==2&&bot.map==645&&bot.instance==3&&bot.session.acks==1&&!bot.pending);
// Missing/mismatched native dungeon data cannot silently choose a portal.
bot.map=0;GameTime::now+=3;lfg.present=false;assert(mgr.FollowIntoInstance(&bot)&&lfg.attempts==2);
lfg.present=true;human.map=36;assert(mgr.FollowIntoInstance(&bot)&&lfg.attempts==2);human.map=645;
bot.combat=true;assert(!mgr.FollowIntoInstance(&bot));bot.combat=false;
bot.pending=true;assert(!mgr.FollowIntoInstance(&bot));bot.pending=false;
human.terrain.dungeon=false;assert(!mgr.FollowIntoInstance(&bot));human.terrain.dungeon=true;
mgr.mixed=false;assert(!mgr.FollowIntoInstance(&bot));mgr.mixed=true;
group.lfg=false;assert(!mgr.FollowIntoInstance(&bot));assert(lfg.attempts==2);
}
'''
with tempfile.TemporaryDirectory() as directory:
p=Path(directory);(p/'test.cpp').write_text(code)
subprocess.run(['c++','-std=c++17',str(p/'test.cpp'),'-o',str(p/'test')],check=True)
subprocess.run([str(p/'test')],check=True)
print('Instance browser re-entry: native group selection, denial, 3s retry, clientless ACK and combat/transfer guards PASS')