Keep clientless flight moving across spline handoffs
GCC PCH / build (push) Waiting to run
clang PCH / build (push) Canceled after 0s

Replace ordinary flight splines before they finish while retaining collision checks, terminal landing and conservative return behavior. Measure actual travelled distance, cover handoff timing with a production Update regression test, retire Arthoran's automatic ship test and document visual acceptance of the travel milestone.
This commit is contained in:
Nico committed 2026-10-26 18:21:48 +01:00
1 parent 8df9591c99
commit ca656403bb
5 files changed
+149 -12

No files matched your search

+92
View File
@@ -0,0 +1,92 @@
"""Exercise production Update with a running native spline, not a string check."""
from pathlib import Path
import subprocess
import tempfile
root = Path(__file__).resolve().parents[2]
source = (root / 'src/server/game/World/ClientlessFlightMgr.cpp').read_text()
a = source.index('void ClientlessFlightMgr::Update(uint32 diff)')
b = source.index('bool ClientlessFlightMgr::Command(', a)
update = source[a:b]
harness = r'''
#include "ClientlessFlightPath.h"
#include <cassert>
#include <cstdint>
#include <string>
#include <unordered_map>
using uint32 = uint32_t;
using namespace ClientlessFlightPath;
struct Position {
float x=0,y=0,z=60;
float GetPositionX() const{return x;} float GetPositionY() const{return y;} float GetPositionZ() const{return z;}
void Relocate(Position const* p){*this=*p;}
};
Point PointOf(Position const& p){return {p.x,p.y,p.z};}
struct Spline {int remaining=500; int timeRemaining()const{return remaining;}};
struct Player:Position {
Spline spline; Spline* movespline=&spline;
bool alive=true,fly=true,running=true;int stops=0;
bool IsInWorld(){return true;} uint32 GetMapId(){return 0;}
bool IsAlive(){return alive;} bool IsBeingTeleported(){return false;}
bool IsMounted(){return true;} bool CanFly(){return fly;}
bool IsSplineEnabled(){return running;}
void StopMoving(){++stops;running=false;}
} player;
struct Session {Player* GetPlayer(){return &player;}} session;
enum class ClientlessPlayerState {Online};
struct World {
Session* FindClientlessSession(uint32){return &session;}
ClientlessPlayerState GetClientlessPlayerState(uint32){return ClientlessPlayerState::Online;}
} world;
auto sWorld=&world;
enum class ClientlessFlightState {Mounting,Flying,Arrived,Failed};
struct Record {
struct {ClientlessFlightState State=ClientlessFlightState::Flying;uint32 MapId=0;Position Landing{800,0,0};float Travelled=0;} Status;
Position LastPosition,Start,Segment{25,0,60};Settings Settings;
uint32 Elapsed=0,SegmentElapsed=0,CheckTimer=0;
bool Moving=true,Returning=false;
};
bool clear=true;
bool ClearRay(Player*,Point const&,Point const&){return clear;}
class ClientlessFlightMgr {
public:
std::unordered_map<uint32,Record> _records;
int advances=0,handoffs=0,failures=0;
Surface Sample(Player*,Record&,float,float){return {0,300,true};}
void Fail(Player*,Record& r,std::string const&){++failures;r.Status.State=ClientlessFlightState::Failed;}
bool Advance(Player*,Record&,bool handoff=false){++advances;handoffs+=handoff;return true;}
void Update(uint32 diff);
};
'''.replace('Settings Settings;', 'ClientlessFlightPath::Settings Settings;')
harness += update + r'''
int main(){
ClientlessFlightMgr mgr;mgr._records[26]={};
// Begin replacement while the existing spline is still active: no stop.
mgr.Update(50);assert(mgr.handoffs==1&&mgr.advances==1&&player.stops==0);
// The 200ms collision cadence must not launch a replacement each tick.
mgr.Update(50);assert(mgr.advances==1);
mgr._records[26].CheckTimer=0;player.spline.remaining=900;
mgr.Update(50);assert(mgr.advances==1);
// Exact landing endpoint must finish normally, never repeatedly extend.
auto& r=mgr._records[26];r.CheckTimer=0;r.Status.Landing=r.Segment;
player.spline.remaining=400;mgr.Update(50);assert(mgr.advances==1);
// Reverse trail keeps its original checked corners.
r.Segment={25,0,60};r.Returning=true;r.CheckTimer=0;
mgr.Update(50);assert(mgr.advances==1);
// Distance means measured motion, not unflown overlapping destinations.
player.x=7;r.CheckTimer=0;mgr.Update(50);assert(std::fabs(r.Status.Travelled-7)<0.01);
// A newly blocked corridor still stops/replans immediately.
clear=false;r.CheckTimer=0;mgr.Update(50);
assert(player.stops==1&&mgr.advances==2&&mgr.handoffs==1);
// A completed spline continues via the normal non-handoff path.
clear=true;r.CheckTimer=0;mgr.Update(50);assert(mgr.advances==3);
player.fly=false;mgr.Update(50);assert(mgr.failures==1);
}
'''
with tempfile.TemporaryDirectory(prefix='vcore-flight-handoff-') 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)
print('Flight handoff before spline end, terminal landing, return corners, collision stop and actual distance passed.')