Include the current addon, terrain integrations, tools, regression tests and recorded development evidence.
85 lines
9.2 KiB
Python
85 lines
9.2 KiB
Python
"""Execute the opt-in fixture's exact callback/custody/snapshot/Candidate methods."""
|
|
import os,re
|
|
from pathlib import Path
|
|
from policy_harness import ROOT,body,run
|
|
P=Path(os.environ.get('ERR_NATIVE_MOUNTED_AMMO_SOURCE',ROOT/'addons/core/Scripts/Game/ERR/40_Chat/ERR_NativeMountedAmmoProbe.c'))
|
|
s=P.read_text()
|
|
assert s.startswith('#ifdef WORKBENCH') and s.rstrip().endswith('#endif')
|
|
for forbidden in ('TryMove','TrySwap','TrySpawn','SpawnEntity','SetOrigin','SetAmmoCount','.Dispatch(','.Ingest(','.Advance('):assert forbidden not in s
|
|
constructor=body(P,'void ERR_NativeMountedAmmoProbe(')
|
|
assert 'errMineStock' in constructor and 'now + 180000' in constructor
|
|
assert 'm_MineStock && (m_SwapEligibility' in constructor and 'errMountedCourier' in constructor
|
|
fleet=body(P,'protected bool Fleet(');tick=body(P,'int Tick(')
|
|
assert fleet.index('Mines(task, true)')<fleet.index('m_ProofTask = task')
|
|
assert tick.index('actual HQ Watch holds separate copy')<tick.index('Mines(m_ProofTask, false)')<tick.rindex('return 1')
|
|
assert 'fixed 180-second mine-stock and radio proof deadline' in tick
|
|
|
|
def cpp(x):
|
|
x=x.replace('protected ','').replace('null','nullptr').replace('foreach (','for (')
|
|
x=x.replace('array<IEntity> items = {};','Array<IEntity> items;').replace('array<IEntity> unique = {};','Array<IEntity> unique;').replace('array<IEntity> items','Array<IEntity> items')
|
|
for t in ('ERR_HQ','ERR_SupplyConvoyTask','ERR_ConvoyVehicle','ERR_ConvoyMineStock','ERR_ConvoyMineCargo','ERR_ConvoyCargoCallback','InventoryStorageManagerComponent','InventoryItemComponent','InventoryStorageSlot'):
|
|
x=re.sub(r'\b'+t+r' (?=\w)',t+'* ',x)
|
|
for n in ('InventoryStorageManagerComponent','InventoryItemComponent','ERR_InfantryAmmoTransfer','ERR_InfantryMineTransfer','ERR_Inventory','ERR_SupplyConvoyTask'):
|
|
x=x.replace(n+'.',n+'::')
|
|
x=x.replace('FindComponent(InventoryStorageManagerComponent)','Inventory()').replace('FindComponent(InventoryItemComponent)','Carried()').replace('FindComponent(DamageManagerComponent)','damage')
|
|
for n in ('m_Truck','m_Inventory','original','item','operation','carried','slot','task','truck','batch','inventory','hq','pending','vehicle','m_MineBatch'):
|
|
x=re.sub(r'\b'+n+r'\.',n+'->',x)
|
|
x=x.replace('truck->Entity.','truck->Entity->').replace('GetStorage().','GetStorage()->').replace('Convoys().','Convoys()->').replace('task->MineStock.','task->MineStock->')
|
|
x=re.sub(r'task->Cargo\[cargo\]\.',r'task->Cargo[cargo]->',x)
|
|
x=x.replace('bool ownsRoot;', 'bool ownsRoot=false;')
|
|
return x
|
|
callback=cpp(body(P,'bool ERR_FixtureMine('))
|
|
methods='\n'.join(cpp(body(P,k)) for k in ('protected bool MineCustody(', 'protected bool Mines(', 'protected ERR_SupplyConvoyTask Candidate('))
|
|
run(r'''
|
|
#include <cassert>
|
|
#include <vector>
|
|
#include <string>
|
|
#include <algorithm>
|
|
using string=std::string;
|
|
template<class T>struct Array:std::vector<T>{using std::vector<T>::vector;int Count(){return this->size();}bool Contains(T x){return std::find(this->begin(),this->end(),x)!=this->end();}void Insert(T x){this->push_back(x);}};
|
|
struct Entity;using IEntity=Entity*;struct InventoryStorageManagerComponent;struct InventoryItemComponent;struct InventoryStorageSlot;
|
|
struct Entity{bool ready=true,damage=true;IEntity under=nullptr;InventoryStorageManagerComponent*inventory=nullptr;InventoryItemComponent*carried=nullptr;InventoryStorageManagerComponent* Inventory(){return inventory;}InventoryItemComponent* Carried(){return carried;}};
|
|
struct Storage{InventoryStorageSlot*slot=nullptr;InventoryStorageSlot*GetSlot(int){return slot;}};
|
|
struct InventoryStorageSlot{IEntity item=nullptr;Storage*storage=nullptr;IEntity GetAttachedEntity(){return item;}Storage*GetStorage(){return storage;}int GetID(){return 0;}};
|
|
struct InventoryItemComponent{InventoryStorageSlot*slot=nullptr;InventoryStorageSlot*GetParentSlot(){return slot;}static auto Cast(InventoryItemComponent*x){return x;}};
|
|
struct InventoryStorageManagerComponent{IEntity owner=nullptr;Array<IEntity>items;IEntity GetOwner(){return owner;}static auto Cast(InventoryStorageManagerComponent*x){return x;}};
|
|
struct ERR_Inventory{static void Items(InventoryStorageManagerComponent*i,Array<IEntity>&items){items=i->items;}};
|
|
struct ERR_InfantryMineTransfer{static bool ReadyMine(IEntity i){return i&&i->ready;}};
|
|
struct ERR_InfantryAmmoTransfer{static bool StoredUnder(IEntity i,IEntity root){return i&&i->under==root;}};
|
|
struct ERR_ConvoyMineStock;
|
|
struct ERR_ConvoyVehicle{IEntity Entity=nullptr;bool Registered=true,Released=false;};
|
|
struct ERR_ConvoyCargoCallback{bool Finished=true;};
|
|
struct ERR_ConvoyMineCargo{bool Finished=true,Succeeded=true;IEntity Item=nullptr;};
|
|
struct ERR_SupplyConvoyTask{bool Stopped=false,Ready=true,MagazinesIssued=true;void*Receipt=this;Array<ERR_ConvoyVehicle*>Vehicles;Array<ERR_ConvoyCargoCallback*>Cargo;ERR_ConvoyMineStock*MineStock=nullptr;static auto Cast(ERR_SupplyConvoyTask*x){return x;}};
|
|
struct ERR_ConvoyMineStock{bool m_Closed=true;ERR_SupplyConvoyTask*m_Task=nullptr;ERR_ConvoyVehicle*m_Original=nullptr;IEntity m_Truck=nullptr;InventoryStorageManagerComponent*m_Inventory=nullptr;Array<IEntity>m_Items;Array<ERR_ConvoyMineCargo*>m_Cargo;
|
|
bool Complete(){return m_Closed;}int Count(){return m_Items.Count();}IEntity At(int i){return m_Items[i];}
|
|
'''+callback+r'''};
|
|
struct Pool{Array<ERR_SupplyConvoyTask*>tasks;int Count(){return tasks.Count();}ERR_SupplyConvoyTask*At(int i){return tasks[i];}};
|
|
struct ERR_HQ{Pool pool;Pool*Convoys(){return &pool;}};
|
|
template<class...T>void PrintFormat(T...){}
|
|
struct Probe{ERR_SupplyConvoyTask*m_ProofTask=nullptr;bool m_MineStock=true,m_Failed=false;ERR_ConvoyMineStock*m_MineBatch=nullptr;ERR_ConvoyVehicle*m_MineTruck=nullptr;InventoryStorageManagerComponent*m_MineInventory=nullptr;Array<IEntity>m_Mines;Array<ERR_ConvoyCargoCallback*>m_PrimaryCargo;void*m_Queued=nullptr;IEntity m_Root=nullptr;
|
|
bool Check(bool yes,string){if(!yes)m_Failed=true;return yes;}
|
|
'''+methods+r'''};
|
|
struct F{Probe p;ERR_HQ h;ERR_SupplyConvoyTask task;ERR_ConvoyVehicle vehicle;ERR_ConvoyMineStock batch;Entity truck,a,b;InventoryStorageManagerComponent inventory;Storage storageA,storageB;InventoryStorageSlot slotA,slotB;InventoryItemComponent itemA,itemB;ERR_ConvoyMineCargo callbackA,callbackB;ERR_ConvoyCargoCallback primary;
|
|
F(){vehicle.Entity=&truck;task.Vehicles={&vehicle,&vehicle,&vehicle,&vehicle,&vehicle,&vehicle};task.Cargo={&primary};task.MineStock=&batch;h.pool.tasks={&task};truck.inventory=&inventory;inventory.owner=&truck;inventory.items={&a,&b};
|
|
a.under=b.under=&truck;a.carried=&itemA;b.carried=&itemB;itemA.slot=&slotA;itemB.slot=&slotB;slotA.item=&a;slotB.item=&b;slotA.storage=&storageA;slotB.storage=&storageB;storageA.slot=&slotA;storageB.slot=&slotB;
|
|
callbackA.Item=&a;callbackB.Item=&b;batch.m_Task=&task;batch.m_Original=&vehicle;batch.m_Truck=&truck;batch.m_Inventory=&inventory;batch.m_Items={&a,&b};batch.m_Cargo={&callbackA,&callbackB};}
|
|
};
|
|
int main(){
|
|
{F f;assert(f.p.Candidate(&f.h)==&f.task&&f.p.Mines(&f.task,true));assert(f.p.m_Mines.Count()==2&&f.p.Mines(&f.task,false));}
|
|
{F f;f.batch.m_Items.pop_back();assert(f.p.Mines(&f.task,true)&&f.p.Mines(&f.task,false));}
|
|
{F f;f.batch.m_Closed=false;assert(!f.p.Candidate(&f.h));f.p.m_MineStock=false;assert(f.p.Candidate(&f.h)==&f.task);assert(f.p.Mines(nullptr,false));}
|
|
{F f;ERR_SupplyConvoyTask other=f.task;f.h.pool.tasks.push_back(&other);f.batch.m_Closed=false;assert(!f.p.Candidate(&f.h)&&f.p.m_ProofTask==&f.task);f.task.MineStock=nullptr;assert(!f.p.Candidate(&f.h)&&f.p.m_ProofTask==&f.task);f.task.MineStock=&f.batch;f.batch.m_Closed=true;assert(f.p.Candidate(&f.h)==&f.task);}
|
|
{F f;f.batch.m_Closed=false;assert(!f.p.Candidate(&f.h)&&f.p.m_MineBatch==&f.batch);ERR_ConvoyMineStock other=f.batch;other.m_Closed=true;f.task.MineStock=&other;assert(!f.p.Candidate(&f.h)&&f.p.m_Failed&&f.p.m_MineBatch==&f.batch);}
|
|
{F f;f.primary.Finished=false;assert(!f.p.Candidate(&f.h));f.primary.Finished=true;f.p.m_Queued=&f;Entity foreign;f.p.m_Root=&foreign;assert(!f.p.Candidate(&f.h));f.p.m_Root=&f.truck;assert(f.p.Candidate(&f.h)==&f.task);}
|
|
for(int bad=0;bad<14;bad++){F f;
|
|
if(bad==0){f.batch.m_Items.clear();}if(bad==1){f.batch.m_Items.push_back(&f.a);}if(bad==2){f.batch.m_Items[1]=&f.a;}if(bad==3){f.callbackA.Succeeded=false;}if(bad==4){f.callbackA.Finished=false;}if(bad==5){f.a.ready=false;}if(bad==6){f.a.damage=false;}if(bad==7){f.a.under=&f.b;}if(bad==8){f.inventory.items.erase(f.inventory.items.begin());}if(bad==9){f.slotA.item=&f.b;}if(bad==10){f.storageA.slot=&f.slotB;}if(bad==11){f.vehicle.Released=true;}if(bad==12){f.inventory.owner=&f.b;}if(bad==13){f.inventory.items.resize(129,&f.a);}
|
|
assert(!f.p.Mines(&f.task,true)&&f.p.m_Failed);}
|
|
for(int bad=0;bad<6;bad++){F f;assert(f.p.Mines(&f.task,true));ERR_ConvoyCargoCallback other;ERR_ConvoyMineStock replacement=f.batch;
|
|
if(bad==0){f.task.MineStock=&replacement;}if(bad==1){std::swap(f.batch.m_Items[0],f.batch.m_Items[1]);}if(bad==2){f.batch.m_Items.pop_back();}if(bad==3){f.task.Cargo[0]=&other;}if(bad==4){f.primary.Finished=false;}if(bad==5){f.inventory.items.clear();}
|
|
assert(!f.p.Mines(&f.task,false)&&f.p.m_Failed);}
|
|
{F f;f.batch.m_Truck=nullptr;assert(!f.batch.ERR_FixtureMine(&f.task,&f.vehicle,&f.a));}
|
|
}
|
|
''')
|
|
print('PASS: actual optional candidate barrier, exact callback/custody proof and unchanged mine/primary snapshots; no native transfer claim')
|