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.
87 lines
5.0 KiB
Python
87 lines
5.0 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;};
|
|
Memory finalApproach;finalApproach.Departed=true;
|
|
auto touchdown=Next({6,0,10},{0,0,0},Settings{},finalApproach,flat,clear);
|
|
assert(touchdown.Valid&&touchdown.Landing&&Distance(touchdown.Next,{0,0,0})<0.01f);
|
|
auto solidWall=[](Point const&,Point const&){return false;};
|
|
assert(!Next({6,0,10},{0,0,0},Settings{},finalApproach,flat,solidWall).Valid);
|
|
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);
|
|
// Convoy members replay exactly the published segments, retaining their own index.
|
|
SharedTrail trail;trail.Points={{20,0,30},{40,0,40}};std::size_t index=0;Settings settings;
|
|
auto shared=FollowTrail({0,0,0},{800,0,0},settings,trail,index,flat,clear);
|
|
assert(shared.Step.Valid&&shared.Step.Next.X==20&&index==0);
|
|
shared=FollowTrail({20,0,30},{800,0,0},settings,trail,index,flat,clear);
|
|
assert(shared.Step.Valid&&shared.Step.Next.X==40&&index==1);
|
|
shared=FollowTrail({40,0,40},{800,0,0},settings,trail,index,flat,clear);
|
|
assert(shared.Waiting&&index==2);trail.Points.push_back({60,0,40});
|
|
shared=FollowTrail({40,0,40},{800,0,0},settings,trail,index,flat,clear);
|
|
assert(shared.Step.Valid&&shared.Step.Next.X==60);
|
|
|
|
assert(!FollowTrail({40,0,40},{800,0,0},settings,trail,index,flat,blocked).Step.Valid);
|
|
trail.Aborted=true;shared=FollowTrail({40,0,40},{800,0,0},settings,trail,index,flat,clear);
|
|
assert(!shared.Step.Valid&&!shared.Waiting);
|
|
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)
|