Files
Viano-Core/tests/clientless/test_shared_flight_landing.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

89 lines
5.2 KiB
Python

"""Regression: join while leader walks to takeoff; continuous safe trail handoff."""
from pathlib import Path
import subprocess,tempfile
root=Path(__file__).resolve().parents[2]
source=(root/'src/server/game/World/ClientlessFlightMgr.cpp').read_text()
a=source.index(' if(record.Following && !record.Returning)',source.index('bool ClientlessFlightMgr::Advance('))
b=source.index(' Point current =',a)
sync=source[a:b]
a=source.index('void ClientlessFlightMgr::Store(')
b=source.index('bool ClientlessFlightMgr::Begin(',a)
store=source[a:b]
code=r'''
#include "ClientlessFlightPath.h"
#include <cassert>
#include <iostream>
#include <memory>
#include <string>
#include <unordered_map>
using uint32=unsigned;
using namespace ClientlessFlightPath;
struct Position{float x=0,y=0,z=0;void Relocate(float a,float b,float c){x=a;y=b;z=c;}float GetExactDist(Position const&p)const{return std::hypot(std::hypot(x-p.x,y-p.y),z-p.z);}};
struct Record{std::shared_ptr<SharedTrail> Following;std::shared_ptr<SharedTrail> Published=std::make_shared<SharedTrail>();bool Returning=false;unsigned SharedWaitSince=0,Elapsed=0;std::size_t SharedIndex=0;SharedJoin Join;struct{unsigned MapId=0;Position Landing,Target;std::string Detail;}Status;};
int landings=0;void* player=nullptr;void LandFollowing(void*){++landings;}
bool Sync(Record& record){
''' + sync + r'''
return false;
}
struct ClientlessFlightMgr{std::unordered_map<unsigned,Record> _records;void Store(unsigned,Record&&);};
''' + store + r'''
int main(){
ClientlessFlightMgr manager;Record original;original.Status.Target.x=100;
auto previous=original.Published;manager.Store(1,std::move(original));
Record updated;updated.Status.Target.x=100;updated.Published->LandingReady=true;
auto successor=updated.Published;manager.Store(1,std::move(updated));
assert(previous->Aborted&&previous->Replacement==successor);
Record other;other.Status.Target.x=200;manager.Store(1,std::move(other));
assert(successor->Aborted&&!successor->Replacement);
Record r;r.Following=std::make_shared<SharedTrail>();r.Status.Landing.z=777;
assert(Sync(r)&&r.Status.Landing.z==777); // still preparing; no zero landing copied
r.Following->Landing={12,34,827.765625f};r.Following->LandingReady=true;
assert(!Sync(r)&&r.Status.Landing.x==12&&r.Status.Landing.y==34&&r.Status.Landing.z==827.765625f);
assert(r.Published->LandingReady&&r.Published->Landing.Z==827.765625f);
auto replacement=r.Following->Replace({56,78,100});
assert(!Sync(r)&&r.Following==replacement&&r.Status.Landing.z==100);
replacement->Complete=true;assert(!Sync(r)); // completed valid trail remains usable
Record waiting;waiting.Following=std::make_shared<SharedTrail>();
assert(Sync(waiting));waiting.Elapsed=120000;assert(Sync(waiting)&&landings==1);
waiting.Following->Aborted=true;assert(Sync(waiting)&&landings==2);
Settings cfg;auto sample=[](float,float){return Surface{827.765625f,1000,true,0};};
auto clear=[](Point const&,Point const&){return true;};
// The same shared object first exists while its leader is walking to takeoff.
SharedTrail trail;Point landing{0,0,0};std::size_t index=0;
assert(!trail.BindLanding(landing));
auto pending=FollowTrail({0,0,0},landing,cfg,trail,index,sample,clear);
assert(pending.Waiting&&!pending.Step.Valid);
// Leader completes admission later. Follower must bind this published landing,
// including after the leader record is gone/has entered the instance.
trail.Landing={-4905.67f,-4232.75f,827.765625f};trail.LandingReady=true;
Point above{trail.Landing.X,trail.Landing.Y,trail.Landing.Z+10};trail.Points={above,trail.Landing};
// Old bug: stale zero goal retains the 8-yard floor margin during touchdown.
assert(!Corridor(above,trail.Landing,landing,cfg,sample,clear,true));
assert(trail.BindLanding(landing));index=1;
auto final=FollowTrail(above,landing,cfg,trail,index,sample,clear);
assert(final.Step.Valid&&final.Step.Landing&&Distance(final.Step.Next,landing)<.01f);
// In open air the next segment is ready before reaching the prior endpoint.
SharedTrail cruise;cruise.LandingReady=true;cruise.Landing={100,0,0};
cruise.Points={{25,0,60},{50,0,60}};
auto flat=[](float,float){return Surface{0,300,true};};
index=0;auto moving=FollowTrail({15,0,60},cruise.Landing,cfg,cruise,index,flat,clear,15);
assert(moving.Step.Valid&&moving.Step.Next.X==50&&index==1);
// No shortcut through a blocked corner, and no early escape-leg shortcut.
auto obstacle=[](Point const&a,Point const&b){return !(a.X<20&&b.X>30);};
index=0;auto corner=FollowTrail({15,0,60},cruise.Landing,cfg,cruise,index,flat,obstacle,15);
assert(corner.Step.Valid&&corner.Step.Next.X==25&&index==0);
cruise.UnderOverhang={true,false};index=0;
auto escape=FollowTrail({15,0,60},cruise.Landing,cfg,cruise,index,flat,clear,15);
assert(escape.Step.Valid&&index==0);
trail.Aborted=true;assert(!trail.BindLanding(landing));
assert(!FollowTrail(above,landing,cfg,trail,index,sample,clear).Step.Valid);
std::cout<<"Shared flight: late landing publication, terminal descent, early handoff, blocked/escape corners and abort PASS\n";
}
'''
with tempfile.TemporaryDirectory() 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)