"""Execute the actual local terrain selector against deterministic native boundary doubles.""" from policy_harness import ROOT, body, run import re P = ROOT / 'addons/core/Scripts/Game/ERR/10_AI/ERR_HQTacticalGround.c' A = ROOT / 'addons/core/Scripts/Game/ERR/10_AI/ERR_HQCoordinated.c' def cpp(s): s = s.replace('protected static float s_Window', 'inline static float s_Window') s = s.replace('protected static int s_Samples', 'inline static int s_Samples') s = s.replace('protected ', '').replace('out vector ', 'vector& ') s = s.replace('class ERR_HQTacticalGround', 'struct ERR_HQTacticalGround') for name in ('ERR_HQMemoryRules', 'ERR_HQTacticalGroundRules', 'ERR_HQOperationRole', 'ERR_Actors', 'ChimeraWorldUtils', 'TraceFlags', 'Math', 'vector'): s = s.replace(name + '.', name + '::') s = s.replace('AIPathfindingComponent.Cast(group.FindComponent(AIPathfindingComponent))', 'group->path') s = s.replace('ChimeraCharacter.Cast(parent)', 'parent->character') s = s.replace('Vehicle.Cast(parent)', 'parent->vehicle') for kind in ('IEntity', 'Physics', 'TraceParam', 'TraceBox', 'SCR_AIGroup', 'ERR_HQTask', 'ERR_AttackSpace', 'AIPathfindingComponent', 'NavmeshWorldComponent', 'ERR_HQUnit', 'ERR_HQWatchEntry', 'ERR_HQBelief', 'ERR_HQOperationSlot', 'ERR_HQTacticalGround'): s = re.sub(r'\b' + kind + r' (\w+)', kind + r'* \1', s) for name in ('parent', 'physics', 'trace', 'volume', 'path', 'navmesh', 'task', 'occupied', 'unit', 'own', 'belief', 'slot', 'Report', 'Task', 'survey'): s = s.replace(name + '.', name + '->') s = s.replace('GetGame().GetWorld().', 'GetGame()->GetWorld()->') s = s.replace('GetGame().GetWorld()', 'GetGame()->GetWorld()') s = s.replace('TraceMove(trace, StaticObstacle)', 'TraceMove(trace, [this](IEntity* e){return StaticObstacle(e);})') s = s.replace('TraceMove(volume, StaticObstacle)', 'TraceMove(volume, [this](IEntity* e){return StaticObstacle(e);})') s = re.sub(r'"(-?[0-9.]+) (-?[0-9.]+) (-?[0-9.]+)"', r'Vector(\1,\2,\3)', s) s = re.sub(r'\bbool (found|sampled|standingClear|lowCovered|approachCovered);', r'bool \1=false;', s) s = s.replace('int requested;', 'int requested=0;').replace('float bestScore;', 'float bestScore=0;') return s rules = cpp(body(P, 'class ERR_HQTacticalGroundRules')) + ';' selector = cpp(body(P, 'class ERR_HQTacticalGround\n')) + ';' adapter = cpp(body(A, 'protected bool CoordinatedGround(')).replace(', m_AttackSpace,', ', &m_AttackSpace,') run(r''' #include #include #include #include #include #include using string=std::string; struct vector { float x=0,y=0,z=0;float& operator[](int i){return i==0?x:i==1?y:z;} vector operator+(vector b)const{return{x+b.x,y+b.y,z+b.z};} vector operator-(vector b)const{return{x-b.x,y-b.y,z-b.z};} vector operator*(float n)const{return{x*n,y*n,z*n};} float Length()const{return std::sqrt(x*x+y*y+z*z);} vector Normalized()const{return *this*(1/Length());} void Normalize(){*this=Normalized();} static float DistanceXZ(vector a,vector b){return std::hypot(a.x-b.x,a.z-b.z);} }; vector Vector(float x,float y,float z){return{x,y,z};} struct Math{static float AbsFloat(float v){return std::abs(v);}static float Min(float a,float b){return std::min(a,b);}}; struct ERR_HQMemoryRules{ static bool Finite(float v){return std::isfinite(v)&&std::abs(v)<=1e12;} static bool PositionValid(vector p){return Finite(p.x)&&Finite(p.y)&&Finite(p.z)&&std::abs(p.x)<=1e6&&std::abs(p.y)<=1e6&&std::abs(p.z)<=1e6;} static bool DeliveryFresh(float at,float now){return Finite(at)&&Finite(now)&&at>=0&&now>=at&&now-at<=120000;} }; enum class ERR_HQOperationRole{OBSERVE,FIX,FLANK,BLOCK,SEARCH,RESERVE,WITHDRAW}; struct ERR_HQTask{ERR_HQOperationRole OperationRole=ERR_HQOperationRole::OBSERVE;vector Destination{100,.1,100},SupportPosition{100,.1,0};float SupportUntil=30000;int OperationId=1,BeliefId=1,BeliefRevision=2,ExecutionId=1;}; struct Physics{bool dynamic=false;bool IsDynamic(){return dynamic;}}; struct IEntity{bool character=false,vehicle=false;Physics*physics=nullptr;IEntity*parent=nullptr;Physics*GetPhysics(){return physics;}IEntity*GetParent(){return parent;}}; struct TraceParam{vector Start,End;int Flags=0;}; struct TraceBox:TraceParam{vector Mins,Maxs;}; struct TraceFlags{enum{WORLD=1,ENTS=2};}; struct NativeWorld{ int scene=0,rays=0,boxes=0;bool cliff=false,water=false; float Surface(vector p){return cliff&&p.x>100?4.1:.1;} float TraceMove(TraceBox*,const std::function&){boxes++;return 1;} float TraceMove(TraceParam*t,const std::function&){ rays++; if(scene==3)return std::numeric_limits::quiet_NaN(); if(scene==4)return 0; if(scene==1||scene==2){ if(t->Start.z<84&&std::abs(t->Start.x-100)<1)return .01; // blind wall north if(t->Start.x<84&&std::abs(t->Start.z-100)<13){ if(t->Start.y<1.4)return .025; // low wall west with clear standing view } } return 1; } } world; struct Game{NativeWorld*GetWorld(){return &world;}} game; Game*GetGame(){return &game;} struct ERR_Actors{static vector Ground(vector p){p.y=world.Surface(p);return p;}}; struct ChimeraWorldUtils{static bool TryGetWaterSurfaceSimple(NativeWorld*,vector p){return world.water&&p.x>101;}}; struct NavmeshWorldComponent{ bool loaded=true;int requests=0;bool IsTileLoaded(vector){return loaded;} bool IsTileRequested(vector){return false;}void LoadTileIn(vector){requests++;} }; struct AIPathfindingComponent{ bool allow=true;vector delta;NavmeshWorldComponent nav;int projections=0; NavmeshWorldComponent*GetNavmeshComponent(){return &nav;} bool GetClosestPositionOnNavmesh(vector p,vector,vector&out){projections++;out=p+delta;return allow;} }; struct SCR_AIGroup{AIPathfindingComponent*path=nullptr;}; struct ERR_AttackSpace{bool allow=true;int checks=0;bool Free(SCR_AIGroup*,vector,float){checks++;return allow;}}; '''+rules+selector+r''' struct ERR_HQWatchEntry{bool Closed=false;int Fit=4;float ObservedAt=1000;vector Position{100,.1,200};}; struct ERR_HQBelief{int BeliefRevision=2;vector Position{100,.1,0};}; struct ERR_HQExecutionReport{int ExecutionId=1;float ObservedAt=2000;vector Position{100,.1,100};}; struct ERR_HQOperationSlot{ERR_HQExecutionReport*Report=nullptr;}; struct ERR_HQUnit{SCR_AIGroup*Group=nullptr;void*Utility=this;bool HomeGuard=false,ReservedForSupport=false;int LogisticsReservation=0,Id=1;string ForceSourceId="one";ERR_HQTask*Task=nullptr;}; struct Watch{ERR_HQWatchEntry*entry=nullptr;ERR_HQWatchEntry*Find(string){return entry;}}; struct Memory{ERR_HQBelief*belief=nullptr;ERR_HQBelief*GetById(int){return belief;}}; struct Operations{ERR_HQOperationSlot*slot=nullptr;ERR_HQOperationSlot*Find(int){return slot;}}; struct Adapter{Watch m_Watch;Memory m_Memory;Operations m_Operations;ERR_AttackSpace m_AttackSpace; '''+adapter+r''' }; int main(){ using R=ERR_HQTacticalGroundRules;using Role=ERR_HQOperationRole; vector anchor{100,.1,100},from{100,.1,200},threat{100,.1,0},selected; float nan=std::numeric_limits::quiet_NaN(); // At an otherwise identical point the observer prefers a usable low wall, // while a withdrawing squad prefers concealment over a clear firing view. assert(R::Score(Role::OBSERVE,100,0,0,true,true,true,false)>R::Score(Role::OBSERVE,100,0,0,true,true,false,false)); assert(R::Score(Role::OBSERVE,100,0,0,true,true,false,false)>R::Score(Role::OBSERVE,100,0,0,true,false,true,false)); assert(R::Score(Role::WITHDRAW,100,0,0,true,false,true,true)>R::Score(Role::WITHDRAW,100,0,0,true,true,true,true)); assert(R::Score(Role::FLANK,20,0,0,true,false,true,true)>R::Score(Role::FLANK,20,0,0,true,true,false,false)); assert(R::Score(Role::RESERVE,100,0,0,false,true,true,true)==R::Score(Role::RESERVE,100,0,0,false,false,false,false)); for(Role role:{Role::OBSERVE,Role::FIX,Role::FLANK,Role::BLOCK,Role::SEARCH,Role::RESERVE,Role::WITHDRAW}){ for(int i=0;i<9;i++){vector p=R::Candidate(anchor,threat,role,i);assert(vector::DistanceXZ(anchor,p)<=R::Radius(role));} } assert(R::Candidate(anchor,threat,Role::SEARCH,8).x==anchor.x); // no survey of neighbouring search patches assert(!R::Admissible(Role::SEARCH,anchor,from,{102.01,.1,100},0,1000)); assert(!R::Admissible(Role::OBSERVE,anchor,from,{100,5,100},0,1000)); assert(!R::Admissible(Role::OBSERVE,anchor,from,{nan,0,100},0,1000)); assert(!R::Admissible(Role::FLANK,{120,.1,100},anchor,{120.1,.1,100},30000,1000)); assert(!R::Admissible(Role::FLANK,{120,.1,100},anchor,{120,.1,100},9000,1000)); assert(R::Admissible(Role::FLANK,{120,.1,100},anchor,{120,.1,100},10000,1000)); assert(!R::Admissible(Role::FLANK,{120,.1,100},anchor,{120,.1,100},nan,1000)); ERR_HQTacticalGround survey;AIPathfindingComponent path;SCR_AIGroup group;group.path=&path; ERR_AttackSpace space;ERR_HQTask task; world.scene=1; assert(survey.Select(&group,&task,from,threat,&space,1000,selected)); assert(selected.x<84&&std::abs(selected.z-100)<1); // takes the low wall, not the blind wall or exposed anchor assert(world.rays<=27&&world.boxes==9); task.OperationRole=Role::RESERVE; assert(survey.Select(&group,&task,from,threat,&space,1000,selected)); assert(selected.z<84&&std::abs(selected.x-100)<1); // reserve uses the blind side for protection task.OperationRole=Role::WITHDRAW; assert(survey.Select(&group,&task,from,threat,&space,1000,selected)); int geometry=world.rays+world.boxes; assert(!survey.Select(&group,&task,from,threat,&space,1000,selected)); assert(world.rays+world.boxes==geometry&&geometry<=108); // shared hard work budget assert(!survey.Select(&group,&task,from,threat,&space,1999,selected)); assert(survey.Select(&group,&task,from,threat,&space,2000,selected)); // Flat open ground retains the original destination. It is still a candidate // only; no contact/arrival/route claim is returned or manufactured. world.scene=0;task.OperationRole=Role::OBSERVE; assert(survey.Select(&group,&task,from,threat,&space,3000,selected)); assert(vector::DistanceXZ(anchor,selected)<.01); // Tile loading stays asynchronous and bounded; absence never accepts origin. path.nav.loaded=false;int before=world.rays+world.boxes; assert(!survey.Select(&group,&task,from,threat,&space,4000,selected)); assert(path.nav.requests==2&&world.rays+world.boxes==before); path.nav.loaded=true;path.allow=false; assert(!survey.Select(&group,&task,from,threat,&space,5000,selected));path.allow=true; space.allow=false;assert(!survey.Select(&group,&task,from,threat,&space,6000,selected));space.allow=true; task.OperationRole=Role::SEARCH;path.delta={1.5,0,0};before=path.projections; assert(survey.Select(&group,&task,from,threat,&space,7000,selected)); assert(path.projections==before+1&&selected.x==101.5); // only the already-selected local footprint path.delta={2.1,0,0};assert(!survey.Select(&group,&task,from,threat,&space,8000,selected)); path.delta={0,2.1,0};assert(!survey.Select(&group,&task,from,threat,&space,9000,selected)); path.delta={1.5,0,0};world.water=true; assert(!survey.Select(&group,&task,from,threat,&space,10000,selected)); // water rechecked after projection path.delta={0,0,0};world.water=false; world.cliff=true;assert(!survey.Standing(anchor));world.cliff=false; task.OperationRole=Role::OBSERVE;world.scene=3; assert(!survey.Select(&group,&task,from,threat,&space,11000,selected)); // corrupt trace cannot invent cover world.scene=0; task.OperationRole=Role::FLANK;task.Destination={120,.1,100};task.SupportUntil=14000; assert(!survey.Select(&group,&task,anchor,threat,&space,12000,selected)); task.SupportUntil=21000; assert(survey.Select(&group,&task,anchor,threat,&space,13000,selected)); assert(vector::DistanceXZ(anchor,selected)<18); // picks an inward point fitting the remaining lease assert(task.SupportUntil==21000&&task.Destination.x==120); // no lease extension or task mutation inside survey // Characters, cars, weapons parented to them and moving props cannot create // a terrain advantage in a survey. Only static map geometry is admitted. survey.m_FilterChecks=0;survey.m_FilterExhausted=false; IEntity wall,character,car,weapon,prop;Physics moving;moving.dynamic=true; character.character=true;car.vehicle=true;weapon.parent=&character;prop.physics=&moving; assert(survey.StaticObstacle(&wall));assert(!survey.StaticObstacle(&character)); assert(!survey.StaticObstacle(&car)&&!survey.StaticObstacle(&weapon)&&!survey.StaticObstacle(&prop)); wall.parent=&wall;assert(!survey.StaticObstacle(&wall));wall.parent=nullptr; survey.m_FilterChecks=512;assert(survey.StaticObstacle(&wall)&&survey.m_FilterExhausted); // The adapter uses radio-delivered positions, including a newer execution // report. An older roster position would incorrectly reject this short bound. Adapter hq;ERR_HQUnit unit;unit.Group=&group;ERR_HQWatchEntry own;ERR_HQBelief belief; hq.m_Watch.entry=&own;hq.m_Memory.belief=&belief;ERR_HQTask previous;unit.Task=&previous; ERR_HQOperationSlot slot;ERR_HQExecutionReport report;slot.Report=&report;hq.m_Operations.slot=&slot; task.SupportUntil=26000;assert(hq.CoordinatedGround(&unit,&task,15000)); assert(vector::DistanceXZ(report.Position,task.Destination)<=20); vector saved=task.Destination;unit.HomeGuard=true;assert(!hq.CoordinatedGround(&unit,&task,16000));unit.HomeGuard=false; unit.ReservedForSupport=true;assert(!hq.CoordinatedGround(&unit,&task,16000));unit.ReservedForSupport=false; unit.LogisticsReservation=1;assert(!hq.CoordinatedGround(&unit,&task,16000));unit.LogisticsReservation=0; belief.BeliefRevision=3;assert(!hq.CoordinatedGround(&unit,&task,16000));belief.BeliefRevision=2; own.Closed=true;assert(!hq.CoordinatedGround(&unit,&task,16000));own.Closed=false; own.Fit=0;assert(!hq.CoordinatedGround(&unit,&task,16000));own.Fit=4; own.ObservedAt=0;assert(!hq.CoordinatedGround(&unit,&task,120001)); assert(vector::DistanceXZ(saved,task.Destination)==0); // rejected surveys never replace an existing destination } ''') source = P.read_text() for forbidden in ('GetOrigin(', 'GetPlayerManager(', 'GetControlledEntity(', 'Gather(', 'CreateEntity(', 'Spawn(', 'SetOrigin(', 'AddWaypoint(', '.Target'): assert forbidden not in source assert 'CoordinatedGround(' not in body(A, 'protected void ShadowCoordinated(') print('PASS: actual terrain survey chooses usable cover/concealment, preserves search and bound envelopes, honours finite support, delivered evidence, ownership, async tiles and shared geometry budget')