"""Actual opt-in setup/tick/terminal/cleanup methods, native boundaries doubled.""" from pathlib import Path import os,re from policy_harness import ROOT,body,run p=Path(os.environ.get('ERR_SMOKE_SOURCE',ROOT/'addons/core/Scripts/Game/ERR/40_Chat/ERR_NativeSmoke.c')) s=p.read_text() # Enforce script instances are managed references. The engine may destroy the # probe when its sole owning field is cleared; C++ raw pointers do not model # this lifetime. Require the strong local explicitly, independently of the # actual-method behavioral doubles below. cleanup=body(p,'void ERR_StopSupplyTravel(') retain='ref ERR_NativeSupplyTravelProbe probe = m_ERRSupplyTravel;' detach='m_ERRSupplyTravel = null;' stop='if (probe) probe.Stop();' assert retain in cleanup, 'cleanup must retain the managed probe before detaching its owner' assert cleanup.index(retain) < cleanup.index(detach) < cleanup.index(stop) assert not re.search(r'\bprobe\s*=\s*null',cleanup[:cleanup.index(stop)]), 'do not drop the retained local before Stop' methods='\n'.join(body(p,x) for x in ('void ERR_StopSupplyTravel(', 'void ERR_BeginSupplyTravel(', 'void ERR_TickSupplyTravel(')) methods=methods.replace('protected ','').replace('ref ','').replace('null','nullptr') methods=methods.replace('DamageManagerComponent.Cast(m_ERRSmokePlayer.FindComponent(DamageManagerComponent))','m_ERRSmokePlayer->damage').replace('ERR_HQ.Cast(Command())','Command()').replace('ERR_Phase.DEFEAT','2') for typ in ['ERR_NativeSupplyTravelProbe','DamageManagerComponent']: methods=re.sub(r'\b'+typ+r' (\w+)',typ+r'* \1',methods) for obj in ['probe','damage','m_ERRSupplyTravel','m_ERRSupplyTravelObserverDamage']: methods=methods.replace(obj+'.',obj+'->') methods=methods.replace('Players().','Players()->') terminal=body(p,'if (m_ERRTestSupplyTravel)\n\t\t{') terminal=terminal.replace('ERR_Phase.DEFEAT','2').replace('GetGame().GetCallqueue().Remove(ERR_SmokeTick);','removed++;').replace('ERR_StopHQPatrol();','ERR_StopSupplyTravel();') # Actual startup expressions/deadline, not a duplicate selector model. a=s.index('m_ERRTestLostHelicopter = System.GetCLIParam(');b=s.index('OnStop().Insert(ERR_StopHQPatrol);',a) selector=s[a:b].replace('System.GetCLIParam("errSmokeOutcome", outcome) && ','').replace('GetWorld().GetWorldTime()','now') selector=re.sub(r'ERR_Native\w+Probe.Enabled\(\)','false',selector) flags=sorted(set(re.findall(r'\bm_ERRTest\w+',selector))) run(r''' #include #include using string=std::string; struct DamageManagerComponent{bool enabled=true;int writes=0;bool IsDamageHandlingEnabled(){return enabled;}void EnableDamageHandling(bool e){enabled=e;writes++;}}; struct Actor{DamageManagerComponent*damage=nullptr;};struct ERR_HQ{};struct Fixture; struct ERR_NativeSupplyTravelProbe{static inline int created=0;int result=0,stops=0,ticks=0;float begun=0;ERR_HQ*seen=nullptr;ERR_NativeSupplyTravelProbe(Fixture*,float now){created++;begun=now;}void Stop(){stops++;}int Tick(ERR_HQ*h,float){seen=h;ticks++;return result;}}; struct Roster{Actor*current=nullptr;bool CurrentActor(Actor*a){return a&&a==current;}}; struct Fixture{Actor actor;DamageManagerComponent damage;Roster roster;ERR_HQ hq;Actor*m_ERRSmokePlayer=&actor;ERR_NativeSupplyTravelProbe*m_ERRSupplyTravel=nullptr;DamageManagerComponent*m_ERRSupplyTravelObserverDamage=nullptr;bool m_ERRSupplyTravelObserverDamageEnabled=false,m_ERRSmokeDone=false,m_ERRTestSupplyTravel=true,unlock=true;int m_ERRSmokeStep=0,failed=0,unlocks=0,transition=0,removed=0;string printed; Fixture(){actor.damage=&damage;roster.current=&actor;}Roster*Players(){return &roster;}ERR_HQ*Command(){return &hq;}void Print(string s){printed=s;}bool UnlockPrison(Actor*a){assert(a==&actor&&!damage.enabled);unlocks++;return unlock;}void Transition(int p){transition=p;}bool ERR_Check(bool ok,string){if(!ok){failed++;m_ERRSmokeDone=true;ERR_StopSupplyTravel();}return ok;} METHODS void Finish(int current){TERMINAL} }; void selector(string outcome,float now){[[maybe_unused]] bool FLAGS;float m_ERRSmokeDeadline=0;SELECTOR if(outcome=="supply-travel"){assert(m_ERRTestSupplyTravel&&!m_ERRTestConvoy&&!m_ERRTestPlayerDeath&&m_ERRSmokeDeadline==now+420000);}else assert(!m_ERRTestSupplyTravel); } int main(){ selector("supply-travel",0);selector("supply-travel",1234);selector("convoy",0);selector("supply-convoys",0);selector("normal-escape-route",0); Fixture f;f.ERR_BeginSupplyTravel(100);auto p=f.m_ERRSupplyTravel;assert(p&&p->begun==100&&f.m_ERRSmokeStep==3200&&f.unlocks==1&&!f.damage.enabled); f.ERR_TickSupplyTravel(500);assert(p->ticks==1&&p->seen==&f.hq&&f.transition==0); p->result=1;f.ERR_TickSupplyTravel(1000);assert(f.m_ERRSmokeStep==3201&&f.transition==2); f.Finish(2);assert(f.m_ERRSmokeDone&&f.removed==1&&p->stops==1&&f.damage.enabled&&!f.m_ERRSupplyTravel&&!f.m_ERRSupplyTravelObserverDamage); assert(f.printed=="ERR SMOKE COMPLETE: production supply convoy original six-vehicle travel; tactics and interception unqualified"); int writes=f.damage.writes;f.ERR_StopSupplyTravel();assert(f.damage.writes==writes&&p->stops==1); Fixture disabled;disabled.damage.enabled=false;disabled.ERR_BeginSupplyTravel(100);disabled.ERR_StopSupplyTravel();assert(!disabled.damage.enabled); Fixture refused;refused.unlock=false;int before=ERR_NativeSupplyTravelProbe::created;refused.ERR_BeginSupplyTravel(100);assert(refused.failed==1&&refused.damage.enabled&&!refused.m_ERRSupplyTravel&&ERR_NativeSupplyTravelProbe::created==before); Fixture replaced;replaced.ERR_BeginSupplyTravel(100);Actor next;DamageManagerComponent nextDamage;next.damage=&nextDamage;replaced.m_ERRSmokePlayer=&next;replaced.ERR_StopSupplyTravel();assert(replaced.damage.enabled&&nextDamage.writes==0); Fixture lost;lost.roster.current=nullptr;lost.ERR_BeginSupplyTravel(100);assert(lost.failed==1&&lost.unlocks==0&&lost.damage.writes==0); Fixture missing;missing.actor.damage=nullptr;missing.ERR_BeginSupplyTravel(100);assert(missing.failed==1&&missing.unlocks==0&&!missing.m_ERRSupplyTravel); Fixture bad;bad.ERR_BeginSupplyTravel(100);auto bp=bad.m_ERRSupplyTravel;bp->result=-1;bad.ERR_TickSupplyTravel(500);assert(bad.failed==1&&bad.damage.enabled&&bp->stops==1&&bad.transition==0); Fixture premature;premature.ERR_BeginSupplyTravel(100);premature.Finish(2);assert(premature.failed==1&&premature.damage.enabled&&premature.printed.find("COMPLETE")==string::npos); } '''.replace('METHODS',methods).replace('TERMINAL',terminal).replace('FLAGS',','.join(f+'=false' for f in flags)).replace('SELECTOR',selector)) assert s.startswith('// Explicit, local Workbench diagnostic only.') and '#ifdef WORKBENCH' in s setup=body(p,'void ERR_BeginSupplyTravel(') for forbidden in ['StartConvoy','SetPerceivedFaction','SetOrigin','Teleport','Hunters()', 'Settings(', 'StartSupply', 'EnemyFaction']: assert forbidden not in setup,forbidden assert 'ERR_StopSupplyTravel();' in body(p,'void ERR_StopHQPatrol(') assert 'ERR_StopHQPatrol();' in body(p,'bool ERR_Check(') assert 'OnStop().Insert(ERR_StopHQPatrol);' in s step=body(p,'void ERR_SmokeTick(') assert step.index('now > m_ERRSmokeDeadline') < step.index('m_ERRSmokeStep == 3200') assert step.index('ERR_CheckCompanionCommands()') < step.index('if (m_ERRTestSupplyTravel) { ERR_BeginSupplyTravel(now); return; }') < step.index('if (m_ERRTestConvoy)') assert 'm_ERRSmokeDeadline' not in methods print('PASS: actual distinct supply-travel hook, fixed420s selector, original observer protection/restoration, failure/terminal cleanup and no legacy convoy setup')