Files
Viano-Core/tests/clientless/test_shared_flight_rejoin.py
T
Nico 65e4abb0b9 Fix shared flight trail replacement and safe follower rejoining
Publish replacement landing targets, bound orphaned trail waits, and plan safe connections from the follower position. Support shared-route regroup landings and preserve catch-up flights after the leader lands. Add geometry, lifecycle and group travel regressions.
2026-11-03 19:59:56 +01:00

62 lines
4.0 KiB
Python

"""Join a leader trail from a later taxi stop instead of replaying its origin."""
from pathlib import Path
import subprocess,tempfile
root=Path(__file__).resolve().parents[2]
code=r'''
#include "ClientlessFlightPath.h"
#include <cassert>
#include <iostream>
using namespace ClientlessFlightPath;
int main(){Settings cfg;auto flat=[](float,float){return Surface{0,1000,true};};auto clear=[](Point const&,Point const&){return true;};
SharedTrail trail;trail.LandingReady=true;trail.Complete=true;trail.Landing={1200,0,0};
trail.Points={{0,0,20},{1025,0,60},{1050,0,60},{1100,0,60},{1200,0,0}};
SharedJoin join;std::size_t index=0;Point current{1000,0,0};bool connected=false;
for(unsigned i=0;i<100&&Distance(current,trail.Landing)>.1f;++i){
auto result=FollowTrail(current,trail.Landing,cfg,trail,index,flat,clear,0,&join);
assert(!result.Waiting&&result.Step.Valid);assert(result.Step.Next.X>=1000);
assert(Corridor(current,result.Step.Next,trail.Landing,cfg,flat,clear,true,result.Step.UnderOverhang));
current=result.Step.Next;if(!join.Active)connected=true;
}
assert(connected&&Distance(current,trail.Landing)<.1f&&index>=1);
// Original Winienwi geometry: the old first point is 2,088 yards behind
// the taxi stop and its direct segment intersects a raised surface.
Point taxi{-4170.55f,-4748.93f,126.786f};SharedTrail actual;
actual.LandingReady=true;actual.Landing={-4905.67f,-4232.75f,827.766f};
actual.Points={{-4863.52f,-6715.61f,24.22f},{-4850,-4750,540},actual.Landing};
auto hills=[](float x,float y){float ground=y< -6500?9.f:126.786f;
if(std::fabs(x+4175.523f)<2.5f&&std::fabs(y+4763.045f)<2.5f)ground=129.25f;
return Surface{ground,1000,true};};
assert(!Corridor(taxi,actual.Points[0],actual.Landing,cfg,hills,clear,true));
join={};index=0;auto connectedTaxi=FollowTrail(taxi,actual.Landing,cfg,actual,index,hills,clear,0,&join);
assert(connectedTaxi.Step.Valid&&join.Target==1&&connectedTaxi.Step.Next.Z>taxi.Z);
// Joining an airborne leg above a tower must still go around its platform.
SharedTrail tower;tower.LandingReady=true;tower.Landing={12,0,200};
tower.Points={{60,0,210},{12,0,210},tower.Landing};
auto platform=[](float x,float y){return Surface{std::hypot(x,y)<20?200.f:0.f,500,true,0.f};};
auto solid=[](Point const&a,Point const&b){for(unsigned 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;}return true;};
current={90,0,80};join={};index=0;
for(unsigned i=0;i<100&&Distance(current,tower.Landing)>.1f;++i){
auto step=FollowTrail(current,tower.Landing,cfg,tower,index,platform,solid,0,&join);
assert(step.Step.Valid&&!step.Waiting);current=step.Step.Next;
}
assert(Distance(current,tower.Landing)<.1f);
// No unvalidated shortcut through a tower or missing terrain.
join={};index=0;auto blocked=[](Point const&,Point const&){return false;};
assert(!FollowTrail({1000,0,0},trail.Landing,cfg,trail,index,flat,blocked,0,&join).Step.Valid);
auto missing=[](float,float){return Surface{};};join={};index=0;
assert(!FollowTrail({1000,0,0},trail.Landing,cfg,trail,index,missing,clear,0,&join).Step.Valid);
// A replacement publishes its verified destination immediately, even before
// any points are flown. Old readers can resolve to this generation.
auto old=std::make_shared<SharedTrail>();auto next=old->Replace({100,0,0});
assert(old->Aborted&&old->Replacement==next&&next->LandingReady&&next->Landing.X==100);
assert(next->Points.empty());next->Points={{25,0,20},{100,0,0}};next->Complete=true;
join={};index=0;auto step=FollowTrail({0,0,0},next->Landing,cfg,*next,index,flat,clear,0,&join);
assert(step.Step.Valid&&!step.Waiting);
std::cout<<"Shared route rejoin after taxi, bounded climb, clear corridor, blocked/missing terrain, replacement publication PASS\n";
}
'''
with tempfile.TemporaryDirectory(prefix="vcore-shared-rejoin-") as directory:
p=Path(directory);(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)