Finish capital waiting travel and adaptive flight entry up to 10,000 yards. Preserve checked vertical climbs, recover blocked ground departures and find validated dry landings. Retain group routes and Undercity arrival constraints. Restore defense from native combat references, coordinate instance rendezvous and browser reentry, finalize clientless sessions before map destruction and transfer Halaa capture-point ownership safely. Include the associated regression tests, investigation reports and reusable diagnostic scripts. Keep generated runtime evidence and server binaries local through scoped ignore rules. Validation/build/live evidence is recorded in the session checkpoint and individual reports.
60 lines
5.0 KiB
Python
60 lines
5.0 KiB
Python
"""Run the generic production route-copy function (no AdventureBot dependency)."""
|
|
from pathlib import Path
|
|
import subprocess,tempfile
|
|
root=Path(__file__).resolve().parents[2]
|
|
s=(root/'src/server/game/World/ClientlessActionExecutorMgr.cpp').read_text()
|
|
a=s.index('bool ClientlessActionExecutorMgr::AdoptRoute(')
|
|
code=r'''
|
|
#include "ClientlessTravelCost.h"
|
|
#include <algorithm>
|
|
#include <cassert>
|
|
#include <cmath>
|
|
#include <cstdlib>
|
|
#include <string>
|
|
#include <vector>
|
|
#include <unordered_map>
|
|
using uint32=unsigned;
|
|
#define TC_LOG_INFO(...) ((void)0)
|
|
struct Guid{unsigned id=0;unsigned GetCounter(){return id;}};
|
|
struct Position{float x,y,z;void Relocate(float a,float b,float c){x=a;y=b;z=c;}};
|
|
struct Group{Guid leader{29};Guid GetLeaderGUID(){return leader;}}group;
|
|
struct Player{bool grouped=true;unsigned map=0;Guid GetGUID(){return {31};}Group*GetGroup(){return grouped?&group:nullptr;}unsigned GetMapId(){return map;}float GetExactDist(Position const&p){return std::hypot(p.x,p.y);}};
|
|
struct ClientlessAction{std::string Name;std::unordered_map<std::string,std::string>Parameters;};
|
|
struct ClientlessTravelRouteStep{std::string NodeKey,EdgeType;unsigned EdgeDatabaseId=0,MapId=0;float X=0,Y=0,Z=0;};
|
|
struct Graph{ClientlessTravelCost::Profile observed;bool allowed=true;bool PlanAdaptiveRoute(Player*,std::string const&node,int,int,std::vector<ClientlessTravelRouteStep>&r,bool&complete,std::string&,std::string&,void const* =nullptr,void const* =nullptr,void const* =nullptr,ClientlessTravelCost::Profile const*costs=nullptr){if(costs)observed=*costs;complete=true;r={{node,"start"}};return allowed;}}graph;auto sClientlessTravelGraphMgr=&graph;
|
|
struct ClientlessActionExecutorMgr{
|
|
struct Record{ClientlessTravelCost::Profile JourneyCosts;std::string JourneyCostKey;bool HasJourneyCosts=false;std::vector<ClientlessTravelRouteStep>Route;size_t RouteStep=0;bool FinalLocalLegPending=false,RouteComplete=true,HardDestination=false,Active=false;
|
|
unsigned FinalMapId=0,FinalDatabaseId=0;float FinalX=0,FinalY=0,FinalZ=0,FinalO=0;std::string FinalLocationId,PlannedDestinationNode,AdaptiveReachedNode,RequiredArrivalNode;bool RequiredArrivalReached=false;};
|
|
std::unordered_map<unsigned,Record>_records;int starts=0;bool StartRouteStep(Player*,unsigned,Record&){++starts;return true;}
|
|
bool AdoptRoute(Player*,ClientlessAction const&,Record&);
|
|
};
|
|
'''+s[a:]+r'''
|
|
int main(){
|
|
ClientlessActionExecutorMgr mgr;Player p;ClientlessAction a;a.Name="travel_to_location";a.Parameters={{"id","destination"},{"route_source","29"}};
|
|
auto& lead=mgr._records[29];lead.Route={{"start","start",0,0,0,0,0},{"taxi_end","taxi",18,0,30,0,0},{"flight_end","free_flight",0,0,80,0,0}};
|
|
lead.JourneyCosts=ClientlessTravelCost::Sample({},12345,0.2f);lead.JourneyCostKey="leader-trip";lead.HasJourneyCosts=true;
|
|
lead.RouteStep=1;lead.FinalLocationId="destination";lead.FinalDatabaseId=77;lead.FinalX=90;lead.FinalLocalLegPending=true;
|
|
ClientlessActionExecutorMgr::Record peer;
|
|
assert(mgr.AdoptRoute(&p,a,peer));assert(peer.Route.size()==3&&peer.Route[1].EdgeType=="taxi"&&peer.Route[1].EdgeDatabaseId==18&&peer.Route[2].EdgeType=="free_flight");
|
|
assert(peer.FinalLocationId=="destination"&&peer.FinalLocalLegPending&&peer.FinalX==90&&peer.FinalDatabaseId==77);
|
|
assert(peer.HasJourneyCosts&&peer.JourneyCosts.Seed==12345&&peer.JourneyCostKey=="leader-trip"&&peer.JourneyCosts.Factors==lead.JourneyCosts.Factors);
|
|
assert(peer.RouteStep==0&&peer.Active&&lead.RouteStep==1);peer.Route[1].NodeKey="changed";assert(lead.Route[1].NodeKey=="taxi_end");
|
|
// Arrival requirements transfer with the route, but a leader's physical arrival is not inherited.
|
|
lead.RequiredArrivalNode="taxi_11";lead.RequiredArrivalReached=true;
|
|
assert(mgr.AdoptRoute(&p,a,peer)&&peer.RequiredArrivalNode=="taxi_11"&&!peer.RequiredArrivalReached);
|
|
lead.RequiredArrivalNode.clear();lead.RequiredArrivalReached=false;
|
|
// Late arrival joins the active route at its previous reached node.
|
|
lead.RouteStep=2;assert(mgr.AdoptRoute(&p,a,peer));assert(peer.Route.size()==2&&peer.Route[0].NodeKey=="taxi_end"&&peer.Route[0].EdgeType=="start"&&peer.Route[1].EdgeType=="free_flight");
|
|
p.map=1;assert(mgr.AdoptRoute(&p,a,peer));assert(graph.observed.Factors==lead.JourneyCosts.Factors&&graph.observed.Seed==12345);graph.allowed=false;assert(!mgr.AdoptRoute(&p,a,peer));graph.allowed=true;p.map=0;
|
|
// No cross-group route copying and no stale destination reuse.
|
|
group.leader={32};assert(!mgr.AdoptRoute(&p,a,peer));group.leader={29};p.grouped=false;assert(!mgr.AdoptRoute(&p,a,peer));p.grouped=true;
|
|
a.Parameters["id"]="different";assert(!mgr.AdoptRoute(&p,a,peer));a.Parameters["id"]="destination";
|
|
lead.Route.clear();assert(!mgr.AdoptRoute(&p,a,peer));
|
|
}
|
|
'''
|
|
with tempfile.TemporaryDirectory() as d:
|
|
p=Path(d);(p/'route.cpp').write_text(code)
|
|
subprocess.run(['g++','-std=c++17','-I'+str(root/'src/server/game/World'),str(p/'route.cpp'),'-o',str(p/'route')],check=True)
|
|
subprocess.run([str(p/'route')],check=True)
|
|
print('Production generic shared routes: same edges/taxi/free flight, independent execution state, final local goal, late catch-up, permissions and stale-goal rejection passed.')
|