Files
Viano-Core/tests/clientless/test_flight_policy.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

145 lines
9.9 KiB
Python

"""Compile production flight eligibility/cost and fail-safe abort decisions with Core doubles."""
from pathlib import Path
import subprocess,tempfile
root=Path(__file__).resolve().parents[2]
source=(root/'src/server/game/World/ClientlessFlightMgr.cpp').read_text()
def function(signature):
a=source.index(signature);opening=source.index('{',a);depth=1;b=opening+1
while depth:
depth+=(source[b]=='{')-(source[b]=='}');b+=1
return source[a:b]
harness=r'''
#include "ClientlessFlightPath.h"
#include <cassert>
#include <memory>
#include <cstdint>
#include <string>
#include <vector>
#include <sstream>
#include <unordered_set>
#include <unordered_map>
#include <limits>
using uint32=uint32_t;
using namespace ClientlessFlightPath;
#define TC_LOG_WARN(...) ((void)0)
constexpr int SKILL_RIDING=762,MAP_COMMON=0,SPELL_AURA_MOUNT_RESTRICTIONS=1;
struct Position{float x=0,y=0,z=0;float GetPositionX()const{return x;}float GetPositionY()const{return y;}float GetPositionZ()const{return z;}};
struct Player;
struct AreaAccess {bool allowed=true,preferred=false;
bool AllowsSegment(Player const*,uint32,Position const&,Position const&)const;
bool PreferredFlight(Player const*,uint32,Position const&)const;
};
Point PointOf(Position const&p){return {p.x,p.y,p.z};}float Infinity(){return std::numeric_limits<float>::infinity();}
struct Guid{uint32 GetCounter()const{return 26;}};
struct Player{
bool license=true,cold=true,learned=true,alive=true,canFly=true,restrictions=false;
uint32 skill=225,map=0,area=87;int stops=0,interrupts=0;
Guid GetGUID()const{return {};}
uint32 GetSkillValue(int)const{return skill;}
bool HasSpell(uint32 s)const{return s==90267?license:s==54197?cold:learned;}
uint32 GetMapId()const{return map;}uint32 GetAreaId()const{return area;}
bool HasAuraType(int)const{return restrictions;}
bool CanFly(){return canFly;}bool IsAlive(){return alive;}
void StopMoving(){++stops;}void InterruptNonMeleeSpells(bool){++interrupts;}
float GetPositionX(){return 0;}float GetPositionY(){return 0;}float GetPositionZ(){return 50;}
};
bool AreaAccess::AllowsSegment(Player const*,uint32,Position const&,Position const&)const{return allowed;}
bool AreaAccess::PreferredFlight(Player const*,uint32,Position const&)const{return preferred;}
AreaAccess access;auto sAdventureAreaMgr=&access;
struct Mount{uint32 DisplayId=32235,Weight=100;};
struct Profile{bool CanFreeFly=true;std::vector<Mount> FlightMounts{{}};} profile;
struct Lua{auto GetAdventureProfile(uint32){return &profile;}} lua;
struct Config{int reads=0;bool enabled=true;bool GetBoolDefault(const char*,bool){++reads;return enabled;}float GetFloatDefault(const char*,float v){++reads;return v;}std::string GetStringDefault(const char*,const char*v){++reads;return v;}} config;
auto sClientlessLuaEngine=&lua;auto sConfigMgr=&config;
struct DBCManager{static bool IsInArea(uint32 area,uint32 zone){return area==zone || (zone==4197&&area==4538);}};
struct Battlefields{bool war=false;bool IsWintergraspFlightAllowed(uint32 map,uint32 area){return map==571&&DBCManager::IsInArea(area,4197)&&!war;}} battlefield;auto sBattlefieldMgr=&battlefield;
struct SpellMgr{void* GetSpellInfo(uint32){return this;}} spells;auto sSpellMgr=&spells;
uint32 FlightType(void*){return 1;}
struct MapEntry{uint32 MapType=0;} entry;struct Maps{auto LookupEntry(uint32){return &entry;}} maps;auto& sMapStore=maps;
enum class AreaMountFlags{AllowFlyingMounts};
struct Flags{bool fly=true;bool HasFlag(AreaMountFlags){return fly;}};
struct Area{bool fly=true;uint32 World_pvp_ID=0;Flags GetMountFlags()const{return {fly};}} area;
struct Areas{bool known=true;auto LookupEntry(uint32){return known?&area:nullptr;}} areas;auto& sAreaTableStore=areas;
enum class ClientlessFlightState{Mounting,Flying,Arrived,Failed};
struct Record{std::shared_ptr<ClientlessFlightPath::SharedTrail>Published=std::make_shared<ClientlessFlightPath::SharedTrail>();
struct{bool FollowingPlayer=false;ClientlessFlightState State=ClientlessFlightState::Flying;uint32 MapId=0;Position Landing;std::string Detail;}Status;
ClientlessFlightPath::Memory Memory;Position Start;bool LandingRecovery=false;uint32 NextLandingSearch=0,LandingFailuresResetAt=0,Elapsed=0;std::vector<Position>RejectedLandings;std::shared_ptr<ClientlessFlightPath::SharedTrail>Following;
bool Moving=true,Returning=false,ApproachingDeparture=false;std::vector<Position> Breadcrumbs{{}};std::string AbortReason;
};
struct Travel{int cancels=0;void CancelTravel(uint32){++cancels;}}travel;auto sClientlessTravelMgr=&travel;
class ClientlessFlightMgr{public:
Player const* _planningPlayer=nullptr;bool _planningEnabled=false;float _planningMinDistance=600;
std::unordered_set<uint32> _planningPreferredZones;
std::unordered_map<int,int> _planningAreas,_planningTerrain;
void BeginPlanning(Player const* = nullptr);
uint32 areaCode=87,zoneCode=12;
std::pair<uint32,uint32> AreaZone(Player const*,uint32,Position const&)const{return {areaCode,zoneCode};}
bool Enabled(Player const*)const;bool Preferred(Player const*,uint32,Position const&)const;
float Estimate(Player const*,uint32,Position const&,Position const&,bool recovery=false)const;
bool FindReturnLanding(Player*,Record&){return false;}
void Fail(Player*,Record&,std::string const&);
};
'''
for signature in ('void ClientlessFlightMgr::BeginPlanning(', 'bool ClientlessFlightMgr::Enabled(', 'bool ClientlessFlightMgr::Preferred(', 'float ClientlessFlightMgr::Estimate(', 'void ClientlessFlightMgr::Fail('):
harness+=function(signature)+'\n'
harness+=r'''
int main(){
ClientlessFlightMgr mgr;Player p;Position a,b;b.x=1000;
float roadBias=mgr.Estimate(&p,0,a,b);assert(roadBias>1000&&std::isfinite(roadBias));
access.allowed=false;assert(!std::isfinite(mgr.Estimate(&p,0,a,b)));access.allowed=true;
access.preferred=true;assert(mgr.Estimate(&p,0,a,b)<roadBias);access.preferred=false;
p.license=false;assert(!std::isfinite(mgr.Estimate(&p,0,a,b)));p.license=true;
p.cold=false;assert(!std::isfinite(mgr.Estimate(&p,571,a,b)));p.cold=true;
p.skill=150;assert(!mgr.Enabled(&p));p.skill=225;
p.learned=false;assert(!mgr.Enabled(&p));p.learned=true;
profile.CanFreeFly=false;assert(!mgr.Enabled(&p));profile.CanFreeFly=true;
entry.MapType=1;assert(!std::isfinite(mgr.Estimate(&p,0,a,b)));entry.MapType=0;
// Eversong/Ghostlands and Deeprun use native mount flags 13, without bit 2.
area.fly=false;assert(!std::isfinite(mgr.Estimate(&p,530,a,b)));
assert(!std::isfinite(mgr.Estimate(&p,369,a,b)));
area.fly=true;mgr.zoneCode=210;
assert(mgr.Estimate(&p,571,a,b)<roadBias); // explicit zone preference
b.x=90;assert(std::isfinite(mgr.Estimate(&p,571,a,b)));
mgr.zoneCode=12;assert(!std::isfinite(mgr.Estimate(&p,0,a,b)));
// Recovery ignores normal RP minimum distance and zone preference, not native permissions.
assert(std::isfinite(mgr.Estimate(&p,0,a,b,true)));
p.license=false;assert(!std::isfinite(mgr.Estimate(&p,0,a,b,true)));p.license=true;
area.fly=false;assert(!std::isfinite(mgr.Estimate(&p,0,a,b,true)));area.fly=true;
b.x=21000;assert(!std::isfinite(mgr.Estimate(&p,0,a,b)));
assert(std::isfinite(mgr.Estimate(&p,0,a,b,true)));
// Unknown metadata is not an invented blanket prohibition; actual native
// mount capability/cast at departure still decides in Start().
areas.known=false;b.x=1000;assert(std::isfinite(mgr.Estimate(&p,0,a,b)));areas.known=true;
area.fly=false;area.World_pvp_ID=1;assert(std::isfinite(mgr.Estimate(&p,571,a,b)));area.World_pvp_ID=0;
// An airborne abort first returns. A blocked return must not dismount/drop.
Record r;mgr.Fail(&p,r,"blocked");assert(r.Returning&&r.Status.State==ClientlessFlightState::Flying&&p.stops==1);
mgr.Fail(&p,r,"reverse blocked");assert(r.Status.State==ClientlessFlightState::Flying&&r.LandingRecovery&&r.NextLandingSearch==10000);
Record mounting;mounting.Status.State=ClientlessFlightState::Mounting;mgr.Fail(&p,mounting,"cast rejected");
assert(mounting.Status.State==ClientlessFlightState::Failed&&p.interrupts==1&&!mounting.Returning);
// A planning scope snapshots repeated config/profile work, while actual
// departure checks and per-map licenses remain live.
profile.CanFreeFly=true;p.skill=225;p.learned=true;p.license=true;config.enabled=true;
area.fly=true;areas.known=true;p.restrictions=false;mgr.zoneCode=12;b.x=1000;
mgr.BeginPlanning(&p);int reads=config.reads;
for(int i=0;i<1000;++i)assert(std::isfinite(mgr.Estimate(&p,0,a,b)));
assert(config.reads==reads);
p.license=false;assert(!std::isfinite(mgr.Estimate(&p,0,a,b)));p.license=true;
profile.CanFreeFly=false;assert(!mgr.Enabled(&p));
mgr.BeginPlanning();assert(!std::isfinite(mgr.Estimate(&p,0,a,b)));
profile.CanFreeFly=true;
// Static Wintergrasp subareas lack flight flags, but peace permits flight.
mgr.areaCode=4538;mgr.zoneCode=4197;area.fly=false;p.cold=true;
assert(std::isfinite(mgr.Estimate(&p,571,a,b)));
battlefield.war=true;assert(!std::isfinite(mgr.Estimate(&p,571,a,b)));
battlefield.war=false;assert(std::isfinite(mgr.Estimate(&p,571,a,b)));
mgr.areaCode=87;mgr.zoneCode=12;assert(!std::isfinite(mgr.Estimate(&p,571,a,b)));area.fly=true;
int beforeInterrupts=p.interrupts;Record approach;approach.ApproachingDeparture=true;approach.Status.State=ClientlessFlightState::Mounting;mgr.Fail(&p,approach,"interrupted");assert(travel.cancels==1&&!approach.ApproachingDeparture&&approach.Status.State==ClientlessFlightState::Failed&&p.interrupts==beforeInterrupts);
Record revoked;p.canFly=false;mgr.Fail(&p,revoked,"permission lost");assert(revoked.Status.State==ClientlessFlightState::Failed&&!revoked.Returning);
}
'''
with tempfile.TemporaryDirectory(prefix='vcore-flight-policy-') as folder:
cpp=Path(folder)/'test.cpp';binary=Path(folder)/'test';cpp.write_text(harness)
subprocess.run(['c++','-include',str(Path(__file__).with_name('telemetry_test_stub.h')),'-std=c++17','-I',str(root/'src/server/game/World'),str(cpp),'-o',str(binary)],check=True)
subprocess.run([str(binary)],check=True)
print('Flight native eligibility, license/profile/zone policy, RP costs and fail-safe return decisions passed.')