Files
jakub 6a667d8deb Capture current mission, AI, map and administration development
Include the current addon, terrain integrations, tools, regression tests and recorded development evidence.
2026-10-13 22:52:53 +02:00

124 lines
8.9 KiB
Python

"""Execute production mounted-report structural seat traversal with native doubles."""
import os,re
from pathlib import Path
from policy_harness import body,run,ROOT
seat_source=Path(os.environ.get('ERR_VEHICLE_SEATS_SOURCE',ROOT/'addons/core/Scripts/Game/ERR/10_AI/ERR_HQStatusSampler.c'))
mounted_source=Path(os.environ.get('ERR_MOUNTED_AMMO_SOURCE',ROOT/'addons/core/Scripts/Game/ERR/10_AI/ERR_HQMountedAmmoSampler.c'))
new=body(seat_source,'protected bool VehicleSeats(')
installed=body(mounted_source,'static bool Installed(')
def cpp(s):
s=s.replace('protected ','').replace('static ','').replace('int cursor;', 'int cursor=0;')
s=re.sub(r'Cast\(\s+', 'Cast(', s)
s=s.replace('array<BaseCompartmentSlot> seats','Array<Seat*>* seats').replace('seats.', 'seats->')
s=s.replace('array<IEntity>','Array<Node*>').replace('array<BaseCompartmentSlot>', 'Array<Seat*>')
for t,field in [('SCR_BaseCompartmentManagerComponent','manager'),('InventoryItemComponent','item')]:
s=s.replace(t+'.Cast(entity.FindComponent('+t+'))','entity->'+field)
s=s.replace('ChimeraCharacter.Cast(entity)','entity->character').replace('EStoragePurpose.','EStoragePurpose::')
s=s.replace('ERR_HQMountedAmmoSampler.', 'ERR_HQMountedAmmoSampler::')
s=s.replace('WeaponSlotComponent.Cast(slot.GetParentContainer())','slot->mount')
s=s.replace('BaseMuzzleComponent.Cast(slot.GetParentContainer())','slot->muzzle')
s=s.replace('InventoryStorageSlot ', 'Slot* ').replace('WeaponSlotComponent ', 'Mount* ').replace('BaseMuzzleComponent ', 'Muzzle* ').replace('BaseMagazineComponent ', 'Magazine* ')
s=s.replace('IEntity ', 'Node* ').replace('BaseCompartmentSlot ', 'Seat* ')
s=s.replace('SCR_BaseCompartmentManagerComponent ', 'Manager* ').replace('InventoryItemComponent ', 'Item* ').replace('BaseInventoryStorageComponent ', 'Storage* ')
for name in ('entity','manager','item','storage','child','mount','muzzle','magazine'):
s=s.replace(name+'.',name+'->')
s=s.replace('GetParentSlot().','GetParentSlot()->').replace('foreach (', 'for (')
return s
run(r'''
#include <cassert>
#include <vector>
#include <algorithm>
template<class T>struct Array:std::vector<T>{using std::vector<T>::vector;
int Count(){return this->size();}bool Contains(T v){return std::find(this->begin(),this->end(),v)!=this->end();}void Insert(T v){this->push_back(v);}};
struct Seat {void* occupant=nullptr;};
struct Manager{Array<Seat*> seats;void GetCompartments(Array<Seat*>& out){out=seats;}};
struct EStoragePurpose {enum{PURPOSE_UNSET=0,PURPOSE_DEPOSIT=1,PURPOSE_ATTACHMENT=2,PURPOSE_ANY=~0};};
struct Storage{int purpose=EStoragePurpose::PURPOSE_DEPOSIT;int GetPurpose(){return purpose;}};
struct Mount;struct Muzzle;
struct Slot{Storage* storage=nullptr;Mount* mount=nullptr;Muzzle* muzzle=nullptr;Storage* GetStorage(){return storage;}};
struct Item{Slot* parent=nullptr;Slot* GetParentSlot(){return parent;}};
struct Node{bool character=false;Manager* manager=nullptr;Item* item=nullptr;Node* child=nullptr;Node* sibling=nullptr;
Node* GetChildren(){return child;}Node* GetSibling(){return sibling;}};
struct Mount{Node* owner=nullptr;Node* weapon=nullptr;Slot* slot=nullptr;
Node* GetOwner(){return owner;}Node* GetWeaponEntity(){return weapon;}Slot* GetSlotInfo(){return slot;}};
struct Magazine{Node* owner=nullptr;Node* GetOwner(){return owner;}};
struct Muzzle{Node* owner=nullptr;Magazine* magazine=nullptr;
Node* GetOwner(){return owner;}Magazine* GetMagazine(){return magazine;}};
struct ERR_HQMountedAmmoSampler{
'''+cpp(installed).replace('bool Installed(', 'static bool Installed(')+r'''
};
struct After{
'''+cpp(new)+r'''
};
int main(){
After after;Node root,crew,seatPart,cargo;Manager manager,partManager;Seat front,rear,foreign;
root.manager=&manager;manager.seats={&front};seatPart.manager=&partManager;partManager.seats={&rear};
root.child=&crew;crew.character=true;crew.sibling=&seatPart;seatPart.sibling=&cargo;
// A valid occupied vehicle with a large soldier inventory fails the old
// all-descendant walk although the structural vehicle consists of two nodes.
Node carried[140];crew.child=&carried[0];for(int i=0;i<139;i++)carried[i].child=&carried[i+1];
Array<Seat*> seats;
assert(after.VehicleSeats(&root,&seats)&&seats.size()==2&&seats[0]==&front&&seats[1]==&rear);
// Deposit inventory cannot introduce foreign seats or consume structure budget.
Storage storage;Slot slot{&storage};Item item{&slot};cargo.item=&item;cargo.child=&carried[0];
Manager cargoManager;cargoManager.seats={&foreign};cargo.manager=&cargoManager;seats.clear();
assert(after.VehicleSeats(&root,&seats)&&seats.size()==2);
// A real attachment remains in structure; its seated occupant is not erased.
storage.purpose=EStoragePurpose::PURPOSE_ATTACHMENT;cargo.child=nullptr;seats.clear();
assert(after.VehicleSeats(&root,&seats)&&seats.size()==3&&seats[2]==&foreign);
// Unknown storage, cycles and oversized actual structure remain conservative.
for(int purpose:{EStoragePurpose::PURPOSE_UNSET,EStoragePurpose::PURPOSE_ANY}){
storage.purpose=purpose;seats.clear();assert(!after.VehicleSeats(&root,&seats));}
storage.purpose=EStoragePurpose::PURPOSE_DEPOSIT;seatPart.sibling=&root;seats.clear();assert(!after.VehicleSeats(&root,&seats));
seatPart.sibling=&cargo;crew.character=false;seats.clear();assert(!after.VehicleSeats(&root,&seats));
crew.character=true;root.manager=nullptr;partManager.seats={nullptr};seats.clear();assert(!after.VehicleSeats(&root,&seats));
assert(!after.VehicleSeats(nullptr,&seats)&&!after.VehicleSeats(&root,nullptr));
// Run both real production methods together: native installed weapon/magazine
// slots may expose null/UNSET/ANY storage without being deposit inventory.
for(int purpose:{-1,int(EStoragePurpose::PURPOSE_UNSET),int(EStoragePurpose::PURPOSE_ANY)}){
Node vehicle,gun,magazine,seat;Manager turretSeats;Seat occupied;occupied.occupant=&crew;
vehicle.child=&gun;gun.child=&magazine;magazine.sibling=&seat;seat.manager=&turretSeats;turretSeats.seats={&occupied};
Storage nativeStorage;nativeStorage.purpose=purpose;Slot gunSlot,magSlot;Item gunItem{&gunSlot},magItem{&magSlot};
Mount mount;mount.owner=&vehicle;mount.weapon=&gun;mount.slot=&gunSlot;gunSlot.mount=&mount;gun.item=&gunItem;
Muzzle muzzle;Magazine loaded;loaded.owner=&magazine;muzzle.owner=&gun;muzzle.magazine=&loaded;magSlot.muzzle=&muzzle;magazine.item=&magItem;
if(purpose>=0){gunSlot.storage=&nativeStorage;magSlot.storage=&nativeStorage;}
seats.clear();assert(after.VehicleSeats(&vehicle,&seats)&&seats.size()==1&&seats[0]==&occupied&&seats[0]->occupant==&crew);
}
// A queued but unvisited sibling is not an accepted mount owner. Nor are
// skipped crew/cargo or stale container links authorization to walk its seats.
for(int fault=0;fault<7;fault++){
Node vehicle,gun,later,outsider;Manager gunSeats;Seat occupied;gun.manager=&gunSeats;gunSeats.seats={&occupied};
vehicle.child=&gun;gun.sibling=&later;Slot gunSlot,otherSlot;Item gunItem{&gunSlot};gun.item=&gunItem;
Mount mount;mount.owner=&vehicle;mount.weapon=&gun;mount.slot=&gunSlot;gunSlot.mount=&mount;
if(fault==0)mount.owner=&later;
if(fault==1)mount.owner=&outsider;
if(fault==2)mount.slot=&otherSlot;
if(fault==3)mount.weapon=&outsider;
if(fault==4)gunSlot.mount=nullptr;
if(fault==5){vehicle.child=&later;later.sibling=&gun;gun.sibling=nullptr;later.character=true;mount.owner=&later;}
Storage deposit;Slot cargoSlot{&deposit};Item cargoItem{&cargoSlot};
if(fault==6){vehicle.child=&later;later.sibling=&gun;gun.sibling=nullptr;later.item=&cargoItem;mount.owner=&later;}
seats.clear();assert(!after.VehicleSeats(&vehicle,&seats)&&seats.empty());
}
// A loaded magazine cannot use a stale/detached or future owner's container.
for(int fault=0;fault<3;fault++){
Node vehicle,magazine,later;vehicle.child=&magazine;magazine.sibling=&later;
Slot magSlot;Item magItem{&magSlot};magazine.item=&magItem;Muzzle muzzle;Magazine loaded;
magSlot.muzzle=&muzzle;muzzle.owner=&vehicle;muzzle.magazine=&loaded;loaded.owner=&magazine;
if(fault==0)muzzle.owner=&later;
if(fault==1)muzzle.magazine=nullptr;
if(fault==2)loaded.owner=&later;
seats.clear();assert(!after.VehicleSeats(&vehicle,&seats));
}
// Cargo ancestry still excludes exact installed descendants, even if they
// contain a compartment manager; the external native seat isn't in this root.
{
Node vehicle,box,gun;vehicle.child=&box;box.child=&gun;Storage deposit;Slot cargoSlot{&deposit};Item cargoItem{&cargoSlot};box.item=&cargoItem;
Slot gunSlot;Item gunItem{&gunSlot};gun.item=&gunItem;Mount mount;mount.owner=&box;mount.weapon=&gun;mount.slot=&gunSlot;gunSlot.mount=&mount;
Manager hidden;Seat foreignSeat;hidden.seats={&foreignSeat};gun.manager=&hidden;
seats.clear();assert(after.VehicleSeats(&vehicle,&seats)&&seats.empty());
}
}
''')
print('PASS: production mounted structural seat scan ignores >128 carried/cargo descendants, shares exact native mount/magazine ownership, preserves attachment seats and exact occupants, rejects unknown/cyclic/oversize structures; native binding still requires qualification.')