65 lines
3.7 KiB
Python
65 lines
3.7 KiB
Python
"""Measured production edge lengths and stable per-journey modal preferences."""
|
|
from pathlib import Path
|
|
import subprocess, tempfile
|
|
root=Path(__file__).resolve().parents[2]
|
|
s=(root/'src/server/game/World/ClientlessTravelGraphMgr.cpp').read_text()
|
|
a=s.index('void ClientlessTravelGraphMgr::RebuildEdgeDistances(')
|
|
b=s.index('\nstd::string ClientlessTravelGraphMgr::FindNearestStartNode(',a)
|
|
code=r'''
|
|
#include "ClientlessTravelCost.h"
|
|
#include <cassert>
|
|
#include <cstdlib>
|
|
#include <limits>
|
|
#include <unordered_map>
|
|
#include <vector>
|
|
using uint32=unsigned;
|
|
#define TC_LOG_DEBUG(...) ((void)0)
|
|
struct Node{unsigned MapId=0;float X=0,Y=0,Z=0;};
|
|
struct Point:Node{float O=0;};
|
|
struct Edge{unsigned DatabaseId=0;std::string FromNode,ToNode,Type;float Cost=99999;bool Reverse=false;};
|
|
struct NativePoint{unsigned ContinentID;struct{float X,Y,Z;}Loc;};
|
|
using TaxiPathNodeList=std::vector<NativePoint const*>;
|
|
std::vector<TaxiPathNodeList>sTaxiPathNodesByPath(2);
|
|
struct Objects{void GetTaxiPath(unsigned,unsigned,unsigned&p,unsigned&fare){p=1;fare=98765;}}objects;auto sObjectMgr=&objects;
|
|
struct Transports{static bool IsTransportEdge(std::string const&t){return t=="ship"||t=="tram";}float ConnectionDistance(std::string const&,std::string const&){return 777;}}transports;
|
|
using ClientlessTransportMgr=Transports;auto sClientlessTransportMgr=&transports;
|
|
struct ClientlessTravelGraphMgr{
|
|
std::unordered_map<std::string,Node>_nodes;std::unordered_map<std::string,std::vector<Edge>>_edges;
|
|
std::unordered_map<unsigned,std::vector<Point>>points;
|
|
auto GetEdgePoints(unsigned id){return points.count(id)?&points[id]:nullptr;}
|
|
void RebuildEdgeDistances();
|
|
};
|
|
'''+s[a:b]+r'''
|
|
int main(){
|
|
using namespace ClientlessTravelCost;
|
|
Profile neutral;
|
|
auto first=Sample(neutral,1234,.2f),same=Sample(neutral,1234,.2f),other=Sample(neutral,9876,.2f);
|
|
assert(first.Factors==same.Factors&&first.Factors!=other.Factors);
|
|
for(float factor:first.Factors)assert(factor>=.8f&&factor<=1.2f);
|
|
assert(Sample(neutral,1234,0).Factors==neutral.Factors);
|
|
bool ground=false,taxi=false;
|
|
for(unsigned seed=1;seed<=200;++seed){auto p=Sample(neutral,seed,.2f);if(p.Cost(Ground,1000)<p.Cost(Taxi,1050))ground=true;else taxi=true;}
|
|
assert(ground&&taxi); // Repeated journeys can choose different near-equal modes.
|
|
neutral.Factors[Flight]=2;assert(neutral.Cost(Flight,100)==200);
|
|
assert(neutral.Cost(Portal,1000000)==1); // Cross-map coordinates never act as travelled distance.
|
|
ClientlessTravelGraphMgr g;g._nodes["A"]={0,0,0,0};g._nodes["B"]={0,10,0,0};
|
|
g._nodes["taxi_1"]={0,0,0,0};g._nodes["taxi_2"]={1,100000,0,0};
|
|
g._edges["A"]={{1,"A","B","ground",99999,false},{2,"A","taxi_2","portal_use",99999,false},
|
|
{3,"A","B","ship",100,false},{4,"A","taxi_2","ground",1,false}};
|
|
g._edges["B"]={{1,"B","A","ground",1,true}};
|
|
g.points[1]={{{0,0,0,0}},{{0,0,10,0}},{{0,10,10,0}},{{0,10,0,0}}};
|
|
g._edges["taxi_1"]={{5,"taxi_1","taxi_2","taxi",1,false}};
|
|
NativePoint a{0,{0,0,0}},b{0,{3,4,0}},c{0,{3,4,12}},d{1,{100000,0,0}},e{1,{100003,4,0}};
|
|
sTaxiPathNodesByPath[1]={&a,&b,&c,&d,&e};g.RebuildEdgeDistances();
|
|
assert(g._edges["A"][0].Cost==30&&g._edges["B"][0].Cost==30);
|
|
assert(g._edges["A"][1].Cost==1&&g._edges["A"][2].Cost==777);
|
|
assert(!std::isfinite(g._edges["A"][3].Cost));
|
|
assert(g._edges["taxi_1"][0].Cost==22); // Native geometry, not ticket price; no cross-map jump.
|
|
}
|
|
'''
|
|
with tempfile.TemporaryDirectory(prefix='vcore-travel-costs-') 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('Production measured roads/native taxi paths/portal transitions/transport distance and reproducible per-mode journey variation passed.')
|