115 lines
7.8 KiB
Python
115 lines
7.8 KiB
Python
"""Run production garage filtering and vehicle-fit rules against unsafe inputs."""
|
|
from policy_harness import ROOT, body, run
|
|
p = ROOT/'addons/core/Scripts/Game/ERR/10_AI/ERR_GarageVehicles.c'
|
|
rules = '\n'.join(body(p, s) for s in ('static bool Garage(', 'static bool Envelope(', 'static bool Yard(', 'static bool Farm(', 'static bool FarmEnvelope(', 'static vector YardOffset('))
|
|
rules += '\n' + body(ROOT/'addons/core/Scripts/Game/ERR/10_AI/ERR_ParkedCarCatalog.c', 'static bool Candidate(')
|
|
rules += '\n' + body(ROOT/'addons/core/Scripts/Game/ERR/10_AI/ERR_ParkedCarCatalog.c', 'static bool MovingCandidate(')
|
|
rules = rules.replace('vector ', 'Vec ').replace('ERR_ForceRules.', 'ERR_ForceRules::')
|
|
run(r'''
|
|
#include <cassert>
|
|
#include <algorithm>
|
|
#include <cmath>
|
|
#include <cctype>
|
|
#include <limits>
|
|
#include <string>
|
|
struct string : std::string {
|
|
using std::string::string;
|
|
void ToLower(){std::transform(begin(),end(),begin(),[](unsigned char c){return std::tolower(c);});}
|
|
bool Contains(const std::string& needle){return find(needle)!=npos;}
|
|
bool EndsWith(const std::string& suffix){return size()>=suffix.size() && compare(size()-suffix.size(),suffix.size(),suffix)==0;}
|
|
};
|
|
struct Vec {float v[3];float& operator[](int i){return v[i];}float operator[](int i)const{return v[i];}Vec operator+(Vec b)const{return {{v[0]+b[0],v[1]+b[1],v[2]+b[2]}};}Vec operator*(float n)const{return {{v[0]*n,v[1]*n,v[2]*n}};}};
|
|
namespace ERR_ForceRules {bool FiniteVector(Vec v){return std::isfinite(v[0])&&std::isfinite(v[1])&&std::isfinite(v[2]);}}
|
|
''' + rules + r'''
|
|
int main(){
|
|
assert(Garage("{GUID}Prefabs/Structures/Houses/Garage/Garage_E_01/Garage_E_01.et"));
|
|
assert(Garage("Prefabs/Structures/Houses/Village/HouseAddon_Garage_E_01/HouseAddon_Garage_E_01.et"));
|
|
assert(!Garage("Prefabs/Structures/Houses/Garage/Garage_E_01/Dst/Garage_E_01_Ruin.et"));
|
|
assert(!Garage("Prefabs/Structures/Houses/Garage/Garage_E_01/Furniture/Garage_E_01_furniture_01.et"));
|
|
assert(!Garage("Prefabs/Structures/BuildingParts/Doors/Door_Garage_E_01_A_LEFT_EXT_COV_B.et"));
|
|
assert(!Garage("Prefabs/Structures/Military/Houses/GarageMilitary_E_01/GarageMilitary_E_01.et"));
|
|
assert(Yard("Prefabs/Structures/Houses/Village/House_Village_E_1I01/House_Village_E_1I01_beige_V2.et"));
|
|
assert(Yard("Prefabs/Structures/Houses/Village/House_Village_E_1I06/House_Village_E_1I06_white.et"));
|
|
assert(!Yard("Prefabs/Structures/Houses/Village/House_Village_E_1I06/House_Village_E_1I06_base.et"));
|
|
assert(!Yard("Prefabs/Structures/Houses/Village/House_Village_E_1I06/Dst/House_Village_E_1I06_ruin.et"));
|
|
assert(!Yard("Prefabs/Structures/Houses/Village/House_Village_E_1I06/Furniture/House_Village_E_1I06_furniture_01.et"));
|
|
assert(Farm("Prefabs/Structures/Agriculture/Barn/Barn_E_01/Barn_E_01_white.et"));
|
|
assert(Farm("Prefabs/Structures/Agriculture/CowShed/CowShed_E_01/CowShed_E_01_short.et"));
|
|
assert(!Farm("Prefabs/Structures/Agriculture/Barn/Barn_E_01/Dst/Barn_E_01_Ruin.et"));
|
|
assert(!Farm("Prefabs/Structures/Agriculture/Barn/Barn_E_01/Barn_E_01_Base.et"));
|
|
assert(!Farm("Prefabs/Structures/Agriculture/Barn/Barn_E_01/Furniture/Barn_E_01_furniture_01.et"));
|
|
assert(FarmEnvelope({{-1.4,-0.2,-2.9}},{{1.4,3,2.9}}));
|
|
assert(!FarmEnvelope({{-1.5,0,-2}},{{1,3,2}}));
|
|
assert(!FarmEnvelope({{-1,0,-2}},{{1,3.2,2}}));
|
|
assert(!FarmEnvelope({{-1,0,-3}},{{1,3,2}}));
|
|
assert(!FarmEnvelope({{-1,0,-2}},{{1,NAN,2}}));
|
|
Vec low={{-4,-1,-6}},high={{6,8,8}};
|
|
assert(YardOffset(low,high,0)[0]==-7 && YardOffset(low,high,0)[2]==1);
|
|
assert(YardOffset(low,high,1)[0]==9 && YardOffset(low,high,1)[1]==0);
|
|
assert(YardOffset(low,high,2)[2]==-9 && YardOffset(low,high,2)[0]==1);
|
|
assert(YardOffset(low,high,3)[2]==11);
|
|
assert(YardOffset(low,high,0,4)[0]==-8 && YardOffset(low,high,3,4)[2]==12);
|
|
assert(Candidate("{GUID}Prefabs/Vehicles/Wheeled/T601/T601_blue_twoTone.et",false));
|
|
assert(!MovingCandidate("{GUID}Prefabs/Vehicles/Wheeled/T601/T601_blue_twoTone.et"));
|
|
assert(MovingCandidate("{GUID}Prefabs/Vehicles/Wheeled/V2101/V2101_lightBlue.et"));
|
|
assert(!MovingCandidate("Prefabs/Vehicles/Wheeled/S105/S105_rally_08.et"));
|
|
assert(Candidate("Prefabs/Vehicles/Wheeled/V2101/V2101_lightBlue.et",false));
|
|
assert(Candidate("Prefabs/Vehicles/Wheeled/S105/S105_rally_08.et",true));
|
|
assert(!Candidate("Prefabs/Vehicles/Wheeled/S105/S105_rally_08.et",false));
|
|
assert(!Candidate("Prefabs/Vehicles/Wheeled/S105/S105_green.et",true));
|
|
assert(!Candidate("Prefabs/Vehicles/Wheeled/T601/T601_base.et",false));
|
|
assert(!Candidate("Prefabs/Vehicles/Wheeled/T601/T601_rally_01_fullkit.et",true));
|
|
assert(!Candidate("Prefabs/Vehicles/Wheeled/T601/VehParts/Wheels/T601_wheel_Rally_Blue.et",false));
|
|
assert(!Candidate("Prefabs/Vehicles/Wheeled/S105/S105_FIA.et",false));
|
|
assert(Envelope({{-1,-0.2,-2.3}},{{1,1.8,2.3}}));
|
|
assert(!Envelope({{-1.06f,0,-2}},{{1,1.8,2}}));
|
|
assert(!Envelope({{-1,0,-2.5}},{{1,1.8,2}}));
|
|
assert(!Envelope({{-1,0,-2}},{{1,2.1,2}}));
|
|
assert(!Envelope({{-1,-0.4,-2}},{{1,1.8,2}}));
|
|
assert(!Envelope({{1,0,2}},{{-1,1.8,-2}}));
|
|
assert(!Envelope({{NAN,0,-2}},{{1,1.8,2}}));
|
|
assert(!Envelope({{-1,0,-2}},{{1,INFINITY,2}}));
|
|
}
|
|
''')
|
|
print('PASS: garage/yard family admission, bounded wall offsets, civilian and optional Rally catalog exclusions, vehicle-fit limits')
|
|
|
|
# Execute the actual yard ground veto with road/terrain doubles. A flat centre
|
|
# alone must not admit a sloping or submerged edge of the parking footprint.
|
|
ground = body(p, 'protected bool YardGround(')
|
|
ground = ground.replace('protected ', '').replace('vector ', 'Vec ')
|
|
ground = ground.replace('SCR_AIWorld world = SCR_AIWorld.Cast(GetGame().GetAIWorld());', 'SCR_AIWorld* world = worldAvailable ? &nativeWorld : nullptr;')
|
|
ground = ground.replace('BaseRoad road; float distance;', 'BaseRoad* road = nullptr; float distance = 0;')
|
|
ground = ground.replace('world.', 'world->').replace('road.', 'road->').replace('GetRoadNetworkManager().', 'GetRoadNetworkManager()->')
|
|
ground = ground.replace('skipNavlinks: true', 'true')
|
|
for name in ['ERR_ForceRules', 'ERR_Actors', 'SCR_TerrainHelper', 'Math']:
|
|
ground = ground.replace(name + '.', name + '::')
|
|
run(r'''
|
|
#include <cassert>
|
|
#include <cmath>
|
|
struct Vec {float v[3];float operator[](int i)const{return v[i];}
|
|
Vec operator+(Vec b)const{return {{v[0]+b[0],v[1]+b[1],v[2]+b[2]}};}
|
|
Vec operator*(float n)const{return {{v[0]*n,v[1]*n,v[2]*n}};}};
|
|
bool worldAvailable=true,managerAvailable=true,hasRoad=true,wetEdge=false;
|
|
float roadDistance=20,edgeHeight=0,waterBoundary=2;
|
|
struct BaseRoad{float width=10;float GetWidth(){return width;}} roadInstance;
|
|
struct Roads{void GetClosestRoad(Vec,BaseRoad*& road,float& distance,bool){road=hasRoad?&roadInstance:nullptr;distance=roadDistance;}} roads;
|
|
struct SCR_AIWorld{Roads* GetRoadNetworkManager(){return managerAvailable?&roads:nullptr;}} nativeWorld;
|
|
namespace ERR_ForceRules{bool Finite(float n){return std::isfinite(n);}}
|
|
namespace SCR_TerrainHelper{float GetTerrainY(Vec p){return p[0]>.5f?edgeHeight:0;}}
|
|
namespace ERR_Actors{bool DryGround(Vec p){return !(wetEdge&&p[2]>waterBoundary)&&std::isfinite(SCR_TerrainHelper::GetTerrainY(p));}}
|
|
namespace Math{float AbsFloat(float n){return std::abs(n);}}
|
|
''' + ground + r'''
|
|
int main(){Vec p={{0,0,0}},matrix[4]={{{1,0,0}},{{0,1,0}},{{0,0,1}},{{0,0,0}}};
|
|
assert(YardGround(p,matrix));
|
|
roadDistance=8.99f;assert(!YardGround(p,matrix));roadDistance=9;assert(YardGround(p,matrix));
|
|
hasRoad=false;assert(YardGround(p,matrix));hasRoad=true;
|
|
worldAvailable=false;assert(!YardGround(p,matrix));worldAvailable=true;
|
|
managerAvailable=false;assert(!YardGround(p,matrix));managerAvailable=true;
|
|
wetEdge=true;assert(!YardGround(p,matrix));waterBoundary=2.75f;assert(YardGround(p,matrix)&&!YardGround(p,matrix,true));wetEdge=false;
|
|
edgeHeight=.19f;assert(!YardGround(p,matrix));edgeHeight=.17f;assert(YardGround(p,matrix));
|
|
edgeHeight=NAN;assert(!YardGround(p,matrix));edgeHeight=0;
|
|
roadDistance=NAN;assert(!YardGround(p,matrix));
|
|
}
|
|
''')
|
|
print('PASS: yard road-width margin, missing road data, footprint water/slope and nonfinite-input vetoes')
|