"""Execute traffic retirement, ownership and spawn scheduling with native adapters.""" import re from policy_harness import ROOT, body, run p=ROOT/'addons/core/Scripts/Game/ERR/10_AI/ERR_CivilianTraffic.c' def translate(s): s=s.replace('protected ','').replace('foreach (','for (').replace('vector ', 'Vec ').replace('array', 'array') s=s.replace('array observers = {};','Array observers;').replace('array actors = {};','Array actors;').replace('array seats = {};','Array seats;') s=s.replace('array observers','Array observers').replace('array actors','Array actors') for typ in ('ERR_CivilianCar','IEntity','BaseCompartmentSlot'): s=re.sub(r'\b'+typ+r' (?=\w)',typ+'* ',s) for name in ('traffic','m_Mode','seat'): s=s.replace(name+'.',name+'->') s=s.replace('Car.','Car->').replace('Driver.','Driver->').replace('Group.','Group->') s=s.replace('string.Format', 'string::Format') s=s.replace('GetGame().','GetGame()->').replace('GetFactionManager().','GetFactionManager()->').replace('Settings().','Settings()->') for cls in ('ERR_CivilianTrafficRules','ERR_ConvoyRules','ERR_Actors','Replication','ERR_GameMode','ERR_Phase','ERR_ForceRules','vector','ERR_HQ'): s=s.replace(cls+'.',('Geometry' if cls=='vector' else cls)+'::') return s rules=translate('\n'.join(body(p,x) for x in ('static bool Far(', 'static bool CleanupDue('))) methods=translate('\n'.join(body(p,x) for x in ('protected void Drive(', 'void PlayerEntered(', 'protected bool Foreign(', 'protected bool SafeCleanup(', 'void Tick(', 'void Stop('))) run(r''' #include #include #include #include struct string:std::string{using std::string::string;string(std::string s):std::string(s){}templatestatic string Format(const char*,T...){return "retry";}}; struct Vec{float x=0,y=0,z=0;}; namespace Geometry{float DistanceXZ(Vec a,Vec b){return std::hypot(a.x-b.x,a.z-b.z);}} templatestruct Array:std::vector{using std::vector::vector;int Count(){return this->size();}bool IsEmpty(){return this->empty();}void Remove(int i){this->erase(this->begin()+i);}}; namespace ERR_ForceRules{bool FiniteVector(Vec p){return std::isfinite(p.x)&&std::isfinite(p.y)&&std::isfinite(p.z);}} struct ERR_CivilianTrafficRules{ '''+rules+r''' }; struct Group{int faction=1,agents=1;bool captured=false,deleted=false;int current=0;int GetCurrentWaypoint(){return current;}int GetFaction(){return faction;}int GetAgentsCount(){return agents;}}; struct IEntity{Vec position;bool player=false,alive=true,fit=true,deleted=false,hidden=true;Group* group=nullptr;IEntity* parent=nullptr;Vec GetOrigin(){return position;}}; struct BaseCompartmentSlot{IEntity* occupant=nullptr;IEntity* GetOccupant(){return occupant;}}; struct Car:IEntity{bool captured=false,seatsKnown=true;Array seats;}; struct ERR_CivilianCar{struct Car* Car=nullptr;IEntity* Driver=nullptr;struct Group* Group=nullptr;bool Released=false,Ready=true,Finished=false;float Deadline=120000,HiddenSince=-1,ProgressAt=0;Vec ProgressPosition;int RouteStop=1,Retries=0;string Status;Array Orders={1,2};void Report(string s){Status=s;}void Finish(string s){Finished=true;Status=s;}Array Route={{},{},{3000,0,0}};int cleared=0;void Protect(bool){}void ClearOrders(){cleared++;}void Release(){if(Released)return;Released=true;ClearOrders();}}; namespace ERR_Actors{bool Player(IEntity* a){return a&&a->player;}Group* Group(IEntity* a){return a?a->group:nullptr;}bool CanFight(IEntity* a){return a&&a->alive&&a->fit;}bool Alive(IEntity* a){return a&&a->alive;}templatevoid DeleteSpawned(T* e){if(e)e->deleted=true;}} namespace ERR_ConvoyRules{bool PartOf(IEntity* e,IEntity* root){for(int i=0;e&&i<32;i++,e=e->parent)if(e==root)return true;return false;}bool Captured(Car* c,Group* g){return (c&&c->captured)||(g&&g->captured);}bool CollectSeats(Car* c,Array& out){out=c->seats;return c->seatsKnown;}} namespace Replication{bool server=true;bool IsServer(){return server;}} namespace ERR_Phase{enum{PRISON=1,RADIO_SEARCH=2};} struct Settings{int target=3;int Get(string){return target;}}; struct Mode{bool active=true;int phase=2;struct Settings settings;bool Active(){return active;}int Phase(){return phase;}struct Settings* Settings(){return &settings;}}; namespace ERR_GameMode{Mode* current=nullptr;Mode* Get(){return current;}} struct FactionManager{int GetFactionByKey(string){return 1;}}; struct Game{FactionManager factions;FactionManager* GetFactionManager(){return &factions;}}game; Game* GetGame(){return &game;} namespace ERR_HQ{void Event(string,string){}} struct Service{Mode* m_Mode;bool m_Stopped=false,known=true,hidden=true,prepare=true;float m_Next=0,m_NextSpawn=0;int m_Serial=0,spawns=0;Array m_Cars;Array observers={{0,0,0}};bool Observers(Array& pos,Array&){pos=observers;return known;}bool Hidden(Vec,Array,IEntity* ignored=nullptr){return hidden;}bool Prepare(ERR_CivilianCar* t){if(prepare)t->Ready=true;return prepare;}int retries=0;bool issued=true;bool GiveRoute(ERR_CivilianCar*){retries++;return issued;}void Spawn(Array,Array,float){spawns++;} '''+methods+r''' }; struct Fixture{Mode mode;Group group;IEntity driver;Car car;ERR_CivilianCar traffic;Service service;Fixture(){ERR_GameMode::current=&mode;service.m_Mode=&mode;driver.group=&group;traffic.Group=&group;traffic.Car=&car;traffic.Driver=&driver;car.position=driver.position={1600,0,0};traffic.ProgressPosition=car.position;traffic.Finished=true;service.m_Cars={&traffic};mode.settings.target=0;}}; int main(){ assert(!ERR_CivilianTrafficRules::Far({999,0,0},{{0,0,0}},1000)); assert(ERR_CivilianTrafficRules::Far({1000,0,0},{{0,0,0}},1000)); assert(!ERR_CivilianTrafficRules::Far({1500,0,0},{{0,0,0},{1499,0,0}},1000)); assert(!ERR_CivilianTrafficRules::CleanupDue(59999,0)&&ERR_CivilianTrafficRules::CleanupDue(60000,0)); assert(!ERR_CivilianTrafficRules::CleanupDue(60000,-1)&&!ERR_CivilianTrafficRules::CleanupDue(0,1)); {Fixture f;f.service.Tick(0);assert(!f.car.deleted&&f.traffic.HiddenSince==0);f.service.Tick(55000);assert(!f.car.deleted);f.service.Tick(60000);assert(f.car.deleted&&f.driver.deleted&&f.group.deleted&&f.service.m_Cars.empty());} for(int fault=0;fault<4;fault++){ Fixture f;f.service.Tick(0); if(fault==0)f.car.position={1499,0,0}; if(fault==1)f.driver.position={1499,0,0}; if(fault==2)f.service.hidden=false; if(fault==3)f.service.known=false; f.service.Tick(60000);assert(!f.car.deleted&&f.traffic.HiddenSince==-1);f.car.position=f.driver.position={1600,0,0};f.service.hidden=f.service.known=true; f.service.Tick(65000);f.service.Tick(120000);assert(!f.car.deleted);f.service.Tick(125000);assert(f.car.deleted); } {Fixture f;IEntity player;player.player=true;IEntity door;door.parent=&f.car;f.service.PlayerEntered(&player,&door);assert(f.traffic.Released);f.car.captured=false;f.service.Tick(999999);f.service.Stop();assert(!f.car.deleted&&!f.driver.deleted&&f.traffic.cleared==1);} {Fixture f;IEntity ai;f.service.PlayerEntered(&ai,&f.car);assert(!f.traffic.Released);ai.player=true;IEntity unrelated;f.service.PlayerEntered(&ai,&unrelated);assert(!f.traffic.Released);Replication::server=false;f.service.PlayerEntered(&ai,&f.car);assert(!f.traffic.Released);Replication::server=true;} for(int fault=0;fault<6;fault++){ Fixture f;Group foreign;IEntity passenger;BaseCompartmentSlot seat;seat.occupant=&passenger; if(fault==0)f.car.captured=true; if(fault==1)f.group.captured=true; if(fault==2)f.driver.group=&foreign; if(fault==3)f.group.faction=2; if(fault==4)f.group.agents=2; if(fault==5)f.car.seats={&seat}; f.service.Tick(0);assert(f.traffic.Released);f.service.Tick(100000);assert(!f.car.deleted); } {Fixture f;f.driver.alive=false;f.driver.group=nullptr;f.service.Tick(0);assert(!f.traffic.Released);f.service.Tick(60000);assert(f.driver.deleted&&f.car.deleted);} {Fixture f;f.traffic.Ready=false;f.traffic.Finished=false;f.service.prepare=false;f.car.position=f.driver.position={100,0,0};f.service.Tick(120000);assert(f.traffic.Finished&&!f.car.deleted);} {Fixture f;f.traffic.Finished=false;f.traffic.ProgressAt=0;f.service.Tick(179999);assert(!f.traffic.Finished);f.service.Tick(185000);assert(f.traffic.Finished&&!f.car.deleted);} {Fixture f;f.service.m_Cars.clear();f.mode.settings.target=3;f.service.Tick(0);assert(f.service.spawns==1);f.service.Tick(29999);assert(f.service.spawns==1);f.service.Tick(35000);assert(f.service.spawns==2);f.service.m_Serial=64;f.service.Tick(70000);assert(f.service.spawns==2);} {Fixture f;f.traffic.Finished=false;f.car.position={100,0,0};f.traffic.ProgressPosition=f.car.position;f.traffic.Route[1]={1500,0,0}; f.service.Tick(59999);assert(f.service.retries==0); f.service.Tick(65000);assert(f.service.retries==1&&f.traffic.Retries==1&&!f.traffic.Finished); f.service.Tick(120000);assert(f.service.retries==2&&f.traffic.Retries==2); f.service.Tick(150000);assert(f.service.retries==2&&!f.traffic.Finished); f.service.Tick(180000);assert(f.traffic.Finished&&!f.car.deleted&&f.service.retries==2); } {Fixture f;f.traffic.Finished=false;f.car.position={100,0,0};f.traffic.ProgressPosition=f.car.position;f.traffic.Route[1]={1500,0,0};f.group.current=2; f.service.Tick(65000);assert(f.traffic.RouteStop==2&&f.service.retries==1); // Do not return to completed middle stop. f.car.position={140,0,0};f.service.Tick(70000);assert(f.traffic.ProgressAt==70000&&!f.traffic.Finished); } {Fixture f;f.traffic.Finished=false;f.car.position={100,0,0};f.traffic.ProgressPosition=f.car.position;f.service.issued=false; f.service.Tick(65000);f.service.Tick(120000);f.service.Tick(180000);assert(f.traffic.Finished&&f.service.retries==2&&!f.car.deleted); } {Fixture f;f.traffic.Finished=false;f.traffic.Group=nullptr;f.service.Drive(&f.traffic,65000);assert(f.traffic.Finished&&f.service.retries==0);} {Fixture f;f.traffic.Finished=false;f.car.position={100,0,0};f.traffic.ProgressPosition=f.car.position;f.traffic.Route[1]={1500,0,0};f.traffic.Orders[1]=0;f.group.current=0;f.service.Tick(65000);assert(f.traffic.RouteStop==1);} for(int fault=0;fault<7;fault++){ Fixture f;f.service.m_Cars.clear();f.mode.settings.target=3; if(fault==0)f.service.observers.clear(); if(fault==1)f.service.known=false; if(fault==2)f.mode.phase=1; if(fault==3)f.mode.active=false; if(fault==4)f.service.m_Stopped=true; if(fault==5)f.mode.settings.target=0; if(fault==6)Replication::server=false; f.service.Tick(0);assert(f.service.spawns==0);Replication::server=true; } } ''') # Integration boundaries: no military admission or late observer-driven retargets. s=p.read_text() assert '.RegisterGroup(' not in s and '.Own(' not in s assert 'm_Serial >= 64' in body(p,'protected bool Spawn(') assert 'Observers(observers, actors)' in body(p,'protected bool Spawn(') assert 'trace.ExcludeArray = excluded' in body(p,'protected bool Hidden(') assert 'sample = -1; sample <= 1' in body(p,'protected bool Hidden(') assert 'SetFactionsFriendly(civilian, other' in body(p,'protected bool Neutral(') game_mode=ROOT/'addons/core/Scripts/Game/ERR/00_Core/ERR_GameMode.c' assert 'ServerTickMeasured();' in body(game_mode,'protected void ServerTick(') assert 'm_CivilianTraffic.Tick(now)' in body(game_mode,'protected void ServerTickMeasured(') print('PASS: traffic distance/grace, all-observer veto, player claims, foreign custody, bounded spawn cadence, failure/stall retention and shutdown preserve nearby/claimed entities') observers=body(p,'protected bool Observers(').replace('protected ','').replace('array', 'Array&').replace('array', 'Array&').replace('array ids = {};','Array ids;').replace('foreach (','for (') observers=observers.replace('SCR_EditorManagerCore.Cast(SCR_EditorManagerCore.GetInstance(SCR_EditorManagerCore))','editorCore').replace('SCR_PlayerController.Cast(GetGame().GetPlayerManager().GetPlayerController(id))','GetGame().GetPlayerManager().GetPlayerController(id)') for typ in ('SCR_EditorManagerCore','SCR_EditorManagerEntity','SCR_PlayerController','IEntity'): observers=re.sub(r'\b'+typ+r' (?=\w)',typ+'* ',observers) for name in ('editors','editor','actor','controller','watched'): observers=observers.replace(name+'.',name+'->') observers=observers.replace('GetGame().','GetGame()->').replace('GetPlayerManager().','GetPlayerManager()->').replace('ERR_ObserverReason.NONE','0').replace('SCR_EditorManagerEntity* editor;', 'SCR_EditorManagerEntity* editor=nullptr;').replace('IEntity* watched;', 'IEntity* watched=nullptr;') run(r''' #include #include templatestruct Array:std::vector{using std::vector::vector;void Clear(){this->clear();}void Insert(T v){this->push_back(v);}}; struct Vec{float x=0;};struct IEntity{Vec p;Vec GetOrigin(){return p;}}; struct SCR_EditorManagerEntity{bool open=false;bool IsOpened(){return open;}}; struct SCR_EditorManagerCore{SCR_EditorManagerEntity* editor=nullptr;SCR_EditorManagerEntity* GetEditorManager(int){return editor;}};SCR_EditorManagerCore* editorCore=nullptr; struct SCR_PlayerController{int state=0;IEntity* watched=nullptr;int ERR_ObserverState(){return state;}IEntity* ERR_ObservedEntity(){return watched;}}; struct Players{Array ids={1};IEntity* actor=nullptr;SCR_PlayerController* controller=nullptr;void GetPlayers(Array& out){out=ids;}IEntity* GetPlayerControlledEntity(int){return actor;}SCR_PlayerController* GetPlayerController(int){return controller;}}; struct Game{Players players;Players* GetPlayerManager(){return &players;}}game;Game* GetGame(){return &game;} '''+observers+r''' int main(){ Array positions;Array actors;IEntity body,watched;body.p.x=100;watched.p.x=300;SCR_PlayerController controller;game.players.controller=&controller; assert(!Observers(positions,actors));game.players.actor=&body;assert(Observers(positions,actors)&&actors.size()==1&&positions[0].x==100); controller.state=1;assert(!Observers(positions,actors));controller.watched=&watched; assert(Observers(positions,actors)&&actors.size()==2&&positions[0].x==300&&positions[1].x==100); game.players.actor=nullptr;assert(Observers(positions,actors)&&actors.size()==1&&actors[0]==&watched); SCR_EditorManagerCore core;SCR_EditorManagerEntity editor;core.editor=&editor;editorCore=&core;editor.open=true;assert(!Observers(positions,actors)); editor.open=false;assert(Observers(positions,actors));game.players.controller=nullptr;assert(!Observers(positions,actors)); game.players.ids.clear();assert(Observers(positions,actors)&&positions.empty()&&actors.empty()); } ''') print('PASS: actual observer collection includes spectator targets and controlled bodies; missing views/controllers and open editor cameras veto spawn/cleanup') settings_path=ROOT/'addons/core/Scripts/Game/ERR/00_Core/ERR_Settings.c' settings='\n'.join(body(settings_path,x) for x in ('static bool Valid(', 'static int AddedDefault(', 'static bool Randomizable(')) command=body(ROOT/'addons/core/Scripts/Game/ERR/00_Core/ERR_AdminService.c','static string CoreSetting(') run('#include \n#include \nusing string=std::string;\nstruct Settings{'+settings+'\n'+command+r''' }; int main(){assert(Settings::AddedDefault("civilianTrafficCount")==3);assert(Settings::Valid("civilianTrafficCount",0));assert(Settings::Valid("civilianTrafficCount",6));assert(!Settings::Valid("civilianTrafficCount",-1));assert(!Settings::Valid("civilianTrafficCount",7));assert(!Settings::Randomizable("civilianTrafficCount"));assert(Settings::CoreSetting("mission","traffic")=="civilianTrafficCount");} ''') print('PASS: civilian traffic defaults to three; menu command resolves to persisted 0..6 setting with zero disabling new cars') exit_road=body(p,'protected bool ExitRoad(').replace('protected ','').replace('vector ', 'Vec ').replace('out Vec end','Vec& end').replace('array','std::vector').replace('foreach (','for (').replace('ERR_SupplyConvoySystem.','Road::').replace('vector.DistanceXZ','Geometry::DistanceXZ') run(r''' #include #include #include struct Vec{float x=0,y=0,z=0;float& operator[](int i){return i==0?x:i==1?y:z;}Vec operator+(Vec b){return {x+b.x,y+b.y,z+b.z};}Vec operator-(Vec b){return {x-b.x,y-b.y,z-b.z};}Vec operator*(float f){return {x*f,y*f,z*f};}}; Vec Vector(float x,float y,float z){return {x,y,z};} namespace Geometry{float DistanceXZ(Vec a,Vec b){return std::hypot(a.x-b.x,a.z-b.z);}} namespace Road{int calls=0,mode=0;bool ApproachDirected(Vec desired,Vec& end,Vec&,float){calls++;end=desired;if(mode==2)return false;if(mode==1)return desired.z>0;return true;}} '''+exit_road+r''' int main(){Vec end;assert(ExitRoad({0,0,0},{1,0,0},{1200,0,0},{0,0,400},end));assert(end.x==-1800&&Road::calls==1); Road::mode=1;Road::calls=0;assert(ExitRoad({0,0,0},{1,0,0},{1200,0,0},{0,0,400},end));assert(end.z==1800&&Road::calls==2); // opposite endpoint is water, turn along coast Road::mode=2;Road::calls=0;assert(!ExitRoad({0,0,0},{1,0,0},{1200,0,0},{0,0,400},end)&&Road::calls==3); } ''') print('PASS: bounded exit-road selection can turn along a coastline when the opposite road is unavailable; no-route case is withheld') protect=body(p,'void Protect(').replace('IEntity entity','IEntity* entity').replace('SCR_GarbageSystem garbage','SCR_GarbageSystem* garbage').replace('SCR_GarbageSystem.GetByEntityWorld','SCR_GarbageSystem::GetByEntityWorld').replace('garbage.','garbage->') run(r''' #include struct IEntity{bool held=false;}; struct SCR_GarbageSystem{inline static bool available=true;static SCR_GarbageSystem* GetByEntityWorld(IEntity*){static SCR_GarbageSystem instance;return available?&instance:nullptr;}void UpdateBlacklist(IEntity* entity,bool held){entity->held=held;}}; struct CarRecord{IEntity* Car=nullptr;IEntity* Driver=nullptr; '''+protect+r''' }; int main(){CarRecord record;record.Protect(true);IEntity car,driver;record.Car=&car;record.Driver=&driver;record.Protect(true);assert(car.held&&driver.held);record.Protect(false);assert(!car.held&&!driver.held);record.Car=nullptr;record.Protect(true);assert(driver.held);record.Protect(false);assert(!driver.held);SCR_GarbageSystem::available=false;record.Protect(true);assert(!driver.held);} ''') assert 'Protect(false)' in body(p,'void Release(') assert 'traffic.ClearOrders(); traffic.Protect(false);' in body(p,'void Tick(') print('PASS: managed traffic pins both native garbage entries; release/retirement removes only those pins, including partial creation')