Files
Viano-Core/tests/clientless/test_rescue_graph.py
T

62 lines
4.0 KiB
Python

"""Execute production adaptive planning and explicit recorded rescue search."""
from pathlib import Path
import runpy,subprocess,tempfile
root=Path(__file__).resolve().parents[2]
e=runpy.run_path(str(root/'tests/clientless/test_free_flight_planner.py'))
s=e['s']
def method(sig):
a=s.index(sig);b=s.index('{',a);n=1;c=b+1
while n:n+=(s[c]=='{')-(s[c]=='}');c+=1
return s[a:c]
preamble=e['preamble'].replace('uint32 GetMapId()const{return 0;}','uint32 map=369; uint32 GetMapId()const{return map;} float GetExactDist(float a,float b,float c)const{return std::sqrt((x-a)*(x-a)+(y-b)*(y-b)+(z-c)*(z-c));}')
cls=e['cls'].replace('\n};','''
std::vector<ClientlessTravelEdgePoint>const*GetEdgePoints(uint32 id)const{auto i=_edgePoints.find(id);return i==_edgePoints.end()?nullptr:&i->second;}
bool PlanRescueRoute(Player*,std::vector<ClientlessTravelRouteStep>&,std::string&,bool=false,std::unordered_set<uint32>const* =nullptr);
bool FindNearestNodeToPosition(uint32,float,float,float,std::string&,float&)const;
};''')
code=preamble+e['structs']+cls+e['method']+method('bool ClientlessTravelGraphMgr::FindNearestNodeToPosition(')+method('bool ClientlessTravelGraphMgr::PlanRescueRoute(')+r'''
void node(ClientlessTravelGraphMgr&g,std::string k,float x,std::string type="ground"){
ClientlessTravelNode n;n.Key=k;n.Type=type;n.X=x;n.MapId=369;g._nodes[k]=n;
}
void edge(ClientlessTravelGraphMgr&g,std::string a,std::string b,unsigned id){
g._edges[a].push_back({id,a,b,"ground",10,false});
ClientlessTravelEdgePoint p;p.X=g._nodes.at(a).X;p.MapId=369;g._edgePoints[id].push_back(p);
p.X=g._nodes.at(b).X;g._edgePoints[id].push_back(p);
}
int main(){
ClientlessTravelGraphMgr g;Player p;p.x=5000;
node(g,"sw",0,"rescue");node(g,"if",2500,"rescue");node(g,"exit_sw",10);node(g,"exit_if",2490);
edge(g,"sw","exit_sw",1);edge(g,"if","exit_if",2);edge(g,"sw","if",3);
std::vector<ClientlessTravelRouteStep>r;std::string transfer,error,reached;bool complete=false;
// Rescue roots are excluded from ordinary nearest anchors and destinations.
float distance;assert(g.FindNearestNodeToPosition(369,0,0,0,reached,distance)&&reached=="exit_sw");
assert(!g.PlanAdaptiveRoute(&p,"sw",4000,200,r,complete,reached,error));
// A recorded rescue corridor cannot be borrowed as a normal shortcut,
// including virtual entries into the interior of its ground edges.
p.x=0;g.PlanAdaptiveRoute(&p,"exit_if",1,200,r,complete,reached,error);assert(!complete);p.x=5000;
// No traversable local start: only map369 may transfer to the nearest
// permitted authored rescue node with a recorded escape edge.
travel.complete=false;
assert(g.PlanRescueRoute(&p,r,transfer)&&transfer=="if"&&r.size()==2&&r.back().EdgeDatabaseId==2);
assert(!g._rescuePlanning); // scoped privilege cannot leak into later plans
p.map=0;assert(!g.PlanRescueRoute(&p,r,transfer));p.map=369;
// A reachable MMAP approach walks; it must not transfer a healthy bot.
travel.complete=true;p.x=2497;
assert(g.PlanRescueRoute(&p,r,transfer)&&transfer.empty()&&r.back().NodeKey=="exit_if");
assert(g.PlanRescueRoute(&p,r,transfer,true)&&transfer=="if");
// Blocked recording and faction/area denial select another legal escape;
// no bypass of a denied rescue root or native edge is allowed.
std::unordered_set<uint32>blocked{2};travel.complete=false;
assert(g.PlanRescueRoute(&p,r,transfer,true,&blocked)&&transfer=="sw");
access.blocked.insert("sw");assert(!g.PlanRescueRoute(&p,r,transfer,true,&blocked));access.blocked.clear();
blocked={1,2,3};assert(!g.PlanRescueRoute(&p,r,transfer,true,&blocked));
// A node without a recorded edge cannot become a teleport destination.
g._edgePoints.clear();assert(!g.PlanRescueRoute(&p,r,transfer,true));
}
'''
with tempfile.TemporaryDirectory()as d:
p=Path(d);(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)
print('Rescue graph: normal exclusion, walking first, recorded-only escapes, bounded tram transfer, access/blocked-edge checks and scoped planning passed')