"""Execute actual event, tracked-hunter match, bounded ancestry and both release layers.""" import os,re from pathlib import Path from policy_harness import ROOT,body,run base=Path(os.environ.get('ERR_HUNTER_CAPTURE_ROOT',ROOT)) p=base/'addons/core/Scripts/Game/ERR/10_AI' h=p/'ERR_HunterService.c';c=p/'ERR_ConvoyService.c' def tr(s): s=re.sub(r'//[^\n]*','',s).replace('override ','').replace('protected ','').replace('null','nullptr') s=s.replace('ERR_HQ.Cast(m_Mode.Command())','m_Mode.Command()').replace('ERR_HQ.Cast(mode.Command())','mode.Command()') s=s.replace('array','Array') s=re.sub(r'foreach \(([^:]+):',r'for (\1:',s) for t in ('IEntity','ERR_GameMode','ERR_HQ','ERR_HunterVehicle','BaseCompartmentManagerComponent','ERR_ForceRecord','AIAgent'): s=re.sub(r'\b'+t+r' (\w+)',t+r'* \1',s) for n in ('m_Mode','mode','hq','unit','Group','agent','record','Recovery','Tactics','CloseContact','entity'): s=re.sub(r'\b'+n+r'\.',n+'->',s) s=s.replace('Forces().','Forces()->').replace('Players().','Players()->').replace('Command().','Command()->').replace('Hunters().','Hunters()->').replace('CivilianTraffic().','CivilianTraffic()->') for n in ('Replication','ERR_GameMode','ERR_ConvoyRules','SCR_EntityHelper'):s=s.replace(n+'.',n+'::') s=s.replace('ERR_HQ* hq;','ERR_HQ* hq=nullptr;').replace('int depth;','int depth=0;') return s service=tr(body(h,'void PlayerEntered(')) if 'void PlayerEntered(' in h.read_text() else 'void PlayerEntered(IEntity*,IEntity*){}' event=tr(body(h,'override protected void OnCompartmentEntered(')).replace('super.','NativeAccess::') if 'override protected void OnCompartmentEntered(' in h.read_text() else 'void OnCompartmentEntered(IEntity* t,BaseCompartmentManagerComponent*m,int i,int s,bool b){NativeAccess::OnCompartmentEntered(t,m,i,s,b);}' base_release=tr(body(c,'void Release(ERR_GameMode mode)')) hunter_release=tr(body(h,'override void Release(ERR_GameMode mode)')).replace('super.','VehicleOwner::') part=tr(body(c,'static bool PartOf(')) run(r''' #include #include templatestruct Array:std::vector{using std::vector::vector;int Count(){return this->size();}}; struct IEntity{IEntity*parent=nullptr;IEntity*GetParent(){return parent;}}; struct AIAgent{int lod=0;void SetPermanentLOD(int n){lod=n;}}; struct GroupType{int lod=0;AIAgent a;void SetPermanentLOD(int n){lod=n;}void GetAgents(Array&v){v={&a};}}; struct BaseCompartmentManagerComponent{}; struct Service;struct ERR_HQ; struct Roster{IEntity*current=nullptr;void*CurrentActor(IEntity*a){return a&&a==current?this:nullptr;}}; struct ERR_ForceRecord{bool Pinned=true;};struct Ledger{ERR_ForceRecord r;ERR_ForceRecord*FindGroup(GroupType*){return &r;}}; struct Traffic{void PlayerEntered(IEntity*,IEntity*){}}; struct ERR_GameMode{Traffic* CivilianTraffic(){return nullptr;}inline static ERR_GameMode*current=nullptr;bool active=true;ERR_HQ*command=nullptr;Roster roster;Ledger ledger;static ERR_GameMode*Get(){return current;}bool Active(){return active;}ERR_HQ*Command(){return command;}Roster*Players(){return &roster;}Ledger*Forces(){return &ledger;}}; namespace Replication{bool server=true;bool IsServer(){return server;}} namespace ERR_ConvoyRules{bool occupied=false;bool Captured(IEntity*,GroupType*){return occupied;} '''+part+r''' } struct ERR_HQ{Service*service=nullptr;int retained=0,unregistered=0,recoveries=0;Service*Hunters(){return service;}bool ReleaseConvoySurvivors(GroupType*){retained++;return true;}void UnregisterGroup(GroupType*){unregistered++;}void ReleaseRecovery(GroupType*){recoveries++;}}; struct RecoveryTask{int stops=0;bool*captured=nullptr;void Stop(){stops++;if(captured)assert(*captured);}void Stop(ERR_GameMode*){Stop();}}; struct VehicleOwner{bool Released=false,Registered=true,PlayerCaptureObserved=false;IEntity*Entity=nullptr;GroupType*Group=nullptr;void*InterceptOrder=nullptr;struct{bool Held=true;}Combat;int SupplyToken=7;bool SupplyHeld=true;int orders=1,clears=0;void ClearIntercept(void*){}void ClearOrder(){orders=0;clears++;} '''+base_release+r''' }; struct ERR_HunterVehicle:VehicleOwner{RecoveryTask*Recovery=nullptr;RecoveryTask*Tactics=nullptr;RecoveryTask*CloseContact=nullptr;void*Downlink=this;void CancelHQDownlink(){Downlink=nullptr;} '''+hunter_release+r''' }; struct Service{bool m_Stopped=false;ERR_GameMode*m_Mode=nullptr;Arraym_Hunters; '''+service+r''' }; struct NativeAccess{IEntity*owner=nullptr;int nativeCalls=0;IEntity*GetOwner(){return owner;}void OnCompartmentEntered(IEntity*,BaseCompartmentManagerComponent*,int,int,bool){nativeCalls++;if(ERR_GameMode::current)ERR_GameMode::current->roster.current=nullptr;ERR_ConvoyRules::occupied=false;}}; struct Access:NativeAccess{ '''+event+r''' }; struct Case{ERR_GameMode mode,other;ERR_HQ hq,otherHQ;Service service,foreign;ERR_HunterVehicle unit;GroupType group;IEntity player,vehicle,turret,unrelated;RecoveryTask recovery,close;Access access; Case(){Replication::server=true;ERR_GameMode::current=&mode;mode.command=&hq;mode.roster.current=&player;hq.service=&service;service.m_Mode=&mode;service.m_Hunters={&unit};unit.Entity=&vehicle;unit.Group=&group;unit.Recovery=&recovery;unit.CloseContact=&close;turret.parent=&vehicle;access.owner=&player;} void Enter(IEntity*t=nullptr){access.OnCompartmentEntered(t?t:&turret,nullptr,1,2,false);} }; int main(){ {IEntity root;assert(ERR_ConvoyRules::PartOf(&root,&root));} {Case c;c.recovery.captured=&c.unit.PlayerCaptureObserved; // Native occupancy is not visible yet; super removes current identity to model // disconnect/body loss before next one-second poll. Event must win that gap. c.Enter();assert(c.unit.PlayerCaptureObserved&&c.unit.Released);assert(c.access.nativeCalls==1); assert(c.hq.unregistered==1&&c.hq.retained==0&&c.hq.recoveries==0); assert(c.close.stops==1&&c.recovery.stops==1&&c.unit.Downlink==nullptr&&c.unit.orders==0&&c.unit.clears==1); assert(!c.mode.ledger.r.Pinned&&c.unit.Entity==&c.vehicle&&c.unit.Group==&c.group); c.mode.roster.current=&c.player;c.Enter();assert(c.access.nativeCalls==2&&c.recovery.stops==1&&c.hq.unregistered==1); } for(int bad=0;bad<8;bad++){Case c; if(bad==0)Replication::server=false; if(bad==1)c.service.m_Stopped=true; if(bad==2)c.mode.active=false; if(bad==3)c.service.m_Mode=&c.other; if(bad==4)c.mode.command=&c.otherHQ; if(bad==5)c.hq.service=&c.foreign; if(bad==6)c.mode.roster.current=&c.unrelated; if(bad==7)c.unit.Entity=nullptr; c.Enter();assert(!c.unit.PlayerCaptureObserved&&!c.unit.Released&&c.hq.unregistered==0&&c.access.nativeCalls==1); } {Case c;c.service.m_Hunters.resize(100,&c.unit);c.Enter();assert(c.unit.PlayerCaptureObserved&&c.unit.Released&&c.hq.unregistered==1);} {Case c;c.Enter(&c.unrelated);assert(!c.unit.Released&&c.access.nativeCalls==1);} {Case c;IEntity chain[33];for(int i=0;i<32;i++)chain[i].parent=&chain[i+1];chain[32].parent=&c.vehicle;c.Enter(&chain[0]);assert(!c.unit.Released);} {Case c;IEntity loop;loop.parent=&loop;c.Enter(&loop);assert(!c.unit.Released);} {Case c;c.Enter(&c.vehicle);assert(c.unit.Released);} // root as well as turret child {Case c;c.unit.Release(&c.mode);assert(c.unit.Released&&c.hq.recoveries==1&&c.hq.unregistered==0);c.Enter();assert(!c.unit.PlayerCaptureObserved&&c.hq.unregistered==0&&c.hq.recoveries==1);} // abandoned asset does not revoke independent survivors {Case c;c.unit.PlayerCaptureObserved=true;c.unit.Release(&c.mode);assert(c.hq.unregistered==1&&c.hq.retained==0&&!c.unit.Downlink);} // latch reaches both release layers without current occupant {Case c;c.service.PlayerEntered(nullptr,&c.vehicle);c.service.PlayerEntered(&c.player,nullptr);assert(!c.unit.Released);} } ''') print('PASS: actual player-entry hook latches original hunter capture before native callbacks; both release layers cancel ownership without new entities/refund; bounded current-owner guards and prior-release policy')