Add preparation outings and equipment checks with a five-minute return to the meeting point. Correct static portal visitor casting and level conditions, with native interaction diagnostics. Recover suspended flying mounts, walk to verified takeoff sites, and validate landing and return volumes. Include SQL migrations, targeted regression tests and live validation checkpoints.
130 lines
7.6 KiB
Python
130 lines
7.6 KiB
Python
"""Exercise real departure admission/ground relocation against layered terrain."""
|
|
from pathlib import Path
|
|
import subprocess,tempfile
|
|
root=Path(__file__).resolve().parents[2]
|
|
s=(root/'src/server/game/World/ClientlessFlightMgr.cpp').read_text()
|
|
a=s.index('uint32 existingMount=0;');b=s.index(' bool foundLanding',a)
|
|
admission=s[a:b]
|
|
a=s.index('bool ClientlessFlightMgr::ApproachDeparture(');b=s.index('\nvoid ClientlessFlightMgr::Fail(',a)
|
|
approach=s[a:b]
|
|
a=s.index(' bool OpenColumn(');b=s.index(' char const * StateName',a)
|
|
column=s[a:b]
|
|
a=s.index(' if(!airborne)\n');b=s.index(' record.Status.State = ClientlessFlightState::Mounting;',a)
|
|
dismount=s[a:b]
|
|
a=s.index(' auto floor = sample(current.X, current.Y);');b=s.index(' player->StopMoving();',a)
|
|
touchdown=s[a:b]
|
|
a=s.index(' FindReturnLanding(player,record);');b=s.index(' record.Status.MountSpell=existingMount;',a)
|
|
return_anchor=s[a:b]
|
|
a=s.index('bool ClientlessFlightMgr::FindReturnLanding(');b=s.index('bool ClientlessFlightMgr::ApproachDeparture(',a)
|
|
find_return=s[a:b]
|
|
code=r'''
|
|
#include "ClientlessFlightPath.h"
|
|
#include <cassert>
|
|
#include <string>
|
|
#include <unordered_map>
|
|
#include <cstdint>
|
|
using uint32=unsigned;using namespace ClientlessFlightPath;
|
|
#define TC_LOG_WARN(...) ((void)0)
|
|
#define TC_LOG_INFO(...) ((void)0)
|
|
constexpr float INVALID_HEIGHT=-100000;constexpr unsigned SPELL_AURA_MOUNTED=1;
|
|
struct Position{float x=0,y=0,z=0,o=0;
|
|
float GetPositionX()const{return x;}float GetPositionY()const{return y;}float GetPositionZ()const{return z;}float GetOrientation()const{return o;}
|
|
void Relocate(float a,float b,float c,float d){x=a;y=b;z=c;o=d;}};
|
|
struct Guid{unsigned GetCounter()const{return 84;}};
|
|
struct Map{float feet=0;float GetHeight(int,float,float,float,bool,float){return feet;}}map;
|
|
struct Player:Position{bool mounted=false,fly=false,aura=false;int removals=0;
|
|
Guid GetGUID(){return {};}unsigned GetMapId(){return 530;}int GetPhaseShift(){return 0;}Map* GetMap(){return ↦}
|
|
bool IsMounted(){return mounted;}bool CanFly(){return fly;}bool HasAura(unsigned){return aura;}
|
|
void RemoveAurasByType(unsigned){++removals;mounted=fly=false;}};
|
|
Point PointOf(Position const&p){return {p.x,p.y,p.z};}
|
|
enum class ClientlessFlightState{Mounting,Flying,Arrived,Failed};
|
|
struct Record{struct{Position Target;ClientlessFlightState State=ClientlessFlightState::Failed;bool FollowingPlayer=false;std::string Detail;}Status;
|
|
bool ApproachingDeparture=false;Position Departure,Start;ClientlessFlightPath::Settings Settings;};
|
|
struct ClientlessPathDiagnostics{bool Calculated=true,Complete=true,Suspicious=false;float FinalDistance=0,PathLength=15,MaxSegmentLength=4,MaxZDelta=1;};
|
|
struct Travel{ClientlessPathDiagnostics nav;bool start=true;int starts=0,probes=0;
|
|
bool AnalyzePath(Player*,Position const&,ClientlessPathDiagnostics& d){++probes;d=nav;return true;}
|
|
bool StartTravel(Player*,Position const&,bool){++starts;return start;}}travel;
|
|
auto sClientlessTravelMgr=&travel;
|
|
struct Areas{bool allowed=true;bool AllowsSegment(Player*,unsigned,Position const&,Position const&){return allowed;}}areas;
|
|
auto sAdventureAreaMgr=&areas;
|
|
struct Lua{int calls=0;void DismountGroundMount(Player*,char const*){++calls;}}lua;
|
|
auto sClientlessLuaEngine=&lua;
|
|
bool clear=true,narrow=false,columnBlocked=false;
|
|
bool ClearRay(Player*,Point const&a,Point const&b){
|
|
if(!clear||(narrow&&std::fabs(a.Y)>=0.01f))return false;
|
|
if(columnBlocked)for(int i=0;i<=80;++i){auto p=Mix(a,b,i/80.f);if(std::fabs(p.X)<1&&std::fabs(p.Y)<1&&p.Z>3&&p.Z<5)return false;}
|
|
return true;
|
|
}
|
|
'''+column+r'''
|
|
struct ClientlessFlightMgr{
|
|
std::unordered_map<unsigned,Record>_records;Surface surface{0,300,true};int approached=0;bool seek=false;
|
|
Surface Sample(Player*,Record&,float,float){return surface;}
|
|
bool ApproachDeparture(Player*,Record&,bool);bool FindReturnLanding(Player*,Record&);
|
|
bool Admit(Player* player,Record&record,std::string&error,bool following=false){
|
|
auto origin=surface;std::vector<std::pair<unsigned,unsigned>>candidates{{123,1}};
|
|
'''+admission+r'''
|
|
return true;
|
|
}
|
|
void ReturnAnchor(Player*player,Record&record){auto origin=surface;
|
|
'''+return_anchor+r'''
|
|
}
|
|
void Fail(Player*,Record&,std::string const&){}
|
|
bool Touchdown(Player*player){auto current=PointOf(*player);Record record;auto sample=[&](float,float){return surface;};
|
|
'''+touchdown+r'''
|
|
return true;
|
|
}
|
|
void KeepMount(Player*player,bool airborne){
|
|
'''+dismount+r'''
|
|
}
|
|
};
|
|
'''+find_return+approach+r'''
|
|
int main(){
|
|
ClientlessFlightMgr mgr;Player p;Record r;std::string error;r.Status.Target={100,0,0};
|
|
// A normal supported open-air departure remains valid.
|
|
assert(mgr.Admit(&p,r,error));
|
|
// Brynli: a native flying mount already suspended ten yards above terrain.
|
|
p.z=10;p.mounted=p.fly=p.aura=true;map.feet=INVALID_HEIGHT;
|
|
assert(mgr.Admit(&p,r,error));assert(mgr._records.empty());
|
|
r.Start=p;mgr.ReturnAnchor(&p,r);assert(r.Start.z==0);
|
|
narrow=true;r.Start=p;mgr.ReturnAnchor(&p,r);assert(r.Start.z==10);narrow=false;
|
|
columnBlocked=true;r.Start=p;mgr.ReturnAnchor(&p,r);assert(r.Start.x>1&&r.Start.z==0&&p.x==0&&p.z==10);
|
|
areas.allowed=false;r.Start=p;mgr.ReturnAnchor(&p,r);assert(r.Start.z==10);areas.allowed=true;columnBlocked=false;
|
|
mgr.KeepMount(&p,true);assert(p.mounted&&p.fly&&p.removals==0&&lua.calls==0);
|
|
// Airborne recovery never applies to an unmounted/ground-only bot.
|
|
p.fly=false;assert(!mgr.Admit(&p,r,error));assert(error.find("departure-unavailable:")==0);
|
|
p.fly=true;p.aura=false;assert(!mgr.Admit(&p,r,error));p.aura=true;
|
|
clear=false;assert(!mgr.Admit(&p,r,error));clear=true;
|
|
mgr.surface.Ceiling=12;assert(!mgr.Admit(&p,r,error));mgr.surface.Ceiling=300;
|
|
// Tholgar: grounded on a lower layer, while the sky sample sees an overhead floor.
|
|
p.z=0;p.mounted=p.fly=p.aura=false;map.feet=0;mgr.surface.Ground=12;
|
|
assert(mgr.Admit(&p,r,error));auto saved=mgr._records.at(84);
|
|
assert(saved.ApproachingDeparture&&saved.Status.State==ClientlessFlightState::Mounting);
|
|
assert(saved.Status.Target.x==100&&p.x==0&&p.z==0&&travel.starts==1);
|
|
// A roof, forbidden ground corridor, partial MMAP path, cliff or failed movement
|
|
// must never manufacture a departure or move the player through the obstruction.
|
|
mgr._records.clear();travel.starts=0;clear=false;
|
|
assert(!mgr.Admit(&p,r,error)&&mgr._records.empty()&&travel.starts==0);clear=true;
|
|
narrow=true;assert(!mgr.Admit(&p,r,error));narrow=false;
|
|
areas.allowed=false;assert(!mgr.Admit(&p,r,error));areas.allowed=true;
|
|
travel.nav.Complete=false;assert(!mgr.Admit(&p,r,error));travel.nav.Complete=true;
|
|
travel.nav.MaxZDelta=20;assert(!mgr.Admit(&p,r,error));travel.nav.MaxZDelta=1;
|
|
travel.nav.PathLength=200;assert(!mgr.Admit(&p,r,error));travel.nav.PathLength=15;
|
|
travel.start=false;assert(!mgr.Admit(&p,r,error));travel.start=true;
|
|
map.feet=INVALID_HEIGHT;assert(!mgr.Admit(&p,r,error));
|
|
// A touchdown may use the actual lower floor, never a roof above it.
|
|
map.feet=0;p.z=0;mgr.surface.Ground=12;
|
|
assert(OpenColumn(&p,0,0,{0,300,true}));narrow=true;assert(!OpenColumn(&p,0,0,{0,300,true}));narrow=false;
|
|
assert(!OpenColumn(&p,0,0,{0,9,true}));assert(!OpenColumn(&p,0,0,{0,300,false}));
|
|
assert(mgr.Touchdown(&p));
|
|
p.z=1.2f;assert(!mgr.Touchdown(&p));p.z=0;
|
|
map.feet=INVALID_HEIGHT;assert(!mgr.Touchdown(&p));map.feet=0;
|
|
clear=false;assert(!mgr.Touchdown(&p));clear=true;
|
|
mgr.KeepMount(&p,false);assert(p.removals==1&&lua.calls==1);
|
|
}
|
|
'''
|
|
with tempfile.TemporaryDirectory(prefix='vcore-flight-departure-') as d:
|
|
p=Path(d);(p/'test.cpp').write_text(code)
|
|
subprocess.run(['c++','-std=c++17','-I'+str(root/'src/server/game/World'),str(p/'test.cpp'),'-o',str(p/'test')],check=True)
|
|
subprocess.run([str(p/'test')],check=True)
|
|
print('Production flight admission: airborne mount retained, lower-floor MMAP departure, blocked/cliff/missing support rejected.')
|