71 lines
4.7 KiB
Python
71 lines
4.7 KiB
Python
"""Exercise the real rescue executor with explicit graph and native transfer doubles."""
|
|
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::TryRescueTravel(');b=s.index('bool ClientlessActionExecutorMgr::RecoverTravel(',a)
|
|
code=r'''
|
|
#include <cassert>
|
|
#include <string>
|
|
#include <vector>
|
|
#include <unordered_set>
|
|
#include <utility>
|
|
using uint32=unsigned;
|
|
#define TC_LOG_WARN(...) ((void)0)
|
|
struct Node{unsigned MapId=369;std::string Type="rescue";float X=33,Y=40,Z=-4,O=0;}node;
|
|
struct Session{unsigned acks=0;void CompleteClientlessTeleport(){++acks;}}session;
|
|
struct Player{
|
|
unsigned map=369,transfers=0,stops=0;bool alive=true,combat=false,teleport=false,transport=false,taxi=false,flying=false,transferOK=true;
|
|
bool IsAlive(){return alive;}bool IsInCombat(){return combat;}bool IsBeingTeleported(){return teleport;}bool GetTransport(){return transport;}
|
|
bool IsInFlight(){return taxi;}bool IsFlying(){return flying;}unsigned GetMapId(){return map;}
|
|
void StopMoving(){++stops;}Session*GetSession(){return &session;}
|
|
bool TeleportTo(unsigned m,float,float,float,float){assert(m==369);++transfers;return transferOK;}
|
|
};
|
|
struct ClientlessTravelRouteStep{std::string NodeKey;};
|
|
struct Graph{bool available=true,transfer=false,forceSeen=false;unsigned calls=0;
|
|
bool PlanRescueRoute(Player*,std::vector<ClientlessTravelRouteStep>&r,std::string&t,bool force,std::unordered_set<uint32>const*){
|
|
++calls;forceSeen=force;if(!available)return false;r={{"rescue"},{"exit"}};t=(transfer||force)?"rescue":"";return true;}
|
|
Node*FindNode(std::string const&){return &node;}
|
|
}graph;auto sClientlessTravelGraphMgr=&graph;
|
|
struct Areas{bool allowed=true;bool AllowsNode(Player*,Node const&){return allowed;}}areas;auto sAdventureAreaMgr=&areas;
|
|
struct Core{bool managed=true;bool IsManaged(unsigned){return managed;}}core;auto sClientlessPlayerMgr=&core;
|
|
struct Travel{unsigned cancels=0;void CancelTravel(unsigned){++cancels;}}travel;auto sClientlessTravelMgr=&travel;
|
|
enum class ClientlessActionExecutionState{Moving,Failed};
|
|
struct ClientlessActionExecutorMgr{
|
|
struct Record{
|
|
bool RescueActive=false,RescueWalkFailed=false,StopAtNode=true,Active=false;
|
|
unsigned RescueAttempts=0;std::unordered_set<unsigned>FailedEdgeDatabaseIds;
|
|
std::vector<ClientlessTravelRouteStep>Route;unsigned RouteStep=99;std::vector<int>EdgePath;
|
|
bool DeferredStartActive=true,GroundExitActive=true,GroundResumeActive=true,TaxiActive=true,RecoveryWanderActive=true;
|
|
bool TransportActive=true,FlightActive=true,FlightApproachActive=true,PortalUseActive=true,FormationWaiting=true,GroundChunk=true,ReplanAtGroundEnd=true,GroundFlightExit=true;
|
|
bool FinalLocalLegActive=true,FinalLocalLegPending=true,RouteComplete=false;
|
|
std::string originalGoal="original-intent";
|
|
struct{ClientlessActionExecutionState State=ClientlessActionExecutionState::Failed;std::string Detail;}Status;
|
|
};unsigned starts=0;bool StartRouteStep(Player*,unsigned,Record&){++starts;return true;}
|
|
bool TryRescueTravel(Player*,unsigned,Record&);
|
|
};
|
|
'''+s[a:b]+r'''
|
|
int main(){
|
|
ClientlessActionExecutorMgr m;Player p;ClientlessActionExecutorMgr::Record r;
|
|
assert(m.TryRescueTravel(&p,58,r)&&r.RescueActive&&r.RescueAttempts==1&&p.transfers==0);
|
|
assert(r.Route.size()==2&&r.RouteStep==0&&!r.StopAtNode&&!r.FinalLocalLegPending&&!r.TransportActive&&!r.ReplanAtGroundEnd);
|
|
assert(r.originalGoal=="original-intent");assert(!m.TryRescueTravel(&p,58,r));
|
|
r.RescueWalkFailed=true;assert(m.TryRescueTravel(&p,58,r)&&graph.forceSeen&&p.transfers==1&&session.acks==1);
|
|
assert(!m.TryRescueTravel(&p,58,r)); // bounded attempts
|
|
r={};graph.transfer=true;p.map=0;assert(!m.TryRescueTravel(&p,58,r)&&p.transfers==1);p.map=369;
|
|
r={};areas.allowed=false;assert(!m.TryRescueTravel(&p,58,r));areas.allowed=true;
|
|
r={};node.Type="ground";assert(!m.TryRescueTravel(&p,58,r));node.Type="rescue";
|
|
r={};p.combat=true;auto calls=graph.calls;assert(!m.TryRescueTravel(&p,58,r)&&graph.calls==calls);p.combat=false;
|
|
p.transport=true;assert(!m.TryRescueTravel(&p,58,r));p.transport=false;
|
|
p.flying=true;assert(!m.TryRescueTravel(&p,58,r));p.flying=false;
|
|
p.alive=false;assert(!m.TryRescueTravel(&p,58,r));p.alive=true;
|
|
core.managed=false;assert(!m.TryRescueTravel(&p,58,r));core.managed=true;
|
|
graph.available=false;assert(!m.TryRescueTravel(&p,58,r));
|
|
}
|
|
'''
|
|
with tempfile.TemporaryDirectory()as d:
|
|
p=Path(d);(p/'test.cpp').write_text(code)
|
|
subprocess.run(['c++','-std=c++17',str(p/'test.cpp'),'-o',str(p/'test')],check=True)
|
|
subprocess.run([str(p/'test')],check=True)
|
|
print('Rescue executor: walk first, tram-only validated transfer, native ACK, original goal retention, state reset, access and bounded retry guards passed')
|