68 lines
3.9 KiB
Python
68 lines
3.9 KiB
Python
"""Exercise elevated landings with production geometry and solid overhangs."""
|
|
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;
|
|
// Tower platform at z=200: collision surface is thin, open air beneath its lip.
|
|
auto terrain=[](float x,float y){return Surface{std::hypot(x,y)<20?200.f:0.f,500,true,0.f};};
|
|
auto rays=[](Point const&a,Point const&b){
|
|
for(int i=0;i<=200;++i){auto p=Mix(a,b,i/200.f);
|
|
if(std::hypot(p.X,p.Y)<20 && p.Z>=199.8f && p.Z<=200.2f)return false;
|
|
if(std::hypot(p.X,p.Y)<5 && p.Z<200)return false;
|
|
}return true;
|
|
};
|
|
void run(Point p,bool escapeExpected){
|
|
Settings cfg;Memory m;m.Departed=true;Point goal{12,0,200};
|
|
bool climbed=false,escaped=false,crossed=false,descended=false;unsigned steps=0;
|
|
SharedTrail trail;trail.LandingReady=true;trail.Landing=goal;
|
|
for(;steps<100 && Distance(p,goal)>.1f;++steps){
|
|
auto n=Next(p,goal,cfg,m,terrain,rays);assert(n.Valid);
|
|
assert(Corridor(p,n.Next,goal,cfg,terrain,rays,false,n.UnderOverhang));
|
|
if(m.Elevated==Memory::ElevatedPhase::Climb){assert(Horizontal(p,n.Next)<.01f);climbed=true;}
|
|
if(n.UnderOverhang){assert(std::fabs(p.Z-n.Next.Z)<.01f);escaped=true;}
|
|
if(m.Elevated==Memory::ElevatedPhase::Cross){assert(n.Next.Z>=209.9f);crossed=true;}
|
|
if(m.Elevated==Memory::ElevatedPhase::Descend){assert(Horizontal(p,n.Next)<.01f);descended=true;}
|
|
trail.Points.push_back(n.Next);trail.UnderOverhang.push_back(n.UnderOverhang);
|
|
std::size_t index=trail.Points.size()-1;
|
|
auto shared=FollowTrail(p,goal,cfg,trail,index,terrain,rays);
|
|
assert(shared.Step.Valid && shared.Step.UnderOverhang==n.UnderOverhang);
|
|
p=n.Next;
|
|
}
|
|
assert(Distance(p,goal)<.1f && steps<100 && climbed && crossed && descended);
|
|
assert(!escapeExpected || escaped);
|
|
}
|
|
int main(){
|
|
run({90,0,80},false); // high target: climb before approaching the wall
|
|
run({12,0,100},true); // directly UNDER platform: move out before rising
|
|
run({25,0,190},false); // only 10 yards high, slope budget is 7.8: no fixed threshold
|
|
// Reachable diagonal approach intersects platform underside. The collision
|
|
// query, rather than a height threshold, must trigger the elevated manoeuvre.
|
|
Memory m;m.Departed=true;Settings cfg;
|
|
auto n=Next({40,0,190},{12,0,200},cfg,m,terrain,rays);
|
|
assert(n.Valid && m.Elevated!=Memory::ElevatedPhase::None);
|
|
// A blocked ascent/crossing must fail, never tunnel through a platform.
|
|
auto blocked=[](Point const&,Point const&){return false;};
|
|
Memory b;b.Departed=true;assert(!Next({12,0,100},{12,0,200},cfg,b,terrain,blocked).Valid);
|
|
// The escape exception must not tunnel through bare terrain or water.
|
|
auto hill=[](float,float){return Surface{200.f,500,true,200.f};};
|
|
assert(!Corridor({12,0,100},{80,0,100},{12,0,200},cfg,hill,rays,false,true));
|
|
// A low flight ceiling cannot be ignored by the vertical exception.
|
|
auto low=[](float x,float y){return Surface{std::hypot(x,y)<20?200.f:0.f,213,true,0.f};};
|
|
Memory c;c.Departed=true;assert(!Next({90,0,80},{12,0,200},cfg,c,low,rays).Valid);
|
|
// Ordinary small height changes still use the normal slope.
|
|
auto gentle=[](float x,float){return Surface{x>99?5.f:0.f,500,true};};
|
|
auto clear=[](Point const&,Point const&){return true;};
|
|
Memory d;d.Departed=true;auto normal=Next({0,0,10},{100,0,5},cfg,d,gentle,clear);
|
|
assert(normal.Valid && d.Elevated==Memory::ElevatedPhase::None);
|
|
std::cout<<"Elevated flight: slope budget, open column, solid overhang escape, above-platform crossing, touchdown, shared trail, blocked/ceiling checks PASS\n";
|
|
}
|
|
'''
|
|
with tempfile.TemporaryDirectory(prefix='vcore-elevated-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)
|