Integrate transient flight alternatives with graph routing, native flying mounts, phased terrain and collision checks, bounded avoidance and confirmed landing. Add safe-return recovery, node and location integration, profile settings, diagnostic commands, regression tests and flight documentation.
68 lines
3.7 KiB
Python
68 lines
3.7 KiB
Python
"""Run the production 3D flight geometry against deterministic terrain/collisions."""
|
|
from pathlib import Path
|
|
import subprocess,tempfile
|
|
root=Path(__file__).resolve().parents[2]
|
|
harness=r'''
|
|
#include "ClientlessFlightPath.h"
|
|
#include <cassert>
|
|
#include <iostream>
|
|
using namespace ClientlessFlightPath;
|
|
struct Run {Point End;float Peak=0,Side=0;unsigned Steps=0,Avoidances=0;bool Arrived=false;};
|
|
Run simulate(Point start,Point target,Sample sample,Ray ray,int limit=500){
|
|
Settings cfg;Memory mem;mem.Departed=start.Z-sample(start.X,start.Y).Ground>cfg.Safety;Run r;Point p=start;
|
|
for(int i=0;i<limit;++i){
|
|
auto next=Next(p,target,cfg,mem,sample,ray);
|
|
if(!next.Valid)break;
|
|
assert(Corridor(p,next.Next,target,cfg,sample,ray,p.Z-sample(p.X,p.Y).Ground<cfg.Safety));
|
|
assert(next.Next.Z+5<=sample(next.Next.X,next.Next.Y).Ceiling);
|
|
p=next.Next;++r.Steps;r.Peak=std::max(r.Peak,p.Z);r.Side=std::max(r.Side,std::fabs(p.Y));r.Avoidances+=next.Avoiding;
|
|
if(Distance(p,target)<0.8f){r.Arrived=true;break;}
|
|
}
|
|
r.End=p;return r;
|
|
}
|
|
int main(){
|
|
auto flat=[](float,float){return Surface{0,300,true};};
|
|
auto clear=[](Point const&,Point const&){return true;};
|
|
auto normal=simulate({0,0,0},{800,0,0},flat,clear);
|
|
assert(normal.Arrived&&normal.Peak>30&&normal.Peak<=60.1f);
|
|
auto low=[](float,float){return Surface{0,42,true};};
|
|
auto ceiling=simulate({0,0,0},{800,0,0},low,clear);
|
|
assert(ceiling.Arrived&&ceiling.Peak<=36.1f);
|
|
auto peak=[](float x,float){return Surface{x>390&&x<400?40.0f:0.0f,300,true};};
|
|
auto smooth=simulate({0,0,0},{800,0,0},peak,clear);
|
|
assert(smooth.Arrived&&smooth.Peak<75); // no nominal clearance chase over short peak
|
|
auto wall=[](Point const&a,Point const&b){
|
|
for(int i=0;i<=80;++i){auto p=Mix(a,b,i/80.0f);if(p.X>=240&&p.X<=260&&std::fabs(p.Y)<16&&p.Z<110)return false;}return true;
|
|
};
|
|
auto side=simulate({0,0,0},{800,0,0},flat,wall);
|
|
assert(side.Arrived&&side.Avoidances>0&&side.Side>10);
|
|
auto wide=[](Point const&a,Point const&b){
|
|
for(int i=0;i<=80;++i){auto p=Mix(a,b,i/80.0f);if(p.X>=240&&p.X<=260&&std::fabs(p.Y)<500&&p.Z<95)return false;}return true;
|
|
};
|
|
auto climb=simulate({0,0,0},{800,0,0},flat,wide);
|
|
assert(climb.Arrived&&climb.Peak>95&&climb.Avoidances>0);
|
|
auto unknown=[](float x,float){return Surface{0,300,x<120};};
|
|
assert(!simulate({0,0,0},{800,0,0},unknown,clear).Arrived);
|
|
auto blocked=[](Point const&,Point const&){return false;};
|
|
assert(!simulate({0,0,0},{800,0,0},flat,blocked).Arrived);
|
|
// Missing/covered/wrong-floor landing is not an arrival.
|
|
auto invalidEnd=[](float x,float){return Surface{x>790?20.0f:0.0f,300,true};};
|
|
assert(!simulate({0,0,0},{800,0,0},invalidEnd,clear).Arrived);
|
|
auto shortFlight=simulate({0,0,0},{90,0,0},flat,clear);
|
|
assert(shortFlight.Arrived&&shortFlight.Peak>5);
|
|
// An avoidance may leave the bot high immediately above the landing site.
|
|
// Open a descending approach instead of oscillating over the target.
|
|
Memory landingMemory;landingMemory.Departed=true;
|
|
Point landingStart{660,0,60};
|
|
auto firstDescent=Next(landingStart,{800,0,0},Settings{},landingMemory,flat,clear);
|
|
assert(firstDescent.Valid&&firstDescent.Next.X>660&&firstDescent.Next.Z<60);
|
|
auto highApproach=simulate({0,0,70},{1,0,0},flat,clear);
|
|
assert(highApproach.Arrived&&highApproach.Steps<20&&highApproach.Peak<=70);
|
|
std::cout<<"Flight geometry passed: takeoff/landing, smoothed peak, ceiling, lateral/climbing avoidance, missing terrain and blocked corridors.\n";
|
|
}
|
|
'''
|
|
with tempfile.TemporaryDirectory(prefix='vcore-free-flight-') as folder:
|
|
cpp=Path(folder)/'test.cpp';binary=Path(folder)/'test';cpp.write_text(harness)
|
|
subprocess.run(['c++','-std=c++17','-I',str(root/'src/server/game/World'),str(cpp),'-o',str(binary)],check=True)
|
|
subprocess.run([str(binary)],check=True)
|