"""Execute actual finite road mine-site geometry and bounded native selector.""" from pathlib import Path import os,re from policy_harness import ROOT,body,run p=Path(os.environ.get('ERR_ENGINEER_MINE_SITE_SOURCE',ROOT/'addons/core/Scripts/Game/ERR/10_AI/ERR_EngineerMineSite.c')) source=p.read_text() for forbidden in ('GetPlayer','GetControlledEntity','GetOrigin','Spawn(', 'AddWaypoint','SetOrigin','CallLater'): assert forbidden not in source,forbidden s=re.sub(r'//[^\n]*','',source).replace('class ERR_EngineerMineSite','struct ERR_EngineerMineSite') s=s.replace('inout int','int&').replace('out vector','vector&').replace('array','Array').replace('array','Array').replace('foreach (','for (') s=s.replace('Array starts,','Array& starts,').replace('Array ends,','Array& ends,') s=s.replace('Array candidates)', 'Array& candidates)').replace('FromPolyline(Array points,','FromPolyline(Array& points,') s=s.replace('SCR_AIWorld.Cast(GetGame().GetAIWorld())','GetGame()->GetAIWorld()') for name in ('SCR_AIWorld','BaseRoad','ERR_SettlementSafety'): s=re.sub(r'\b'+name+r' (\w+)',name+r'* \1',s) for name in ('world','road','settlements'):s=s.replace(name+'.',name+'->') s=s.replace('GetGame().','GetGame()->').replace('GetRoadNetworkManager().','GetRoadNetworkManager()->') for name in ('ERR_ForceRules','ERR_HQRoadIntercept','vector','Math','ERR_Actors','Replication'):s=s.replace(name+'.',name+'::') s=s.replace('null','nullptr');s=re.sub(r'\bVector\(', 'vector(', s) s=re.sub(r'\b(bool|int|float) (\w+);',r'\1 \2{};',s).replace('\n}\n','\n};\n') settlement=ROOT/'addons/core/Scripts/Game/ERR/10_AI/ERR_SettlementSafety.c' settle=settlement.read_text().replace('class ERR_SettlementSafety','struct ERR_SettlementSafety').replace('protected ','').replace('static const float','static constexpr float') settle=settle.replace('MapDescriptorComponent.Cast(entity.FindComponent(MapDescriptorComponent))','entity->descriptor').replace('entity.FindComponent(MapDescriptorComponent)','entity->descriptor') settle=settle.replace('IEntity entity','Entity* entity').replace('MapDescriptorComponent descriptor','MapDescriptorComponent* descriptor').replace('descriptor.','descriptor->').replace('entity.','entity->') settle=settle.replace('GetGame().','GetGame()->').replace('GetWorld().','GetWorld()->').replace('Vector(','vector(').replace('vector.','vector::').replace('string.Format','string::Format').replace('EMapDescriptorType.','EMapDescriptorType::').replace('EQueryEntitiesFlags.','EQueryEntitiesFlags::') settle=settle.replace('CheckSettlement, FilterSettlement','[this](Entity* e){return CheckSettlement(e);}, [this](Entity* e){return FilterSettlement(e);}') settle=re.sub(r'\b(bool|int|float) (\w+);',r'\1 \2{};',settle).replace('\n}\n','\n};\n') road=ROOT/'addons/core/Scripts/Game/ERR/10_AI/ERR_HQRoadIntercept.c' better=body(road,'static bool Better(') stand=body(road,'static bool Standable(').replace('array','Array').replace('foreach (','for (').replace('TraceBox body','TraceBox* body') stand=stand.replace('GetGame().','GetGame()->').replace('GetWorld().','GetWorld()->').replace('body.','body->').replace('null','nullptr') for name in ('ERR_ForceRules','ChimeraWorldUtils','ERR_Actors','Math','TraceFlags'):stand=stand.replace(name+'.',name+'::') clearance_checks='' if 'static bool FarFromRoads(' in source: clearance_checks=r''' {Array starts={{0,10,0}},ends={{.009f,10,0}};int comparisons=0; assert(!Site::FarFromRoads({15.001f,10,0},starts,ends,comparisons)&&comparisons==1); comparisons=0;assert(Site::FarFromRoads({15.01f,10,0},starts,ends,comparisons)); comparisons=65536;assert(!Site::FarFromRoads({30,10,0},starts,ends,comparisons)&&comparisons==65536); comparisons=65535;ends.Insert({0,10,1});starts.Insert({0,10,1});assert(!Site::FarFromRoads({30,10,0},starts,ends,comparisons)&&comparisons==65536); starts={{0,10,0}};ends=starts;comparisons=0;assert(!Site::FarFromRoads({14.99f,10,0},starts,ends,comparisons)); comparisons=0;assert(Site::FarFromRoads({15,10,0},starts,ends,comparisons)); } ''' run(r''' #include #include #include #include #include struct string:std::string{using std::string::string;templatestatic string Format(const char*s,T...){return s;}}; #include struct Math{static float Clamp(float x,float a,float b){return std::clamp(x,a,b);}static float AbsFloat(float x){return std::abs(x);}static float Sqrt(float x){return std::sqrt(x);}}; struct vector{float x=0,y=0,z=0;vector()=default;vector(float a,float b,float c):x(a),y(b),z(c){}vector(const char*s){sscanf(s,"%f %f %f",&x,&y,&z);}float&operator[](int i){return i==0?x:i==1?y:z;}float operator[](int i)const{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};}bool operator==(vector b)const{return x==b.x&&y==b.y&&z==b.z;} static float Dot(vector a,vector b){return a.x*b.x+a.y*b.y+a.z*b.z;}static float DistanceXZ(vector a,vector b){return std::hypot(a.x-b.x,a.z-b.z);}static vector Lerp(vector a,vector b,float n){return a+(b-a)*n;}static const vector Zero;};const vector vector::Zero{}; templatestruct Array:std::vector{using std::vector::vector;using std::vector::operator=;int Count(){return this->size();}void Insert(T v){this->push_back(v);}void Clear(){this->clear();}void Remove(int i){this->erase(this->begin()+i);}bool IsEmpty(){return this->empty();}bool Contains(T v){return std::find(this->begin(),this->end(),v)!=this->end();}explicit operator bool(){return true;}}; struct ERR_ForceRules{static bool Finite(float n){return std::isfinite(n);}static bool FiniteVector(vector p){return Finite(p.x)&&Finite(p.y)&&Finite(p.z);}}; struct TraceFlags{static constexpr int WORLD=1,ENTS=2;};struct TraceBox{vector Start,End,Mins,Maxs;int Flags=0;}; struct EMapDescriptorType{static constexpr int MDT_NAME_CITY=1,MDT_NAME_TOWN=2,MDT_NAME_VILLAGE=3,MDT_NAME_SETTLEMENT=4,MDT_BUILDING=5;}; struct EQueryEntitiesFlags{static constexpr int ALL=1;}; struct MapDescriptorComponent{int type=EMapDescriptorType::MDT_NAME_VILLAGE;int GetBaseType(){return type;}}; struct Entity{vector position;MapDescriptorComponent*descriptor=nullptr;vector GetOrigin(){return position;}}; struct NativeWorld{Array settlements;int queries=0;float now=1000;float GetWorldTime(){return now;}templatevoid QueryEntitiesByAABB(vector low,vector high,A check,B filter,int){queries++;assert(high.x-low.x==400&&high.y-low.y==10000&&high.z-low.z==400);for(auto*e:settlements)if(e&&filter(e)&&!check(e))break;}int traces=0;bool obstructed=false,blockNear=false,onlyTop=false;float TraceMove(TraceBox* t,void*){traces++;bool blocked=obstructed||(blockNear&&std::hypot(t->Start.x,t->Start.z)<50)||(onlyTop&&(std::abs(t->Start.x)>1||t->Start.z<50));delete t;return blocked?.5f:1.f;}}; struct BaseRoad{float width=4;int pointReads=0;Arraypoints;float GetWidth(){return width;}void GetPoints(Array&p){pointReads++;p=points;}}; struct RoadManager{Arrayroads;int queries=0;void GetRoadsInAABB(vector low,vector high,Array&out){queries++;assert((high.x-low.x==120||high.x-low.x==160)&&high.z-low.z==high.x-low.x&&high.y-low.y==2000);out.clear();for(auto*r:roads){if(!r||r->points.size()<2){out.Insert(r);continue;}float minX=INFINITY,maxX=-INFINITY,minZ=INFINITY,maxZ=-INFINITY;bool invalid=false;for(auto p:r->points){if(!std::isfinite(p.x)||!std::isfinite(p.z))invalid=true;minX=std::min(minX,p.x);maxX=std::max(maxX,p.x);minZ=std::min(minZ,p.z);maxZ=std::max(maxZ,p.z);}if(invalid||(maxX>=low.x&&minX<=high.x&&maxZ>=low.z&&minZ<=high.z))out.Insert(r);}}}; struct SCR_AIWorld{RoadManager manager;bool available=true;RoadManager*GetRoadNetworkManager(){return available?&manager:nullptr;}}; struct Game{NativeWorld world;SCR_AIWorld ai;NativeWorld*GetWorld(){return &world;}SCR_AIWorld*GetAIWorld(){return &ai;}}game;Game*GetGame(){return &game;} struct Replication{static inline bool server=true;static bool IsServer(){return server;}}; struct ERR_Actors{static inline bool steep=false;static vector Ground(vector p){p.y=10;if(steep)p.y+=p.x;return p;}}; struct ChimeraWorldUtils{static inline bool water=false;static bool TryGetWaterSurfaceSimple(NativeWorld*,vector){return water;}}; struct ERR_HQRoadIntercept{'''+better+stand+r'''}; '''+settle+s+r''' float roadDistance(vector p,const Array&points){ float best=INFINITY; for(size_t i=1;i=15.f); assert(game.ai.manager.queries==1&&game.world.queries>0); std::reverse(road.points.begin(),road.points.end());assert(Site::Select(post,reversed));assert(vector::DistanceXZ(out,reversed)<.001f); // A crossing or nearby parallel narrow road is still a clearance hazard. BaseRoad cross,parallel;cross.width=2;cross.points={{0,10,-100},{0,10,100}}; game.ai.manager.roads={&road,&cross};assert(Site::Select(post,out));assert(roadDistance(out,road.points)>=15&&roadDistance(out,cross.points)>=15); game.ai.manager.roads={&cross,&road};assert(Site::Select(post,reversed)&&vector::DistanceXZ(out,reversed)<.001f); parallel.width=1;parallel.points={{-100,10,-16},{100,10,-16}}; game.ai.manager.roads={&road,¶llel};assert(Site::Select(post,out));assert(roadDistance(out,road.points)>=15&&roadDistance(out,parallel.points)>=15&&out.z>0); // Dense parallel roads leave no safe flank in the25–60m annulus. BaseRoad grid[9];game.ai.manager.roads={&road};for(int i=0;i<9;i++){grid[i].width=2;grid[i].points={{-100,10,float(-60+i*15)},{100,10,float(-60+i*15)}};game.ai.manager.roads.Insert(&grid[i]);} assert(!Site::Select(post,out)&&out==vector::Zero); // Clearance includes a narrow neighbor beyond the old60m query. Only the // upper outer flank is physically clear, and its neighboring road is10m away. BaseRoad edge,outer;edge.points={{-100,10,44.98f},{100,10,44.98f}};outer.width=2;outer.points={{-100,10,70},{100,10,70}}; game.ai.manager.roads={&edge};game.world.onlyTop=true;assert(Site::Select(post,out)&&out.z>59); game.ai.manager.roads={&edge,&outer};assert(!Site::Select(post,out)&&out==vector::Zero);game.world.onlyTop=false; // Actual shared settlement logic: named village within200m rejects a candidate; // an opposite clear flank remains selectable. Ordinary buildings are excluded. game.ai.manager.roads={&road};MapDescriptorComponent descriptor;Entity settlement;settlement.descriptor=&descriptor;settlement.position={0,10,-200};game.world.settlements={&settlement}; assert(Site::Select(post,out)&&out.z>0&&vector::DistanceXZ(out,settlement.position)>200); settlement.position=post;assert(!Site::Select(post,out)&&out==vector::Zero); descriptor.type=EMapDescriptorType::MDT_BUILDING;assert(Site::Select(post,out)); descriptor.type=EMapDescriptorType::MDT_NAME_CITY;assert(!Site::Select(post,out)); descriptor.type=EMapDescriptorType::MDT_NAME_TOWN;assert(!Site::Select(post,out)); descriptor.type=EMapDescriptorType::MDT_NAME_SETTLEMENT;assert(!Site::Select(post,out));game.world.settlements.Clear(); // Real bends retain clearance from every constituent segment, never chords. BaseRoad bend;bend.points={{-70,10,30},{50,10,30},{50,10,-30},{-70,10,-30}};game.ai.manager.roads={&bend}; assert(Site::Select(post,out)&&Site::InBand(post,out)&&roadDistance(out,bend.points)>=15); std::reverse(bend.points.begin(),bend.points.end());assert(Site::Select(post,reversed)&&vector::DistanceXZ(out,reversed)<.001f); // Existing exact annulus bounds and deterministic bounded retention survive. assert(Site::InBand(post,{25,10,0})&&Site::InBand(post,{60,10,0}));assert(!Site::InBand(post,{24.999f,10,0})&&!Site::InBand(post,{60.001f,10,0})); Arrayforward,reverse;for(int i=0;i<200;i++)Site::Keep(post,{30+float(i)/100,10,0},forward);for(int i=199;i>=0;i--)Site::Keep(post,{30+float(i)/100,10,0},reverse); assert(forward.Count()==128&&reverse.Count()==128);for(auto p:forward)assert(reverse.Contains(p)); // Elevated centerlines cannot be converted to terrain below a bridge. game.ai.manager.roads={&road};road.points={{-100,20,0},{100,20,0}};int before=game.world.traces; assert(!Site::Select(post,out)&&out==vector::Zero&&game.world.traces==before);road.points={{-100,10,0},{100,10,0}}; ChimeraWorldUtils::water=true;assert(!Site::Select(post,out)&&out==vector::Zero);ChimeraWorldUtils::water=false; ERR_Actors::steep=true;assert(!Site::Select(post,out)&&out==vector::Zero);ERR_Actors::steep=false; game.world.obstructed=true;before=game.world.traces;assert(!Site::Select(post,out)&&game.world.traces-before<=128);game.world.obstructed=false; game.world.blockNear=true;assert(Site::Select(post,out)&&vector::DistanceXZ(out,post)>=50);game.world.blockNear=false; // Hard bounds reject incomplete hazard inventories before physical checks. game.ai.manager.roads.resize(129,&road);before=game.world.traces;assert(!Site::Select(post,out)&&game.world.traces==before); BaseRoad dense;for(int i=0;i<1024;i++)dense.points.push_back({float(i),10,30});game.ai.manager.roads={&dense,&dense,&dense,&dense,&dense};before=game.world.traces; assert(!Site::Select(post,out)&&game.world.traces==before); BaseRoad bad;bad.width=1;bad.points={{0,10,0},{NAN,10,30}};game.ai.manager.roads={&road,&bad};assert(!Site::Select(post,out)&&out==vector::Zero); bad.points={{0,10,0}};assert(!Site::Select(post,out));bad.points.resize(1025,{0,10,0});assert(!Site::Select(post,out)); game.ai.manager.roads={&road,nullptr};assert(!Site::Select(post,out));game.ai.manager.roads={&road}; Replication::server=false;before=game.ai.manager.queries;int settlementsBefore=game.world.queries;assert(!Site::Select(post,out)&&game.ai.manager.queries==before&&game.world.queries==settlementsBefore);Replication::server=true; before=game.ai.manager.queries;assert(!Site::Select({NAN,10,0},out)&&out==vector::Zero&&game.ai.manager.queries==before); } ''') print('PASS: actual mine selector respects road and settlement flank safety; native boundaries doubled')