Merge owned systems into one addon while preserving resource identities. Gate player admission on the replicated prison scene, restore the original framed door, and hold enemy AI until escape. Correct scenario branding and author metadata, include publishing assets, and retain regression and native verification evidence.
193 lines
16 KiB
Python
193 lines
16 KiB
Python
"""Actual field evidence/observation bodies; physical engine boundaries remain untested."""
|
|
from policy_harness import ROOT, body, run
|
|
import re
|
|
P=ROOT/'addons/core/Scripts/Game/ERR/10_AI/ERR_NativeAircraftFieldProbe.c'
|
|
s=P.read_text()
|
|
def cpp(x):
|
|
x=x.replace('ERR_AircraftFlightState.','State::').replace('ERR_NativeAircraftFieldRules.','Rules::').replace('ERR_AircraftFieldRules.','FieldRules::').replace('vector.','vector::').replace('ERR_AircraftFieldFlight flight','Flight* flight').replace('flight.','flight->')
|
|
return re.sub(r'(?<![\w.])(\d+\.\d+)(?![\w.])',r'\1f',x)
|
|
rules=s[s.index('class ERR_NativeAircraftFieldRules'):s.index('class ERR_NativeAircraftFieldProbe')].replace('class ERR_NativeAircraftFieldRules','struct Rules').rstrip()+';'
|
|
observed='\n'.join(cpp(body(P,k)) for k in ('void ObserveBrakingContact(', 'void BrakeBegan(', 'void BrakeStopped('))
|
|
run(r'''#include <cassert>
|
|
#include <cmath>
|
|
#include <string>
|
|
using string=std::string;
|
|
struct vector {float x=0,y=0,z=0;static float DistanceXZ(vector a,vector b){return std::hypot(a.x-b.x,a.z-b.z);}};
|
|
namespace State {enum {COMPLETE=8,CANCELLED,FAILED,RELINQUISHED};}
|
|
'''+cpp(rules)+r'''
|
|
struct FieldRules {static float HorizontalSpeed(vector v){return std::hypot(v.x,v.z);}static float BrakingReserve(float s){return s*s/.30f+s+3;}};
|
|
struct Flight {float ERR_NativeFieldStageDeadline(){return 70000;}vector LandingPoint(){return {100,0,0};}};
|
|
template<typename...T>void PrintFormat(T...args){}
|
|
struct Probe {
|
|
bool m_Stopped=false,m_BrakeObserved=false,m_BrakeStopped=false,m_BrakePassed=false,m_BrakeContactObserved=false;
|
|
string m_ObservationFailure;
|
|
Flight* m_Flight=nullptr;float m_BrakeAt=0,m_BrakeReserve=0,m_BrakeStageDeadline=0,m_ControlDeadline=240000,m_BrakeSampledTravel=0,m_BrakeLowSince=-1;
|
|
vector m_BrakeOrigin,m_BrakePrevious,m_BrakeLandingPoint;
|
|
'''+observed+r'''
|
|
};
|
|
int main(){
|
|
assert(Rules::Cruise(1,1,false,1)&&!Rules::Cruise(.99f,1,false,1)&&!Rules::Cruise(1,2.501f,false,1));
|
|
assert(!Rules::Cruise(1,1,true,1)&&!Rules::Cruise(1,1,false,2));
|
|
assert(Rules::Terminal(false,State::COMPLETE,0,true,true,true,true,100,.5f));
|
|
assert(!Rules::Terminal(false,State::COMPLETE,0,true,false,true,true,100,.5f));
|
|
assert(!Rules::Terminal(false,State::COMPLETE,0,true,true,false,true,100,.5f));
|
|
assert(!Rules::Terminal(false,State::COMPLETE,0,true,true,true,false,100,.5f));
|
|
assert(!Rules::Terminal(false,State::COMPLETE,0,true,true,true,true,98,.5f));
|
|
assert(!Rules::Terminal(false,State::COMPLETE,0,true,true,true,true,100,.76f));
|
|
assert(Rules::Terminal(true,State::CANCELLED,1,false,false,false,true,30,.5f));
|
|
assert(!Rules::Terminal(true,State::CANCELLED,1,true,false,false,true,30,.5f));
|
|
assert(!Rules::Terminal(true,State::COMPLETE,1,false,false,false,true,30,.5f));
|
|
assert(!Rules::Terminal(true,State::CANCELLED,0,false,false,false,true,30,.5f));
|
|
assert(!Rules::Terminal(true,State::CANCELLED,2,false,false,false,true,30,.5f));
|
|
assert(Rules::PhysicalFinish(true,true,true,1,1,1,1,101,101));
|
|
assert(!Rules::PhysicalFinish(true,false,true,1,1,1,1,101,101));
|
|
assert(!Rules::PhysicalFinish(true,true,false,1,1,1,1,101,101));
|
|
assert(!Rules::PhysicalFinish(true,true,true,0,1,1,1,101,101));
|
|
assert(!Rules::PhysicalFinish(true,true,true,1,2,1,1,101,101));
|
|
for(int i=0;i<5;i++)assert(!Rules::CanDispose(i!=0,i!=1,i!=2,i!=3,i!=4));
|
|
Flight flight,foreign;Probe p;p.m_Flight=&flight;
|
|
p.BrakeBegan(&foreign,1000,{0,0,0},{2,0,0},false);assert(!p.m_BrakeObserved);
|
|
p.BrakeBegan(&flight,1000,{0,0,0},{2,0,0},false);assert(p.m_BrakeObserved&&p.m_BrakeReserve>18&&p.m_BrakeReserve<19);
|
|
p.m_BrakeSampledTravel=15;p.m_BrakePrevious={15,0,0};p.m_BrakeLowSince=2000;
|
|
p.BrakeStopped(&flight,4000,{16,0,0},{.1f,0,0},false);assert(p.m_BrakePassed&&p.m_BrakeStopped&&p.m_ObservationFailure.empty());
|
|
p.BrakeBegan(&flight,5000,{50,0,0},{2,0,0},false);assert(!p.m_ObservationFailure.empty()&&p.m_BrakeAt==1000); // no renewal
|
|
for(int fault=0;fault<4;fault++){
|
|
Probe bad;bad.m_Flight=&flight;bad.BrakeBegan(&flight,1000,{0,0,0},{2,0,0},false);bad.m_BrakeLowSince=2000;
|
|
float stopped=4000;vector at={16,0,0},vel={.1f,0,0};
|
|
if(fault==0){at={19,0,0};} if(fault==1){stopped=3999;} if(fault==2){vel={.25f,0,0};} if(fault==3){bad.m_BrakeSampledTravel=20;}
|
|
bad.BrakeStopped(&flight,stopped,at,vel,false);assert(!bad.m_BrakePassed&&!bad.m_ObservationFailure.empty()&&!bad.m_Stopped); // failure deferred outside callback
|
|
}
|
|
// Ground friction at entry, an intermediate callback, or the stop sample
|
|
// permanently invalidates an otherwise plausible measured reserve/low-speed pass.
|
|
for(int contactAt=0;contactAt<3;contactAt++){
|
|
Probe grounded;grounded.m_Flight=&flight;
|
|
grounded.BrakeBegan(&flight,1000,{0,0,0},{2,0,0},contactAt==0);
|
|
grounded.m_BrakeLowSince=2000;
|
|
grounded.ObserveBrakingContact(contactAt==1);
|
|
grounded.ObserveBrakingContact(false); // later loss of contact cannot clear evidence
|
|
grounded.BrakeStopped(&flight,4000,{16,0,0},{.1f,0,0},contactAt==2);
|
|
assert(grounded.m_BrakeContactObserved&&!grounded.m_BrakePassed&&!grounded.m_ObservationFailure.empty()&&!grounded.m_Stopped);
|
|
}
|
|
Probe before;before.ObserveBrakingContact(true);assert(!before.m_BrakeContactObserved);
|
|
Probe after;after.m_BrakeObserved=true;after.m_BrakeStopped=true;after.ObserveBrakingContact(true);assert(!after.m_BrakeContactObserved); // actual landing is separate
|
|
assert(!Rules::Braking(NAN,1,1,0,3000,0,false)&&!Rules::Braking(10,NAN,1,0,3000,0,false));
|
|
}
|
|
''')
|
|
assert s.startswith('#ifdef WORKBENCH') and s.rstrip().endswith('#endif')
|
|
assert 'outcome == "aircraft-field"' in body(P,'static bool Enabled(')
|
|
find=body(P,'protected bool FindPad(')
|
|
assert '"4890 0 11730"' in find and '"0 0 100"' in find
|
|
assert find.count('.Survey(')==1 and 'for (' not in find and 'AirportOffset' not in s
|
|
assert s.count('ERR_Actors.Spawn(AIRCRAFT,')==1 and s.count('SpawnCharacterInCompartment(')==1
|
|
assert s.count('physics.SetActive(ActiveState.ACTIVE)')==1
|
|
for prohibited in ('SetWorldTransform(', 'SetOrigin(', 'SetVelocity(', '.StartEngine(', '.StopEngine(', 'm_Mode.Own(', 'm_Flight.Tick(', 'm_Flight.Cancel(', 'm_Flight.StartField(', 'FieldDemand('):assert prohibited not in s
|
|
for sig in ('void PrepareActions(', 'void PrepareHelicopter('):
|
|
assert '++' in body(P,sig) and '.Prepare' not in body(P,sig)
|
|
for sig in ('void ObserveBrakingContact(', 'void BrakeBegan(', 'void BrakeStopped('):assert 'Check(' not in body(P,sig) and 'Stop(' not in body(P,sig)
|
|
assert 'ObserveBrakingContact' in body(P,'void PrepareHelicopter(') and 'ObserveBrakingContact(contact)' in body(P,'int Tick(')
|
|
assert 'super.BeginFieldBrake(now)' in body(P,'protected override bool BeginFieldBrake(')
|
|
assert 'super.CheckTranslation(now, position, height, speed, upright)' in body(P,'protected override void CheckTranslation(')
|
|
start=body(P,'protected bool StartRetainedField(');assert '.StartField(m_Aircraft, m_Envelope, ORDER_TOKEN, m_ControlDeadline)' in start
|
|
assert 'ERR_AircraftFieldFlight.Cast(entry.Flight)' in body(P,' ERR_AircraftFieldFlight ERR_NativeOriginalFieldFlight(')
|
|
tick=body(P,'int Tick(')
|
|
assert tick.index('FindPad(m_Pad)')<tick.index('ERR_Actors.Spawn(AIRCRAFT,')
|
|
assert tick.index('QualifyField(')<tick.index('StartRetainedField()')
|
|
assert tick.index('m_Service.Tick();')<tick.index('m_ObservationFailure.IsEmpty()')<tick.index('if (!m_Flight.Finished())')
|
|
assert 'now - m_CruiseSince >= 10000' in tick and 'now - m_CruiseSince >= 1000' in tick
|
|
assert 'now - m_TranslationStable >= 5000' in tick and 'now - m_LandingStable >= 2000' in tick
|
|
stop=body(P,'void Stop(')
|
|
assert stop.index('s_Current = null')<stop.index('m_Service.Stop()')<stop.index('ERR_Actors.DeleteSpawned(')<stop.index('m_Service.Tick()')<stop.index('m_Flight = null')
|
|
assert 'CanDispose(' in stop
|
|
# Execute root-owned Chat dispatch branch: failure cannot become completion/reset.
|
|
chat=ROOT/'addons/core/Scripts/Game/ERR/40_Chat/ERR_NativeSmoke.c';cs=chat.read_text()
|
|
a=cs.index('if (m_ERRSmokeStep == 240)');opening=cs.index('{',a);i=opening+1;depth=1
|
|
while depth:depth+=(cs[i]=='{')-(cs[i]=='}');i+=1
|
|
branch=cs[opening+1:i-1].replace('m_ERRAircraftField.Tick','m_ERRAircraftField.Tick').replace('ERR_Phase.DEFEAT','2')
|
|
run(r'''#include <cassert>
|
|
#include <initializer_list>
|
|
struct Fixture {int result=0;int Tick(float){return result;}};
|
|
struct Chat {Fixture m_ERRAircraftField;int m_ERRSmokeStep=240,failures=0,transitions=0;void ERR_Check(bool,const char*){failures++;}void Transition(int){transitions++;}void Tick(float now){
|
|
'''+branch+r'''} };
|
|
int main(){for(int result:{-1,0,1}){Chat c;c.m_ERRAircraftField.result=result;c.Tick(1000);assert(c.failures==(result<0));assert(c.transitions==(result==1));assert(c.m_ERRSmokeStep==(result==1?241:240));}}
|
|
''')
|
|
assert 'm_ERRTestAircraftField = outcome == "aircraft-field"' in cs
|
|
assert 'm_ERRTestAircraftControl || m_ERRTestAircraftRoute || m_ERRTestAircraftField' in cs and '+ 330000' in cs
|
|
assert 'm_ERRAircraftField.Stop()' in body(chat,'protected void ERR_StopHQPatrol(')
|
|
assert 'errSmokeFieldServiceCancel' in cs and 'current == ERR_Phase.DEFEAT && m_ERRSmokeStep == 241' in cs
|
|
print('PASS: actual field result/braking observer and Chat dispatch rules; one finite fixed candidate, deferred callback failure and guarded cleanup; no native measurement')
|
|
|
|
# Execute the real optional grid/FindPad flow, faking only CLI/world/terrain/logging.
|
|
def audit_cpp(text):
|
|
text=text.replace('protected ','').replace('out vector result','vector& result')
|
|
for before,after in (('System.','System::'),('Replication.','Replication::'),('SCR_TerrainHelper.','Terrain::'),('ERR_AircraftFieldEnvelope.','Envelope::'),('ERR_Actors.','Actors::'),('Math.','Math::'),('GetGame().GetWorld()','GetGame()->GetWorld()')):text=text.replace(before,after)
|
|
for before,after in (('"0 0 0"','vector{}'),('"0 0 100"','vector{0,0,100}'),('"4890 0 11730"','vector{4890,0,11730}')):text=text.replace(before,after)
|
|
return text
|
|
run(r'''#include <cassert>
|
|
#include <cmath>
|
|
#include <string>
|
|
#include <vector>
|
|
#include <map>
|
|
#include <sstream>
|
|
using string=std::string;
|
|
struct vector {float v[3]={0,0,0};vector()=default;vector(float x,float y,float z):v{x,y,z}{}float& operator[](int i){return v[i];}float operator[](int i)const{return v[i];}vector operator+(vector b)const{return {v[0]+b[0],v[1]+b[1],v[2]+b[2]};}};
|
|
std::ostream& operator<<(std::ostream& out,vector v){return out<<v[0]<<','<<v[1]<<','<<v[2];}
|
|
std::vector<string> logs;
|
|
void Print(const char* value){logs.push_back(value);}
|
|
template<class...A>void PrintFormat(const char* format,A...args){std::ostringstream out;((out<<args<<' '),...);logs.push_back(string(format)+"|"+out.str());}
|
|
struct System {static std::map<string,string> args;static bool GetCLIParam(string name,string& value){auto i=args.find(name);if(i==args.end())return false;value=i->second;return true;}};std::map<string,string> System::args;
|
|
struct Replication {static bool server;static bool IsServer(){return server;}};bool Replication::server=true;
|
|
struct Game {bool world=true;bool GetWorld(){return world;}} game;bool gamePresent=true;Game* GetGame(){return gamePresent?&game:nullptr;}
|
|
struct Math {static float AbsFloat(float value){return std::abs(value);}};
|
|
struct Terrain {static std::vector<vector> points;static int invalidAt;static float invalidValue;static float GetTerrainY(vector point){points.push_back(point);if(int(points.size())==invalidAt)return invalidValue;return point[0]*.001f+point[2]*.002f;}};std::vector<vector> Terrain::points;int Terrain::invalidAt=0;float Terrain::invalidValue=NAN;
|
|
struct Actors {static int groundCalls;static vector Ground(vector p){groundCalls++;p[1]=28.5f;return p;}};int Actors::groundCalls=0;
|
|
struct Envelope {static bool permitted;static int calls;static bool Survey(vector from,vector to){calls++;assert(std::abs(from[0]-4890)<.01f&&std::abs(from[2]-11730)<.01f&&to[2]-from[2]==100);return permitted;}};bool Envelope::permitted=false;int Envelope::calls=0;
|
|
struct Probe {bool m_TerrainAudited=false,m_Stopped=false,m_AllocationRequested=false,m_Aircraft=false,m_Group=false,m_Pilot=false;vector m_Destination;
|
|
'''+ '\n'.join(audit_cpp(body(P,key)) for key in ('static bool Enabled(', 'static bool TerrainAuditEnabled(', 'protected void AuditTerrain(', 'protected bool FindPad('))+r'''
|
|
};
|
|
void reset(){System::args={{"errSmoke","1"},{"errSmokeOutcome","aircraft-field"},{"errSmokeFieldTerrainAudit","1"}};logs.clear();Terrain::points.clear();Terrain::invalidAt=0;Terrain::invalidValue=NAN;Actors::groundCalls=0;Envelope::calls=0;Envelope::permitted=false;Replication::server=true;gamePresent=true;game.world=true;}
|
|
int main(){
|
|
reset();Probe p;vector unchanged={99,88,77};assert(!p.FindPad(unchanged));assert(unchanged[0]==99&&unchanged[1]==88&&unchanged[2]==77&&p.m_Destination[0]==0);
|
|
assert(Envelope::calls==1&&Actors::groundCalls==2&&Terrain::points.size()==1681&&logs.size()==1683&&p.m_TerrainAudited&&!p.m_AllocationRequested&&!p.m_Aircraft&&!p.m_Group&&!p.m_Pilot);
|
|
assert(logs.front().find("minX=4750 maxX=5150 minZ=11600 maxZ=12000 spacing=10 columns=41 rows=41 nodes=1681")!=string::npos);
|
|
assert(logs.back().find("original survey refusal unchanged; no candidate qualified")!=string::npos);
|
|
for(int i=0;i<1681;i++){
|
|
auto q=Terrain::points[i];assert(q[0]==4750+(i/41)*10&&q[1]==0&&q[2]==11600+(i%41)*10);
|
|
std::ostringstream expected;expected<<'|'<<i<<' '<<q[0]<<' '<<q[2]<<' '<<(q[0]*.001f+q[2]*.002f)<<' ';
|
|
assert(logs[i+1].find("ERR AIRCRAFT FIELD TERRAIN AUDIT POINT:")==0&&logs[i+1].find(expected.str())!=string::npos);
|
|
}
|
|
p.AuditTerrain();assert(Terrain::points.size()==1681&&logs.size()==1683); // no retry, even if directly reentered
|
|
// Neither CLI omission nor malformed/conflicting scope permits collection.
|
|
for(int fault=0;fault<13;fault++){
|
|
reset();Probe refused;
|
|
if(fault==0)System::args.erase("errSmokeFieldTerrainAudit");
|
|
if(fault==1)System::args["errSmokeFieldTerrainAudit"]="0";
|
|
if(fault==2)System::args["errSmoke"]="0";
|
|
if(fault==3)System::args["errSmokeOutcome"]="aircraft-route";
|
|
if(fault==4)Replication::server=false;
|
|
if(fault==5)System::args["errSmokeFieldServiceCancel"]="1";
|
|
if(fault==6)refused.m_Stopped=true;
|
|
if(fault==7)refused.m_AllocationRequested=true;
|
|
if(fault==8)refused.m_Aircraft=true;
|
|
if(fault==9)refused.m_Group=true;
|
|
if(fault==10)refused.m_Pilot=true;
|
|
if(fault==11)gamePresent=false;
|
|
if(fault==12)game.world=false;
|
|
assert(!refused.FindPad(unchanged));assert(Terrain::points.empty()&&logs.empty()&&!refused.m_TerrainAudited&&Envelope::calls==1);
|
|
}
|
|
// Successful original survey never runs the optional audit or changes its result.
|
|
reset();Envelope::permitted=true;Probe success;assert(success.FindPad(unchanged));assert(Terrain::points.empty()&&!success.m_TerrainAudited&&Envelope::calls==1&&success.m_Destination[2]-unchanged[2]==100);
|
|
// Malformed heights stop without retry, completion, candidate selection or allocation.
|
|
for(float invalid:{float(NAN),float(INFINITY),float(-INFINITY),1000001.0f}){
|
|
reset();Terrain::invalidAt=17;Terrain::invalidValue=invalid;Probe malformed;assert(!malformed.FindPad(unchanged));
|
|
assert(Terrain::points.size()==17&&logs.size()==18&&logs.back().find("AUDIT ABORT:")!=string::npos&&malformed.m_TerrainAudited&&!malformed.m_AllocationRequested);
|
|
malformed.AuditTerrain();assert(Terrain::points.size()==17);
|
|
}
|
|
}
|
|
''')
|
|
audit=body(P,'protected void AuditTerrain(')
|
|
for forbidden in ('Spawn(', 'SetOrigin(', 'SetActive(', 'TraceMove(', '.Survey(', '.Qualify', 'new ', 'GetEntities', 'm_Destination ='):
|
|
assert forbidden not in audit
|
|
assert audit.count('GetTerrainY(')==1
|
|
assert find.index('.Survey(')<find.index('AuditTerrain();')<find.index('return false;')<find.index('result = candidate')
|
|
print('PASS: actual opt-in terrain audit records one fixed1681-point grid, preserves original survey refusal/success and exact no-allocation scope; malformed heights stop without retry; no native data acquired')
|