Add configurable nearby garage vehicles and fix roadblocks and fuel pumps; record Workshop 0.0.131
continuous-integration/drone/push Build is passing

This commit is contained in:
2026-10-30 18:56:57 +01:00
parent 3ec882dc4e
commit 2dcbe3107d
75 changed files with 7478 additions and 59 deletions
+12 -5
View File
@@ -1,9 +1,12 @@
"""Execute the shipped checkpoint layout across road widths and rotations."""
from policy_harness import ROOT, body, run
import re
p=ROOT/'addons/core/Scripts/Game/ERR/10_AI/ERR_Roadblocks.c'
s='\n'.join(body(p,x) for x in ('protected void Layout(', 'protected void AddProp('))
s='\n'.join(body(p,x) for x in ('protected void Layout(', 'protected void AddProp(', 'protected vector GuardPosition('))
s=s.replace('protected ', '').replace('out ', '').replace('array<ref ERR_RoadblockProp> covers', 'Array<Prop*>& covers')
s=s.replace('ResourceName ', 'string ').replace('vector ', 'Vec ').replace('ERR_Actors.Ground','Ground').replace('new ERR_RoadblockProp','new Prop')
shoulder = re.search(r'm_Shoulder = ([^;]+);', body(p, 'protected bool Candidate('))[1]
shoulder = shoulder.replace('road.GetWidth()', 'width').replace('Math.Max', 'std::max')
run(r'''
#include <cassert>
#include <cmath>
@@ -27,24 +30,28 @@ int main(){
for(double width:{4.,6.,10.,16.})for(int degrees=0;degrees<360;degrees+=15){
Checkpoint l;double angle=degrees*3.141592653589793/180;
l.m_Forward={std::sin(angle),0,std::cos(angle)};l.m_Right={std::cos(angle),0,-std::sin(angle)};
l.m_Shoulder=std::max(width*.5+1.5,4.);Array<Prop*>props;l.Layout(props);assert(props.size()==18);
l.m_Shoulder='''+shoulder+r''';Array<Prop*>props;l.Layout(props);assert(props.size()==8);
std::map<string,int>counts;std::vector<double>barriers;
for(auto*p:props){counts[p->Prefab]++;
Vec delta=p->Position-l.m_Centre;double across=dot(delta,l.m_Right),along=dot(delta,l.m_Forward);
// Whole footprints (not just origins) preserve a four-metre straight passage.
double reach=std::abs(dot(p->Right,l.m_Right))*p->HalfWidth+std::abs(dot(p->Forward,l.m_Right))*p->HalfDepth;
assert(std::abs(across)-reach>=2.-1e-8);
// Bound the compact footprint, including both road shoulders.
assert(std::abs(across)+reach <= std::max(width*.5+1.2,4.5)+1e-6);
double depth=std::abs(dot(p->Right,l.m_Forward))*p->HalfWidth+std::abs(dot(p->Forward,l.m_Forward))*p->HalfDepth;
assert(std::abs(along)+depth <= 8.9+1e-6);
if(p->Prefab=="barrier")barriers.push_back(along);
if(p->Prefab=="sign")assert(dot(p->Forward,l.m_Forward)*along>0); // both approaches face outward
// Guard starting volumes cannot intersect any prop in the planned post.
for(int side:{-1,1})for(int row:{-1,1}){
Vec guard=l.m_Centre+l.m_Right*(side*(l.m_Shoulder+2.5))+l.m_Forward*(side*(row-1.5));
Vec guard=l.GuardPosition(side,row);
Vec rel=guard-p->Position;
assert(std::abs(dot(rel,p->Right))>p->HalfWidth+.6 || std::abs(dot(rel,p->Forward))>p->HalfDepth+.6);
}
}
assert(counts["cover"]==8&&counts["barrier"]==4&&counts["obstacle"]==2&&counts["sign"]==2&&counts["table"]==1&&counts["shelter"]==1);
assert(barriers.size()==4&&std::abs(barriers[0]-barriers[2])>15.9);
assert(counts["cover"]==4&&counts["barrier"]==2&&counts["sign"]==2&&counts.size()==3);
assert(barriers.size()==2&&std::abs(barriers[0]-barriers[1])>11.9);
// No physical prop footprint intersects another (separating axes).
for(size_t i=0;i<props.size();i++)for(size_t j=i+1;j<props.size();j++){
auto*a=props[i];auto*b=props[j];bool separate=false;