Validate independent packed addons and complete physical mortar salvos
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
"""Execute the actual full-salvo evidence gates; this is not a native firing result."""
|
||||
from policy_harness import ROOT, body, run
|
||||
p=ROOT/'addons/ai/Scripts/Game/ERR/ERR_NativeMortarSalvoProbe.c'
|
||||
base=ROOT/'addons/ai/Scripts/Game/ERR/ERR_NativeMortarFiringProbe.c'
|
||||
rules='\n'.join(body(base, sig) for sig in ['static bool AimFresh(', 'static bool CommitFresh(', 'static bool EventBound('])
|
||||
rules=rules.replace('ERR_MortarPrediction.', 'ERR_MortarPrediction::')
|
||||
complete=body(p,'static bool Complete(').replace('ERR_MortarSalvo.', 'ERR_MortarSalvo::')
|
||||
methods='\n'.join(body(p,sig) for sig in ['void NativeCommit(', 'void NativeClosing(', 'void NativeProjectile('])
|
||||
for a,b in [('ERR_MortarBattery battery','Battery* battery'),('IEntity gun, IEntity projectile','Entity* gun, Entity* projectile'),('string reason, string failure','std::string reason, std::string failure'),('m_Battery.','m_Battery->'),('battery.','battery->'),('Report.','Report->'),('projectile.GetOrigin()','projectile->GetOrigin()'),('GetGame().GetWorld().GetWorldTime()','clockNow'),('ERR_NativeMortarEvidenceRules.','ERR_NativeMortarEvidenceRules::'),('ERR_MortarSalvo.','ERR_MortarSalvo::')]: methods=methods.replace(a,b)
|
||||
run('''#include <cassert>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
float clockNow=20000;
|
||||
struct ERR_MortarPrediction {static constexpr float MAX_REPORT_AGE_MS=60000;};
|
||||
struct ERR_MortarSalvo {static constexpr int ROUNDS=8;};
|
||||
struct ERR_NativeMortarEvidenceRules {'''+rules+'''};
|
||||
struct Rules {'''+complete+'''};
|
||||
struct Entity {int GetOrigin(){return 0;}};
|
||||
struct Report {int MessageId=7;float ObservedAt=1000;};
|
||||
struct Battery {void* Activity=nullptr;void* Refresh=nullptr;bool RefreshRejected=false;bool CommandOpen=true,Released=true,stopped=false;int SourceId=7,OrderId=1,OrderShots=0;float AimedAt=19000,AimValidatedAt=19000,FlightTime=20;struct Report report;struct Report* Report=&report;bool Stopped(){return stopped;}};
|
||||
struct Items {std::vector<Entity*> values;bool Contains(Entity* p){return std::find(values.begin(),values.end(),p)!=values.end();}void Insert(Entity* p){values.push_back(p);}};
|
||||
template<class... Args>void PrintFormat(Args...args){}
|
||||
struct Probe {
|
||||
void* m_OriginalActivity=nullptr;bool m_RefreshCase=false;int m_UpdatedCommits=0,m_CommitSource=0;float m_CommitObservedAt=0;
|
||||
bool m_Stopped=false,m_BadProjectile=false,m_CommitPending=false,m_ClosureSeen=false,m_ClosureComplete=false;
|
||||
Battery* m_Battery;Entity* m_Gun;Items m_Projectiles;int m_Events=0,m_Step=1,m_Source=7,m_Order=1,m_Commits=0,m_CommitOrder=0,m_CommitShot=0;float m_ObservedAt=1000,m_CommittedAt=0;std::string m_BadReason;
|
||||
bool ReportKnown(Report* report){return report&&report->MessageId==m_Source&&report->ObservedAt==m_ObservedAt;}
|
||||
bool AllAccepted(){return !m_RefreshCase;}
|
||||
'''+methods+'''};
|
||||
int main(){
|
||||
assert(Rules::Complete(8,8,8,8,19,false));
|
||||
for(int count=0;count<8;count++)assert(!Rules::Complete(count,count,count,count,27-count,false));
|
||||
assert(!Rules::Complete(9,9,9,9,18,false));
|
||||
assert(!Rules::Complete(8,7,8,8,19,false));
|
||||
assert(!Rules::Complete(8,8,7,8,19,false));
|
||||
assert(!Rules::Complete(8,8,8,7,19,false));
|
||||
assert(!Rules::Complete(8,8,8,8,20,false));
|
||||
assert(!Rules::Complete(8,8,8,8,18,false));
|
||||
assert(!Rules::Complete(8,8,8,8,19,true));
|
||||
Entity gun,foreign,shots[9];Battery b;Probe p;p.m_Battery=&b;p.m_Gun=&gun;
|
||||
p.NativeProjectile(&foreign,&shots[0]);assert(p.m_Events==0);
|
||||
for(int i=0;i<8;i++){
|
||||
b.OrderShots=i;b.AimedAt=clockNow;b.AimValidatedAt=clockNow;
|
||||
p.NativeCommit(&b,clockNow);assert(p.m_CommitPending&&!p.m_BadProjectile&&p.m_Commits==i+1);
|
||||
clockNow+=500;p.NativeProjectile(&gun,&shots[i]);assert(p.m_Events==i+1&&!p.m_CommitPending&&!p.m_BadProjectile);
|
||||
}
|
||||
b.OrderShots=8;p.NativeClosing(&b,"native artillery activity COMPLETED (shot count is separate)","");
|
||||
assert(p.m_ClosureSeen&&p.m_ClosureComplete&&!p.m_BadProjectile);
|
||||
p.NativeCommit(&b,clockNow);assert(p.m_BadProjectile&&p.m_Commits==8); // ninth commit forbidden
|
||||
for(int fault=0;fault<11;fault++){
|
||||
Battery f;Probe q;q.m_Battery=&f;q.m_Gun=&gun;clockNow=20000;
|
||||
if(fault==0)f.report.ObservedAt=1001; // retimestamped contact
|
||||
if(fault==1)f.OrderId=2;
|
||||
if(fault==2)f.SourceId=8;
|
||||
if(fault==3)f.OrderShots=1; // skipped physical event
|
||||
if(fault==4)q.m_Step=2; // post-completion replay
|
||||
if(fault==5)q.m_CommitPending=true;
|
||||
if(fault==6){clockNow=61001;f.AimedAt=61000;f.AimValidatedAt=61000;}
|
||||
if(fault==7)f.AimValidatedAt=9999;
|
||||
if(fault==8)f.Released=false;
|
||||
if(fault==9)f.CommandOpen=false;
|
||||
if(fault==10)f.FlightTime=0;
|
||||
q.NativeCommit(&f,clockNow);assert(q.m_BadProjectile&&q.m_Commits==0);
|
||||
}
|
||||
Battery f;Probe q;q.m_Battery=&f;q.m_Gun=&gun;clockNow=20000;
|
||||
q.NativeCommit(&f,clockNow);q.NativeProjectile(&gun,&shots[0]);q.NativeProjectile(&gun,&shots[0]);assert(q.m_BadProjectile&&q.m_Events==1);
|
||||
for(int fault=0;fault<4;fault++){
|
||||
Battery f;Probe q;q.m_Battery=&f;q.m_Gun=&gun;q.m_Events=8;q.m_Commits=8;f.OrderShots=8;
|
||||
std::string reason="native artillery activity COMPLETED (shot count is separate)";
|
||||
if(fault==0){q.m_Events=4;q.m_Commits=4;f.OrderShots=4;}
|
||||
if(fault==1)reason="native aim or firing authorization rejected";
|
||||
if(fault==2)f.stopped=true;
|
||||
if(fault==3)q.m_CommitPending=true;
|
||||
q.NativeClosing(&f,reason,"delivered target report expired");assert(q.m_BadProjectile);
|
||||
}
|
||||
Battery stopped;Probe quiet;quiet.m_Battery=&stopped;quiet.m_Gun=&gun;quiet.m_Stopped=true;
|
||||
quiet.NativeCommit(&stopped,20000);quiet.NativeProjectile(&gun,&shots[0]);quiet.NativeClosing(&stopped,"HQ stopped","");
|
||||
assert(!quiet.m_BadProjectile&&quiet.m_Events==0&&quiet.m_Commits==0&&!quiet.m_ClosureSeen);
|
||||
}
|
||||
''')
|
||||
# Native hooks must count only real events and retain the existing superclass behavior.
|
||||
s=p.read_text()
|
||||
assert s.startswith('#ifdef WORKBENCH') and 'outcome == "mortar-salvo"' in s
|
||||
assert 'super.OnWeaponFired(effectEntity, muzzle, projectileEntity);' in s
|
||||
assert 'super.ReserveShellAirspace(now);' in s and 'super.Cancel(reason);' in s
|
||||
assert 'm_StopUntil = now + 25000' in s
|
||||
assert 'm_Battery.CanRequest(m_Delivered, now)' in s
|
||||
assert 'm_Battery.Order(' not in s and 'm_Battery.BeginRequest(' not in s
|
||||
assert 'm_Battery.Stop();' in body(p,'void Stop(')
|
||||
print('PASS: actual full-salvo gates require eight fresh committed physical launches, natural closure and exact finite inventory; reject partial/extra/replayed events')
|
||||
Reference in New Issue
Block a user