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.
61 lines
3.9 KiB
Python
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')
|