"""Actual start policy/setup/freeze methods; engine/resource/terrain boundaries doubled.""" import os,sys from pathlib import Path ROOT=Path(os.environ.get('ERR_REPO',Path(__file__).resolve().parents[1])) P=Path(os.environ.get('ERR_CRASH_CORE_ROOT',ROOT)) sys.path.insert(0,str(ROOT/'tests')) from policy_harness import body,run C='addons/core/Scripts/Game/ERR/00_Core/' def source(name):return P/C/name def cpp(s): for a,b in [('protected ',''),('ERR_ForceRules.','ERR_ForceRules::'),('ERR_StartRules.','Rules::'),('ERR_CrashSiteResources.','Resources::'),('ERR_LocationKind.','Kind::'),('Math.','Math::'),('vector.Zero','vector{}'),('out vector ','vector& '),('out float ','float& ')]:s=s.replace(a,b) return s rules='\n'.join(cpp(body(source('ERR_StartRules.c'),sig)) for sig in ['static bool Valid(','static bool Geometry(']) setup='\n'.join(cpp(body(source('ERR_StartSetup.c'),sig)) for sig in ['static bool IsCrash(','static bool Geometry(','static bool Configure(']) for a,b in [('ERR_SiteDefinition site','Site* site'),('ERR_SiteDefinition start;','Site* start=nullptr;'),('ERR_ScenarioDefinition definition','Definition* definition'),('ERR_SiteProp wreck','Prop* wreck'),('ref Prop*','Prop*'),('new ERR_SiteProp()','new Prop()'),('new array()','new Array()'),('foreach (','for ('),('int count;','int count=0;')]:setup=setup.replace(a,b) for var in ['site','start','definition','wreck']:setup=setup.replace(var+'.',var+'->') setup=setup.replace('start->Props.Insert','start->Props->Insert').replace('.IsEmpty()','.empty()') run(r''' #include #include #include #include #include #define null nullptr struct vector{float a[3]{};float&operator[](int i){return a[i];}float operator[](int i)const{return a[i];}float Length(){return std::sqrt(a[0]*a[0]+a[1]*a[1]+a[2]*a[2]);}}; vector Vector(float x,float y,float z){return{{x,y,z}};}vector operator+(vector a,vector b){return Vector(a[0]+b[0],a[1]+b[1],a[2]+b[2]);}vector operator*(vector a,float b){return Vector(a[0]*b,a[1]*b,a[2]*b);} namespace ERR_ForceRules{bool Finite(float x){return std::isfinite(x);}} namespace Math{float Ceil(float x){return std::ceil(x);}float Max(float x,float y){return std::fmax(x,y);}float AbsFloat(float x){return std::fabs(x);}} struct Rules{RULES}; namespace Kind{constexpr int PRISON=0;} templatestruct Array:std::vector{using std::vector::operator=;void Insert(T x){this->push_back(x);}}; struct Prop{std::string Prefab;vector Offset;}; struct Site{int Kind=0,GuardCount=6,ResponseCount=2;bool Guarded=true,AllowFactionPool=true,RandomClear=false;std::string Prefab="prison",Label="Prison",Guards="guards",Container="finite-bag",Id="original";float RootHeight=2;int*Patrol=(int*)1;void*Stock=(void*)2;vector ContainerOffset=Vector(-4,0,0);Array*Props=nullptr;}; struct Definition{ArraySites;bool valid=true;int calls=0;bool Valid(){calls++;return valid;}}; namespace Resources{bool ready=true;vector low=Vector(-4,-1,-3),high=Vector(6,4,3);std::string SitePrefab(){return"crash-site";}std::string WreckPrefab(){return"wreck";}bool Bounds(vector&lo,vector&hi){lo=low;hi=high;return ready;}} struct Setup{SETUP}; int main(){ assert(Rules::Valid(0)&&Rules::Valid(1)&&!Rules::Valid(-1)&&!Rules::Valid(2)); vector offset,center;float half,height; assert(Rules::Geometry(Resources::low,Resources::high,offset,center,half,height));assert(offset[0]+Resources::low[0]==12&&offset[1]==1&&half==6&&height==6); for(int a=0;a<3;a++)for(float bad:{std::numeric_limits::infinity(),std::numeric_limits::quiet_NaN()}){vector lo=Resources::low;lo[a]=bad;assert(!Rules::Geometry(lo,Resources::high,offset,center,half,height)&&half==0&&height==0&&offset[0]==0);} assert(!Rules::Geometry(Vector(0,0,100),Vector(1,1,101),offset,center,half,height));assert(!Rules::Geometry(Vector(0,0,0),Vector(0,1,1),offset,center,half,height));assert(!Rules::Geometry(Vector(-50,0,0),Vector(-49,1,1),offset,center,half,height));assert(!Rules::Geometry(Vector(0,0,0),Vector(31,1,1),offset,center,half,height));assert(!Rules::Geometry(Vector(0,0,0),Vector(1,21,1),offset,center,half,height)); Site prison;Definition original;original.Sites={&prison};Resources::ready=false;assert(Setup::Configure(&original,0)&&prison.Guarded&&prison.Prefab=="prison"&&prison.ResponseCount==2&&prison.RootHeight==2&&original.calls==0); assert(!Setup::Configure(&original,1)&&prison.Prefab=="prison");Resources::ready=true; assert(Setup::Configure(&original,1)&&original.calls==1&&Setup::IsCrash(&prison));assert(!prison.Guarded&&prison.Guards.empty()&&prison.GuardCount==0&&prison.ResponseCount==0&&!prison.Patrol&&!prison.AllowFactionPool&&prison.RandomClear&&prison.RootHeight==0); assert(prison.Stock==(void*)2&&prison.Container=="finite-bag"&&prison.Id=="original"&&prison.ContainerOffset[0]==-4&&prison.Props->size()==1&&(*prison.Props)[0]->Prefab=="wreck"&&(*prison.Props)[0]->Offset[0]==16); for(int fault=0;fault<7;fault++){Site a,b;Definition d;d.Sites={&a};if(fault==0)d.Sites.clear();if(fault==1)d.Sites.push_back(&b);if(fault==2)a.Container="";if(fault==3)a.ContainerOffset[0]=9;if(fault==4)a.ContainerOffset[1]=2;if(fault==5)d.valid=false;assert(!Setup::Configure(fault==6?nullptr:&d,1));} assert(!Setup::Configure(&original,-1)); } '''.replace('RULES',rules).replace('SETUP',setup)) # Actual once-only server freeze, including failed settings and restart/new owner. freeze=body(source('ERR_GameMode.c'),'protected bool FreezeStartMode(').replace('protected ','').replace('Replication.','Replication::').replace('ERR_Phase.','Phase::').replace('ERR_StartRules.','Rules::').replace('m_Settings.','m_Settings->') run(r''' #include #include namespace Replication{bool server=true;int bumps=0;bool IsServer(){return server;}void BumpMe(){bumps++;}} namespace Phase{constexpr int PREPARING=0;} namespace Rules{bool Valid(int n){return n==0||n==1;}} struct Settings{int value=0,reads=0;int Get(std::string key){assert(key=="startMode");reads++;return value;}}; struct Mode{bool m_Stopped=false,m_NativeEndHandled=false,m_StartModeFrozen=false;int m_Phase=0,m_StartMode=0;Settings*m_Settings=nullptr;METHOD}; int main(){Settings s;Mode p;p.m_Settings=&s;assert(p.FreezeStartMode()&&p.m_StartMode==0);s.value=1;assert(p.FreezeStartMode()&&p.m_StartMode==0&&s.reads==1);Mode restart;restart.m_Settings=&s;assert(restart.FreezeStartMode()&&restart.m_StartMode==1);for(int f=0;f<6;f++){Mode x;x.m_Settings=&s;if(f==0)Replication::server=false;if(f==1)x.m_Stopped=true;if(f==2)x.m_NativeEndHandled=true;if(f==3)x.m_Phase=1;if(f==4)x.m_Settings=nullptr;if(f==5)s.value=2;assert(!x.FreezeStartMode()&&!x.m_StartModeFrozen);Replication::server=true;s.value=1;}} '''.replace('METHOD',freeze)) # Actual transition policy retains all default edges; crash authorization adds # only initial RADIO_SEARCH and cannot add a terminal or downstream shortcut. policy='\n'.join(body(source('ERR_MissionRules.c'),sig) for sig in ['static bool Terminal(','static bool CanTransition(']).replace('ERR_Phase.','Phase::') run(r''' #include namespace Phase{enum{PREPARING,PRISON,RADIO_SEARCH,RADIO_DEFENCE,EXTRACTION,VICTORY,DEFEAT};} POLICY int main(){for(int from=0;from<=6;from++)for(int to=0;to<=6;to++){bool old=(from<5&&to==from+1)||(from>=1&&from<=4&&to==6);assert(CanTransition(from,to)==old);assert(CanTransition(from,to,true)==(from==0?to==2:old));}} '''.replace('POLICY',policy)) mode=source('ERR_GameMode.c').read_text();scenario=source('ERR_ScenarioComponent.c').read_text() transition=body(source('ERR_GameMode.c'),'bool Transition(') assert 'm_StartModeFrozen && m_StartPrepared && m_StartMode == 1' in transition assert 'm_Phase == ERR_Phase.PREPARING && !m_StartPrepared' in transition start=body(source('ERR_GameMode.c'),'protected void StartScenario(') assert start.index('FreezeStartMode()') #include namespace Replication{bool server=true;bool IsServer(){return server;}} namespace Phase{enum{PREPARING,PRISON,RADIO_SEARCH,RADIO_DEFENCE,EXTRACTION,VICTORY,DEFEAT};} namespace Policy{POLICY} struct Mode{int m_Phase=0,m_StartMode=1;bool m_StartModeFrozen=false,m_StartPrepared=false;std::string m_PreparationError;ADMIT}; int main(){Mode crash;assert(!crash.Transition(2));crash.m_StartModeFrozen=true;assert(!crash.Transition(2));crash.m_StartPrepared=true;assert(crash.Transition(2)&&!crash.Transition(1));crash.m_PreparationError="failed";assert(!crash.Transition(2));crash.m_PreparationError="";Replication::server=false;assert(!crash.Transition(2));Replication::server=true;Mode prison;prison.m_StartMode=0;prison.m_StartModeFrozen=true;prison.m_StartPrepared=true;assert(prison.Transition(1)&&!prison.Transition(2));prison.m_Phase=1;assert(prison.Transition(2));} '''.replace('POLICY',policy).replace('ADMIT',admit)) # Execute actual common site survey to prove both measured wreck and start/cache # areas are required and that unknown measured bounds cannot fall back to10m. site=body(source('ERR_GeneratedSites.c'),'bool Site(') for a,b in [('ERR_SiteDefinition site','SiteData* site'),('site.','site->'),('foreach (','for ('),('ERR_LocationKind.','Kind::'),('ERR_StartSetup.','StartSetup::'),('SCR_AIWorld aiWorld = SCR_AIWorld.Cast(GetGame().GetAIWorld());','AIWorld* aiWorld = &world;'),('aiWorld.GetRoadNetworkManager()','aiWorld->GetRoadNetworkManager()'),('GetRoadNetworkManager().','GetRoadNetworkManager()->'),('BaseRoad road; float distance;','Road* road=nullptr; float distance=0;'),('skipNavlinks: true','true'),('out float ','float& '),('vector.DistanceXZ','DistanceXZ')]:site=site.replace(a,b) run(r''' #include #include #include #define null nullptr struct vector{float x=0,y=0,z=0;};vector operator+(vector a,vector b){return{a.x+b.x,a.y+b.y,a.z+b.z};}float DistanceXZ(vector a,vector b){return std::hypot(a.x-b.x,a.z-b.z);} namespace Kind{constexpr int PRISON=0;} struct SiteData{int Kind=0,ResponseCount=0;bool Guarded=false,crash=false;vector GuardOffset,ResponseOffset;}; namespace StartSetup{bool measured=true;bool IsCrash(SiteData*s){return s->crash;}bool Geometry(vector&offset,vector¢er,float&half,float&height){offset={16,1,0};center={17,0,0};half=6;height=6;return measured;}} struct Road{};struct RoadManager{void GetClosestRoad(vector,Road*&,float&,bool){}};struct AIWorld{RoadManager roads;RoadManager*GetRoadNetworkManager(){return &roads;}}; struct Call{vector p;float half,height;}; struct Survey{AIWorld world;std::vectorm_Airfields;std::vectorcalls;int refuse=0;vector Rotate(vector p,float h){assert(h==90);return{p.z,p.y,-p.x};}bool Clear(vector p,float,float half,float,float&floor,float height=4){calls.push_back({p,half,height});floor=42;return int(calls.size())!=refuse;}SITE}; int main(){SiteData a;float floor=0;Survey normal;assert(normal.Site(&a,{100,0,200},90,floor)&&normal.calls.size()==1&&normal.calls[0].half==10&&normal.calls[0].height==4);a.crash=true;Survey crash;assert(crash.Site(&a,{100,0,200},90,floor)&&crash.calls.size()==2);assert(crash.calls[1].p.x==100&&crash.calls[1].p.z==183&&crash.calls[1].half==6&&crash.calls[1].height==6);for(int refusal:{1,2}){Survey blocked;blocked.refuse=refusal;assert(!blocked.Site(&a,{100,0,200},90,floor));}StartSetup::measured=false;Survey unknown;assert(!unknown.Site(&a,{100,0,200},90,floor)&&unknown.calls.size()==1);} '''.replace('SITE',site)) print('PASS: actual GameMode readiness admission and common full-footprint survey require crash authorization and both surveyed areas')