"""Execute the actual finite native magazine transaction; engine behavior remains separate.""" from pathlib import Path import os,re from policy_harness import ROOT,run,body from test_finite_magazine_reservation import translated_reservation p=Path(os.environ.get('ERR_INFANTRY_TRANSFER_SOURCE',ROOT/'addons/core/Scripts/Game/ERR/10_AI/ERR_InfantryAmmoTransfer.c')) s=p.read_text() for forbidden in ('TrySpawn','DeleteEntity','SetOrigin','SetTransform','TryInsert','TryRemove','SetAmmoCount'): assert forbidden not in s,forbidden callback=s[s.index('class ERR_InfantryAmmoCallback'):s.index('// One exact physical')] code=s[s.index('class ERR_InfantryAmmoTransfer\n'):] code=re.sub(r'//[^\n]*','',code).replace('protected ','').replace('class ','struct ') for src,dst in { 'm_Donor.FindComponent(VehicleHelicopterSimulation)':'m_Donor->helicopter', 'InventoryItemComponent.Cast(loaded.GetOwner().FindComponent(InventoryItemComponent))':'loaded->GetOwner()->item', 'BaseMagazineComponent.Cast(exactMagazine.FindComponent(BaseMagazineComponent))':'exactMagazine->magazine', 'BaseWeaponManagerComponent.Cast(actor.FindComponent(BaseWeaponManagerComponent))':'actor->weapons', 'BaseWeaponComponent.Cast(rifle.FindComponent(BaseWeaponComponent))':'rifle->weapon', 'InventoryItemComponent.Cast(entity.FindComponent(InventoryItemComponent))':'entity->item', 'InventoryItemComponent.Cast(m_Magazine.FindComponent(InventoryItemComponent))':'m_Magazine->item', 'InventoryItemComponent.Cast(exact.FindComponent(InventoryItemComponent))':'exact->item', 'InventoryItemComponent.Cast(candidate.FindComponent(InventoryItemComponent))':'candidate->item', 'BaseMagazineComponent.Cast(m_Magazine.FindComponent(BaseMagazineComponent))':'m_Magazine->magazine', 'BaseMagazineComponent.Cast(candidate.FindComponent(BaseMagazineComponent))':'candidate->magazine', 'SCR_AIVehicleUsageComponent.Cast(m_Donor.FindComponent(SCR_AIVehicleUsageComponent))':'m_Donor->usage', 'InventoryStorageManagerComponent.Cast(m_Donor.FindComponent(InventoryStorageManagerComponent))':'m_Donor->inventory', 'InventoryStorageManagerComponent.Cast(m_Recipient.FindComponent(InventoryStorageManagerComponent))':'m_Recipient->inventory', }.items():code=code.replace(src,dst) code=code.replace('SCR_MuzzleInMagComponent.Cast(muzzle)', '(muzzle->inMag ? muzzle : null)') code=code.replace('ref ERR_InfantryAmmoCallback','ERR_InfantryAmmoCallback*').replace('array<','Array<').replace('foreach (','for (').replace('null','nullptr') code=re.sub(r'\bERR_GameMode (?=\w)','ERR_GameMode* ',code) code=code.replace('void ERR_InfantryAmmoTransfer(','ERR_InfantryAmmoTransfer(').replace('EWeaponType kind','int kind').replace('EMuzzleType muzzleKind','int muzzleKind') for name in ('ERR_InfantryAmmoTransferState','ERR_InfantryAmmoAccess','ERR_GameMode','ERR_EnemyEquipmentRules','ERR_ForceRules','Replication','SCR_Global','ERR_Actors','SCR_FactionManager','ERR_ConvoyRules','CompartmentAccessComponent','EWeaponType','EMuzzleType','EStoragePurpose','vector'): code=code.replace(name+'.',name+'::') for name in ('m_Mode','m_Donor','m_DonorGroup','m_Recipient','m_RecipientGroup','m_Source','m_Destination','m_Storage','m_OriginalSlot','m_Callback','magazine','reloadable','loaded','loadedItem','loadedSlot','manager','weapon','muzzle','entity','item','storage','inventory','incoming','empty','source','destination','m_ReturnCallback','donorRecord','recipientRecord','utility','usage','physics'): code=re.sub(r'\b'+name+r'\.',name+'->',code) code=code.replace('GetMagazineWell().','GetMagazineWell()->').replace('GetParentSlot().','GetParentSlot()->').replace('Forces().','Forces()->').replace('m_VehicleMgr.','m_VehicleMgr->').replace('GetPilotCompartmentSlot().','GetPilotCompartmentSlot()->') code=re.sub(r'\b(bool|int|Vehicle|IEntity|SCR_AIGroup|ERR_ForceRecord|InventoryStorageSlot|InventoryStorageManagerComponent|BaseInventoryStorageComponent|ERR_GameMode\*|ERR_InfantryAmmoCallback\*) (\w+);',r'\1 \2{};',code) code=code.replace('\n}\n','\n};\n') callback=callback.replace('class ERR_InfantryAmmoCallback : ScriptedInventoryOperationCallback','').strip()[1:-1] callbacks=[] for name in ('OnComplete','OnFailed','OnAllComplete','OnAllFailed'): m=re.search(r'protected override void '+name+r'\(\) (\{[^\n]+\})',callback) callbacks.append('void ERR_InfantryAmmoCallback::'+name+'() '+m[1].replace('Transfer.','Transfer->')) # Integrate the actual coordinator transfer selector with this actual leaf. coordinator_path=Path(os.environ.get('ERR_INFANTRY_RESUPPLY_SOURCE',ROOT/'addons/core/Scripts/Game/ERR/10_AI/ERR_InfantryResupply.c')) transfer=body(coordinator_path,'protected void Transfer(float now)').replace('protected ','').replace('null','nullptr').replace('foreach (','for (') transfer=transfer.replace('ERR_HQAmmoSnapshot local','ERR_HQAmmoSnapshot* local') for name in ('ERR_Actors','ERR_HQAmmoSampler','ERR_InfantryAmmoTransfer','vector'): transfer=transfer.replace(name+'.',name+'::') transfer=transfer.replace('ERR_FiniteMagazineReservation reservation', 'ERR_FiniteMagazineReservation* reservation').replace('new ERR_FiniteMagazineReservation(m_Stock, m_Spent,', 'new ERR_FiniteMagazineReservation(&m_Stock, &m_Spent,') for name in ('m_Move','actor','m_Truck','m_Recipient','local','reservation'): transfer=transfer.replace(name+'.',name+'->') transfer=transfer.replace('Entity.GetOrigin()', 'Entity->GetOrigin()') pre=r''' #include #include #include #include #include #include #include using string=std::string; templatestruct Array:std::vector{using std::vector::vector;int Count(){return this->size();}bool IsEmpty(){return this->empty();}void Insert(T t){this->push_back(t);}void RemoveItem(T t){this->erase(std::remove(this->begin(),this->end(),t),this->end());}bool Contains(T t){return std::find(this->begin(),this->end(),t)!=this->end();}}; struct vector{float x=0,y=0,z=0;float Length(){return std::sqrt(x*x+y*y+z*z);}static float DistanceXZ(vector a,vector b){return std::hypot(a.x-b.x,a.z-b.z);}static float Distance(vector a,vector b){return vector{a.x-b.x,a.y-b.y,a.z-b.z}.Length();}}; struct Entity;struct Group;struct Inventory;struct Storage;struct Item;struct Slot;struct Magazine;struct Weapon;struct Muzzle;struct Manager;struct Utility;struct Usage;struct Physics_;struct Record; using IEntity=Entity*;using Vehicle=Entity*;using SCR_AIGroup=Group*;using ERR_ForceRecord=Record*; using InventoryStorageSlot=Slot*;using InventoryStorageManagerComponent=Inventory*;using BaseInventoryStorageComponent=Storage*;using InventoryItemComponent=Item*;using BaseMagazineComponent=Magazine*; using BaseWeaponManagerComponent=Manager*;using BaseWeaponComponent=Weapon*;using BaseMuzzleComponent=Muzzle*;using SCR_MuzzleInMagComponent=Muzzle*; using SCR_AIGroupUtilityComponent=Utility*;using SCR_AIVehicleUsageComponent=Usage*;using Physics=Physics_*; enum ERR_InfantryAmmoTransferState{FAILED=-1,PENDING,SUCCEEDED}; struct ERR_InfantryAmmoTransfer; struct ScriptedInventoryOperationCallback{virtual void OnComplete(){}virtual void OnFailed(){}virtual void OnAllComplete(){}virtual void OnAllFailed(){}virtual ~ScriptedInventoryOperationCallback()=default;}; struct ERR_InfantryAmmoCallback:ScriptedInventoryOperationCallback{ERR_InfantryAmmoTransfer*Transfer=nullptr;bool Returning=false;void OnComplete()override;void OnFailed()override;void OnAllComplete()override;void OnAllFailed()override;}; struct EWeaponType{static const int WT_RIFLE=1,WT_SNIPERRIFLE=2,WT_MACHINEGUN=3,WT_HANDGUN=4,WT_GRENADELAUNCHER=5,WT_ROCKETLAUNCHER=6;}; struct EMuzzleType{static const int MT_BaseMuzzle=0,MT_UGLMuzzle=1,MT_RPGMuzzle=2;};struct EStoragePurpose{static const int PURPOSE_DEPOSIT=1;}; struct Well{int type=1,parent=0;int Type(){return type;}bool IsInherited(int t){return type==t||parent==t;}}; struct Magazine{IEntity owner=nullptr;IEntity GetOwner(){return owner;}Well*well=nullptr;int rounds=30,capacity=30;bool used=false;bool IsUsed(){return used;}Well*GetMagazineWell(){return well;}int GetAmmoCount(){return rounds;}int GetMaxAmmoCount(){return capacity;}}; struct Muzzle{bool inMag=false,canReload=true;bool CanBeReloaded(){return canReload;}bool disposable=false;bool IsDisposable(){return disposable;}Magazine*loaded=nullptr;Magazine*GetMagazine(){return loaded;}Well*well=nullptr;int kind=0;Well*GetMagazineWell(){return well;}int GetMuzzleType(){return kind;}}; struct Weapon{IEntity owner=nullptr;Arraymuzzles;int kind=1;IEntity GetOwner(){return owner;}int GetWeaponType(){return kind;}void GetMuzzlesList(Array&a){a=muzzles;}}; struct Manager{Arrayweapons;void GetWeaponsList(Array&a){a=weapons;}}; struct Storage{IEntity owner=nullptr;IEntity GetOwner(){return owner;}}; struct Slot{Storage*storage=nullptr;IEntity occupant=nullptr;Muzzle*container=nullptr;IEntity attached=nullptr;Muzzle*GetParentContainer(){return container;}IEntity GetAttachedEntity(){return attached;}Storage*GetStorage(){return storage;}IEntity GetOccupant(){return occupant;}}; struct Item{Slot*slot=nullptr;Slot*GetParentSlot(){return slot;}}; struct Physics_{vector velocity,angular;vector GetVelocity(){return velocity;}vector GetAngularVelocity(){return angular;}}; struct Usage{Slot*pilot=nullptr;Slot*GetPilotCompartmentSlot(){return pilot;}}; struct VehicleManager{IEntity vehicle=nullptr;IEntity FindVehicle(IEntity v){return vehicle==v?v:nullptr;}}; struct Utility{VehicleManager*m_VehicleMgr=nullptr;bool military=true;bool IsMilitary(){return military;}}; struct Group{int faction=1,players=0;bool slave=false;Utility*utility=nullptr;int GetPlayerCount(bool){return players;}int GetFaction(){return faction;}bool IsSlave(){return slave;}Utility*GetGroupUtilityComponent(){return utility;}}; struct Entity{bool helicopter=false;bool alive=true,awake=true,player=false,captured=false;int faction=1;Group*group=nullptr;IEntity vehicle=nullptr,parent=nullptr; Inventory*inventory=nullptr;Magazine*magazine=nullptr;Manager*weapons=nullptr;Weapon*weapon=nullptr;Item*item=nullptr;Usage*usage=nullptr;Physics_*physics=nullptr;vector position; IEntity GetParent(){return parent;}Physics_*GetPhysics(){return physics;}vector GetOrigin(){return position;}}; struct Record{SCR_AIGroup Group=nullptr;bool Physical=true,Eliminated=false;}; struct Ledger{Arrayrecords;Record*FindGroup(SCR_AIGroup g){for(auto*r:records)if(r->Group==g)return r;return nullptr;}}; struct ERR_GameMode{inline static ERR_GameMode*current=nullptr;bool active=true;Ledger*ledger=nullptr;static ERR_GameMode*Get(){return current;}bool Active(){return active;}Ledger*Forces(){return ledger;}int EnemyFaction(){return 1;}}; struct Replication{inline static bool server=true;static bool IsServer(){return server;}}; struct SCR_Global{inline static bool editor=false;static bool IsEditMode(){return editor;}}; struct ERR_Actors{static bool CanFight(IEntity a){return a&&a->alive&&a->awake;}static bool Alive(IEntity a){return a&&a->alive;}}; struct SCR_FactionManager{static int SGetFaction(IEntity a){return a?a->faction:-1;}}; struct CompartmentAccessComponent{static IEntity GetVehicleIn(IEntity a){return a?a->vehicle:nullptr;}}; struct ERR_ConvoyRules{static bool Captured(Vehicle v,SCR_AIGroup g){return v->captured||g->players>0;}static bool PartOf(IEntity a,IEntity root){return a==root;}}; struct ERR_EnemyEquipmentRules{static bool Eligible(ERR_GameMode*m,SCR_AIGroup g,IEntity a){return m&&g&&a&&a->alive&&a->awake&&!a->player&&a->group==g&&g->players==0&&g->faction==m->EnemyFaction()&&g->utility&&g->utility->military;}}; struct ERR_ForceRules{static bool Finite(float n){return std::isfinite(n);}}; struct ERR_InfantryAmmoAccess{static inline bool clear=true;static inline int checks=0;static bool Clear(Vehicle donor,IEntity recipient){assert(donor&&recipient);checks++;return clear;}}; struct Inventory{IEntity owner=nullptr;Arrayitems;Arraystorages;Storage*selected=nullptr;bool allow=true,accept=true;int calls=0,callback=0;ScriptedInventoryOperationCallback*last=nullptr;std::function effect; IEntity GetOwner(){return owner;}void GetItems(Array&a,int purpose){assert(purpose==1);a=items;}void GetStorages(Array&a,int purpose){assert(purpose==1);a=storages;} Storage*FindStorageForItem(IEntity,int purpose){assert(purpose==1);return selected;} bool CanMoveItemToStorage(IEntity,Storage*,int slot){assert(slot==-1);return allow;} bool TryMoveItemToStorage(IEntity,Storage*,int slot,ScriptedInventoryOperationCallback*cb){assert(slot==-1);calls++;last=cb;if(effect)effect();if(callback==1){cb->OnComplete();}if(callback==2){cb->OnFailed();}return accept;}}; ''' main=r''' struct Fixture{ERR_GameMode mode;Ledger ledger;Group donorGroup,recipientGroup,otherGroup;Record donorRecord,recipientRecord;Entity truck,recipient,driver,spareDriver,magEntity,rifle,foreign; VehicleManager vehicleManager;Utility donorUtility,recipientUtility;Physics_ physics;Usage usage;Slot pilot,fromSlot,toSlot;Storage sourceStorage,targetStorage;Inventory source,destination;Item item;Magazine magazine;Manager weapons;Weapon weapon;Muzzle muzzle;Well well; Fixture(){ERR_GameMode::current=&mode;mode.ledger=&ledger;donorRecord.Group=&donorGroup;recipientRecord.Group=&recipientGroup;ledger.records={&donorRecord,&recipientRecord}; donorGroup.utility=&donorUtility;recipientGroup.utility=&recipientUtility;donorUtility.m_VehicleMgr=&vehicleManager;vehicleManager.vehicle=&truck; truck.physics=&physics;truck.usage=&usage;usage.pilot=&pilot;pilot.occupant=&driver;driver.group=&donorGroup;driver.vehicle=&truck;spareDriver.group=&donorGroup;spareDriver.vehicle=&truck; recipient.group=&recipientGroup;recipient.position.x=4;truck.inventory=&source;source.owner=&truck;recipient.inventory=&destination;destination.owner=&recipient; sourceStorage.owner=&truck;targetStorage.owner=&recipient;source.storages={&sourceStorage};destination.storages={&targetStorage};destination.selected=&targetStorage; source.items={&magEntity};magEntity.item=&item;item.slot=&fromSlot;fromSlot.storage=&sourceStorage;fromSlot.attached=&magEntity;toSlot.storage=&targetStorage;magEntity.magazine=&magazine;magazine.well=&well; recipient.weapons=&weapons;weapons.weapons={&rifle};rifle.weapon=&weapon;weapon.owner=&rifle;weapon.muzzles={&muzzle};muzzle.well=&well;} ERR_InfantryAmmoTransfer Job(){return ERR_InfantryAmmoTransfer(&mode,&truck,&donorGroup,&recipient,&recipientGroup,&magEntity,true);} void Move(){source.items.RemoveItem(&magEntity);destination.items.Insert(&magEntity);item.slot=&toSlot;} }; struct EmptyFixture:Fixture{ Entity empty,secondEmpty;Magazine emptyMag;Item emptyItem,secondItem;Slot emptyFrom,emptyTo; EmptyFixture(){emptyMag.well=&well;emptyMag.rounds=0;empty.magazine=&emptyMag;empty.item=&emptyItem; emptyFrom.storage=&targetStorage;emptyTo.storage=&sourceStorage;emptyItem.slot=&emptyFrom; secondEmpty.magazine=&emptyMag;secondEmpty.item=&secondItem;secondItem.slot=&emptyFrom; destination.items={&empty,&secondEmpty};destination.selected=nullptr;source.selected=&sourceStorage;} void Return(bool capacity=true){destination.items.RemoveItem(&empty);source.items.Insert(&empty);emptyItem.slot=&emptyTo;if(capacity)destination.selected=&targetStorage;} }; struct ERR_HQAmmoSnapshot{bool Complete=true,LauncherComplete=true;int Members=1,LauncherMuzzles=1,LauncherMagazines=1,LauncherRounds=0,LauncherChambers=0;bool Valid(int n){return n==Members;}int SmallArmsMuzzles=1,SmallArmsRounds=0,SmallArmsChambers=0;}; struct ERR_HQAmmoSampler{static void Inspect(IEntity actor,SCR_AIGroup group,ERR_HQAmmoSnapshot* stock){assert(actor&&actor->group==group&&stock);}}; struct SupplyTruck{IEntity Entity;SCR_AIGroup Group;}; struct SupplyRecipient{SCR_AIGroup Group;}; struct Coordinator{bool m_LauncherTrip=false;ERR_GameMode* m_Mode;SupplyTruck* m_Truck;SupplyRecipient* m_Recipient; ERR_InfantryAmmoTransfer* m_Move=nullptr;Arraym_Members,m_Stock,m_Spent,m_Served;IEntity m_Receiving=nullptr; int m_Delivered=0,m_TripDelivered=0,finishes=0,audits=0; void Finish(string){finishes++;if(m_Move)m_Move->Stop();} void Audit(string){audits++;} bool Contains(IEntity owner,IEntity item){return owner&&owner->inventory&&owner->inventory->items.Count()<=128&&owner->inventory->items.Contains(item);} '''+transfer+r''' }; struct SupplyFixture:Fixture{SupplyTruck supplyTruck;SupplyRecipient supplyRecipient;Coordinator c; SupplyFixture():supplyTruck{&truck,&donorGroup},supplyRecipient{&recipientGroup}{ c.m_Mode=&mode;c.m_Truck=&supplyTruck;c.m_Recipient=&supplyRecipient;c.m_Members={&recipient};c.m_Stock={&magEntity};} }; struct LauncherFixture:SupplyFixture{Entity loaded;Magazine empty;Item loadedItem;Slot loadedSlot; LauncherFixture(){c.m_LauncherTrip=true;weapon.kind=EWeaponType::WT_GRENADELAUNCHER;muzzle.kind=EMuzzleType::MT_UGLMuzzle; rifle.parent=&recipient;loaded.parent=&rifle;loaded.magazine=∅empty.owner=&loaded;empty.well=&well;empty.rounds=0;muzzle.loaded=∅loaded.item=&loadedItem;loadedItem.slot=&loadedSlot;loadedSlot.container=&muzzle;loadedSlot.attached=&loaded;} }; int main(){ // The shared force claim is necessary: independent rifle leaves can otherwise // submit the same still-carried empty to two different trucks. Native acceptance // is delayed here; this proves submission interference, not an engine outcome. {EmptyFixture first;Fixture second;ERR_GameMode::current=&first.mode; first.ledger.records.Insert(&second.donorRecord);second.source.selected=&second.sourceStorage; auto old=first.Job();assert(old.Tick(0)==PENDING&&old.Unresolved()); assert(old.m_ReturnMagazine==&first.empty&&old.m_ReturnStorage==&first.sourceStorage); old.Stop();assert(old.Unresolved()&&old.Tick(180001)==FAILED); ERR_InfantryAmmoTransfer next(&first.mode,&second.truck,&second.donorGroup,&first.recipient,&first.recipientGroup,&second.magEntity,true); assert(next.Tick(180001)==PENDING&&next.Unresolved()); assert(first.destination.calls==2&&next.m_ReturnMagazine==old.m_ReturnMagazine); assert(next.m_ReturnStorage==&second.sourceStorage&&next.m_ReturnStorage!=old.m_ReturnStorage); assert(first.destination.items.Contains(&first.empty)&&first.source.calls==0&&second.source.calls==0); // No duplicate object is invented: one physical completion can settle only its // original donor proof; the competing outstanding submission remains unknown. first.Return();old.m_ReturnCallback->OnComplete();assert(!old.Unresolved()&&next.Unresolved()); assert(old.Tick(180002)==FAILED&&first.source.calls==0&&second.source.calls==0);} // Rifle moves must obey the same irreversible cancellation boundary as launchers. // Native inventory processing may synchronously invoke mission/ownership events. for(int loss=0;loss<4;loss++){Fixture f;auto t=f.Job(); f.source.effect=[&](){if(loss==0)t.Stop();if(loss==1)f.truck.captured=true;if(loss==2)f.mode.active=false;if(loss==3)f.recipient.group=&f.otherGroup;f.Move();}; f.source.callback=1;assert(t.Tick(0)==FAILED&&t.Submitted()&&!t.Unresolved()&&f.source.calls==1); assert(t.Tick(1)==FAILED&&f.source.calls==1);} // Callback without custody after cancellation retains uncertainty until the // original physical identity arrives, without resurrecting success or retry. {Fixture f;auto t=f.Job();f.source.effect=[&](){t.Stop();};f.source.callback=1; assert(t.Tick(0)==FAILED&&t.Submitted()&&t.Unresolved());f.Move();assert(!t.Unresolved());assert(t.Tick(1)==FAILED&&f.source.calls==1);} // Coordinator must never book a cancelled native rifle transfer as delivery. {SupplyFixture f;f.source.effect=[&](){f.c.m_Move->Stop();f.Move();};f.source.callback=1; f.c.Transfer(0);assert(f.c.m_Spent.Count()==1&&f.c.m_Delivered==0);f.c.Transfer(1000); assert(f.c.finishes==1&&f.c.m_Delivered==0&&f.c.m_Spent.Count()==1&&f.source.calls==1);} // Failed callback settles only exact original unchanged custody; unknown never does. {LauncherFixture f;f.source.callback=2;f.c.Transfer(0);assert(f.c.m_Move->Submitted()&&!f.c.m_Move->Unresolved()&&f.c.m_Spent.Count()==1);f.c.Transfer(1000);assert(f.source.calls==1&&f.c.m_Spent.Count()==1);} for(int bad=0;bad<7;bad++){LauncherFixture f;f.c.Transfer(0);assert(f.c.m_Move->Unresolved()); if(bad!=0)f.source.last->OnFailed(); if(bad==1)f.item.slot=nullptr; if(bad==2)f.fromSlot.attached=nullptr; if(bad==3)f.sourceStorage.owner=&f.foreign; if(bad==4)f.destination.items.Insert(&f.magEntity); if(bad==5)f.truck.inventory=&f.destination; if(bad==6)f.source.items.RemoveItem(&f.magEntity); assert(f.c.m_Move->Unresolved());f.c.m_Move->Stop();assert(f.c.m_Move->Unresolved());} {LauncherFixture f;f.muzzle.loaded=nullptr;assert(ERR_InfantryAmmoTransfer::Compatible(&f.recipient,&f.magEntity,true));f.c.Transfer(0);assert(f.source.calls==1&&f.c.m_Move->Submitted());} {LauncherFixture f;assert(!ERR_InfantryAmmoTransfer::Compatible(&f.recipient,&f.magEntity));assert(ERR_InfantryAmmoTransfer::Compatible(&f.recipient,&f.magEntity,true)); f.c.Transfer(0);assert(f.c.m_Move&&f.c.m_Move->Submitted()&&f.c.m_Spent.Count()==1&&f.source.calls==1); f.Move();f.source.last->OnComplete();f.c.Transfer(1000);f.c.Transfer(2000);assert(f.c.m_Delivered==1&&f.source.calls==1&&f.c.m_Served.Count()==1);} for(int bad=0;bad<8;bad++){LauncherFixture f;if(bad==0)f.magazine.used=true;if(bad==1)f.muzzle.well=nullptr;if(bad==2)f.muzzle.disposable=true;if(bad==3)f.empty.well=nullptr;if(bad==4)f.loadedSlot.attached=nullptr;if(bad==5)f.rifle.parent=nullptr;if(bad==6)f.empty.capacity=0;if(bad==7){f.muzzle.inMag=true;f.muzzle.canReload=false;} f.c.Transfer(0);assert(!f.c.m_Move&&f.source.calls==0&&f.c.m_Spent.IsEmpty());} {LauncherFixture f;f.source.accept=false;f.c.Transfer(0);assert(f.c.m_Move&&f.c.m_Move->Submitted()&&f.c.m_Move->Unresolved()&&f.c.m_Spent.Count()==1);f.c.Transfer(1000);assert(f.source.calls==1);f.Move();f.source.last->OnComplete();assert(!f.c.m_Move->Unresolved());} {LauncherFixture f;auto t=ERR_InfantryAmmoTransfer(&f.mode,&f.truck,&f.donorGroup,&f.recipient,&f.recipientGroup,&f.magEntity,false,true); f.source.effect=[&](){t.Stop();f.Move();};f.source.callback=1;assert(t.Tick(0)==FAILED&&!t.Unresolved()&&f.source.calls==1);assert(t.Tick(1)==FAILED);} // A capacity recovery uses one exact unused empty, separately proving both native operations. {Fixture f;Entity empty;Magazine emptyMag;Item emptyItem;Slot emptyFrom{&f.targetStorage},emptyTo{&f.sourceStorage}; emptyMag.well=&f.well;emptyMag.rounds=0;empty.magazine=&emptyMag;empty.item=&emptyItem;emptyItem.slot=&emptyFrom; f.destination.items={&empty};f.destination.selected=nullptr;f.source.selected=&f.sourceStorage; auto t=f.Job();assert(t.Tick(0)==PENDING&&t.Submitted()&&t.Unresolved()&&f.destination.calls==1&&f.source.calls==0); auto returning=f.destination.last;returning->OnComplete();assert(t.Tick(1)==PENDING&&f.source.calls==0&&t.Unresolved()); f.destination.items.clear();f.source.items.Insert(&empty);emptyItem.slot=&emptyTo;f.destination.selected=&f.targetStorage; assert(t.Tick(2)==PENDING&&!t.Unresolved()&&f.source.calls==0);assert(t.Tick(3)==PENDING&&f.source.calls==1&&t.Unresolved()); returning->OnAllComplete();returning->OnFailed();assert(t.Tick(4)==PENDING&&t.Unresolved()); f.Move();assert(t.Tick(5)==PENDING);f.source.last->OnComplete();assert(t.Tick(6)==SUCCEEDED&&!t.Unresolved()); assert(f.destination.calls==1&&f.source.calls==1);} // Ground coordinator reserves the incoming identity as soon as reverse native movement is submitted. // A failed/ambiguous return never releases it to try a second empty or another incoming magazine. for(int outcome=0;outcome<3;outcome++){EmptyFixture f;SupplyTruck truck{&f.truck,&f.donorGroup};SupplyRecipient recipient{&f.recipientGroup};Coordinator c; c.m_Mode=&f.mode;c.m_Truck=&truck;c.m_Recipient=&recipient;c.m_Members={&f.recipient};c.m_Stock={&f.magEntity}; if(outcome==0){f.destination.accept=false;} c.Transfer(0);assert(c.m_Move&&c.m_Move->Submitted()&&c.m_Spent.Count()==1&&c.m_Receiving==&f.recipient&&c.m_Delivered==0); if(outcome==1){f.Return(false);f.destination.last->OnComplete();c.Transfer(1000);} c.Transfer(outcome==2?8000:2000);assert(c.finishes==1&&c.m_Spent.Contains(&f.magEntity)&&c.m_Delivered==0&&f.destination.calls==1&&f.source.calls==0); assert(c.m_Move->Unresolved()==(outcome==2));} {EmptyFixture f;SupplyTruck truck{&f.truck,&f.donorGroup};SupplyRecipient recipient{&f.recipientGroup};Coordinator c; c.m_Mode=&f.mode;c.m_Truck=&truck;c.m_Recipient=&recipient;c.m_Members={&f.recipient};c.m_Stock={&f.magEntity}; c.Transfer(0);f.Return();f.destination.last->OnComplete();c.Transfer(1000);assert(c.m_Delivered==0&&f.source.calls==0); c.Transfer(2000);assert(c.m_Delivered==0&&f.source.calls==1);f.Move();f.source.last->OnComplete();c.Transfer(3000);c.Transfer(4000); assert(c.m_Delivered==1&&c.m_Served.Count()==1&&c.m_Spent.Count()==1&&f.source.calls==1&&f.destination.calls==1&&f.source.items.Contains(&f.empty));} // Default callers (including air delivery) retain the original one-way behavior. {EmptyFixture f;ERR_InfantryAmmoTransfer t(&f.mode,&f.truck,&f.donorGroup,&f.recipient,&f.recipientGroup,&f.magEntity); assert(t.Tick(0)==FAILED&&!t.Submitted()&&f.destination.calls==0&&f.source.calls==0);} // No return when capacity already exists, even with carried empties. {EmptyFixture f;f.destination.selected=&f.targetStorage;auto t=f.Job();assert(t.Tick(0)==PENDING&&f.source.calls==1&&f.destination.calls==0);} // Unused, zero-round, exact-well, exclusive recipient storage ownership and donor space are required. for(int invalid=0;invalid<12;invalid++){EmptyFixture f;f.destination.items={&f.empty};Well other;other.type=2; if(invalid==0)f.emptyMag.used=true;if(invalid==1)f.emptyMag.rounds=1;if(invalid==2)f.emptyMag.rounds=-1; if(invalid==3)f.emptyMag.capacity=0;if(invalid==4)f.emptyMag.well=&other;if(invalid==5)f.emptyMag.well=nullptr; if(invalid==6)f.emptyItem.slot=&f.emptyTo;if(invalid==7)f.source.items.Insert(&f.empty); if(invalid==8)f.source.selected=nullptr;if(invalid==9)f.destination.allow=false; if(invalid==10){for(int i=0;i<129;i++)f.destination.items.Insert(&f.empty);}if(invalid==11)ERR_InfantryAmmoAccess::clear=false; auto t=f.Job();assert(t.Tick(0)==FAILED&&!t.Submitted()&&!t.Unresolved()&&f.destination.calls==0&&f.source.calls==0); ERR_InfantryAmmoAccess::clear=true;} // Return proof needs exact destination slot as well as callback; no second candidate is ever moved. {EmptyFixture f;auto t=f.Job();t.Tick(0);f.Return();f.emptyItem.slot=&f.emptyFrom;f.destination.last->OnComplete(); assert(t.Tick(1)==PENDING&&t.Unresolved()&&f.source.calls==0&&f.destination.calls==1); f.emptyItem.slot=&f.emptyTo;assert(t.Tick(2)==PENDING&&!t.Unresolved());assert(t.Tick(3)==PENDING&&f.source.calls==1&&f.destination.calls==1);} // Inline success callbacks override a false API result for the reverse operation, but require physical proof. {EmptyFixture f;f.destination.accept=false;f.destination.callback=1;f.destination.effect=[&](){f.Return();};auto t=f.Job(); assert(t.Tick(0)==PENDING&&t.Submitted()&&!t.Unresolved());assert(t.Tick(1)==PENDING&&f.source.calls==0); f.source.accept=false;f.source.callback=1;f.source.effect=[&](){f.Move();};assert(t.Tick(2)==SUCCEEDED&&f.source.calls==1&&f.destination.calls==1);} // Every attempted reverse move burns the incoming identity, including synchronous rejection. for(int failure=0;failure<3;failure++){EmptyFixture f;if(failure==0)f.destination.accept=false;if(failure==1)f.destination.callback=2; auto t=f.Job();assert(t.Tick(0)==PENDING&&t.Submitted()&&f.destination.calls==1&&f.source.calls==0); assert(t.Tick(failure==2?8000:1)==FAILED);assert(t.Unresolved()==(failure==2)); for(int i=0;i<3;i++){t.Tick(9000+i);}assert(f.destination.calls==1&&f.source.calls==0);} // Stop before, during, or after confirmed return can never launch the incoming move. for(int stopAt=0;stopAt<3;stopAt++){EmptyFixture f;auto t=f.Job();if(stopAt==0){t.Stop();assert(t.Tick(0)==FAILED&&!t.Submitted());continue;} t.Tick(0);if(stopAt==2){f.Return();f.destination.last->OnComplete();assert(t.Tick(1)==PENDING&&!t.Unresolved());} t.Stop();assert(t.Tick(2)==FAILED&&t.Submitted()&&f.source.calls==0);if(stopAt==1){assert(t.Unresolved());f.Return();f.destination.last->OnAllComplete();} assert(!t.Unresolved()&&t.Tick(3)==FAILED&&f.source.calls==0&&f.destination.calls==1);} // Confirmed return cannot trigger a second empty or bypass revalidated incoming custody/capacity/access. for(int changed=0;changed<6;changed++){EmptyFixture f;auto t=f.Job();t.Tick(0);f.Return(changed!=0);f.destination.last->OnComplete();assert(t.Tick(1)==PENDING); if(changed==1)f.source.items.RemoveItem(&f.magEntity);if(changed==2)f.destination.items.Insert(&f.magEntity); if(changed==3)f.truck.captured=true;if(changed==4)f.recipient.player=true;if(changed==5)ERR_InfantryAmmoAccess::clear=false; assert(t.Tick(2)==FAILED&&t.Submitted()&&!t.Unresolved()&&f.source.calls==0&&f.destination.calls==1); assert(t.Tick(3)==FAILED&&f.destination.calls==1);ERR_InfantryAmmoAccess::clear=true;} // Original owner/driver/ledger loss while a return is accepted quarantines that exact operation. for(int changed=0;changed<4;changed++){EmptyFixture f;auto t=f.Job();t.Tick(0); if(changed==0)f.truck.captured=true;if(changed==1)f.recipient.player=true;if(changed==2)f.pilot.occupant=&f.spareDriver;if(changed==3)f.donorRecord.Eliminated=true; assert(t.Tick(1)==FAILED&&t.Unresolved());f.destination.last->OnFailed();assert(!t.Unresolved()&&f.source.calls==0&&f.destination.calls==1);} // Both native phases are bounded independently, with no renewal while waiting for callbacks. {EmptyFixture f;auto t=f.Job();t.Tick(0);f.Return();f.destination.last->OnComplete();assert(t.Tick(7999)==PENDING); assert(t.Tick(8000)==PENDING&&f.source.calls==1);assert(t.Tick(15999)==FAILED&&t.Unresolved());} // XZ approach can precede valid vertical reach, stopped state, capacity or clear access. // None of those no-submission outcomes consumes cargo or ends the trip; the same exact item can later submit once. for(int obstruction=0;obstruction<5;obstruction++){SupplyFixture f; if(obstruction==0){f.recipient.position.y=3;}if(obstruction==1){f.physics.velocity.x=1;} if(obstruction==2){f.destination.selected=nullptr;}if(obstruction==3){f.source.allow=false;} if(obstruction==4){ERR_InfantryAmmoAccess::clear=false;} for(int tick=0;tick<3;tick++){f.c.Transfer(tick*1000);assert(f.source.calls==0&&f.c.m_Spent.IsEmpty()&&!f.c.m_Move&&!f.c.m_Receiving&&f.c.finishes==0);} f.recipient.position.y=0;f.physics.velocity.x=0;f.destination.selected=&f.targetStorage;f.source.allow=true;ERR_InfantryAmmoAccess::clear=true; f.c.Transfer(3000);assert(f.source.calls==1&&f.c.m_Spent.Count()==1&&f.c.m_Move&&f.c.m_Move->Submitted()); f.Move();f.source.last->OnComplete();f.c.Transfer(4000);assert(f.c.m_Delivered==1&&f.c.m_Served.Contains(&f.recipient)&&f.source.calls==1&&f.c.m_Spent.Count()==1); } // A capacity-blocked first member cannot prevent another original member from receiving this magazine. {SupplyFixture f;Fixture second;ERR_GameMode::current=&f.mode; second.recipient.group=&f.recipientGroup;second.recipientRecord.Group=&f.recipientGroup; f.c.m_Members.Insert(&second.recipient);f.destination.selected=nullptr; f.c.Transfer(0);assert(f.source.calls==1&&f.c.m_Receiving==&second.recipient&&f.c.m_Spent.Count()==1&&f.c.finishes==0); f.source.items.clear();second.destination.items={&f.magEntity};f.item.slot=&second.toSlot;f.source.last->OnComplete(); f.c.Transfer(1000);assert(f.c.m_Delivered==1&&f.c.m_Served.Contains(&second.recipient)&&!f.c.m_Served.Contains(&f.recipient));} // A native API may complete both physical movement and callback inline. Account once on the next slow tick. {SupplyFixture f;f.source.callback=1;f.source.effect=[&](){f.Move();};f.c.Transfer(0); assert(f.source.calls==1&&f.c.m_Move&&f.c.m_Move->Submitted()&&f.c.m_Delivered==0&&f.c.m_Spent.Count()==1); f.c.Transfer(1000);f.c.Transfer(2000);assert(f.c.m_Delivered==1&&f.c.m_Served.Count()==1&&f.source.calls==1&&f.c.finishes==0);} // Crossing the native submission boundary burns the exact identity even if native refusal is synchronous. for(int refusal=0;refusal<2;refusal++){SupplyFixture f;if(refusal==0){f.source.accept=false;}else{f.source.callback=2;} f.c.Transfer(0);assert(f.source.calls==1&&f.c.m_Spent.Count()==1&&f.c.m_Move->Submitted()); f.c.Transfer(1000);assert(f.c.finishes==1&&f.c.m_Spent.Count()==1&&f.source.calls==1); } // Accepted but unresolved loss stays retained/spent; changing geometry cannot cause a second native move. {SupplyFixture f;f.c.Transfer(0);f.recipient.position.x=8;f.c.Transfer(1000); assert(f.c.finishes==1&&f.c.m_Move&&f.c.m_Move->Unresolved()&&f.c.m_Spent.Count()==1&&f.source.calls==1);} // Several equivalent magazines do not multiply a blocked actor's expensive preflight work on one slow tick. {SupplyFixture f;Entity another=f.magEntity;f.source.items.Insert(&another);f.c.m_Stock.Insert(&another); ERR_InfantryAmmoAccess::clear=false;ERR_InfantryAmmoAccess::checks=0;f.c.Transfer(0); assert(ERR_InfantryAmmoAccess::checks==1&&f.source.calls==0&&f.c.m_Spent.IsEmpty());ERR_InfantryAmmoAccess::clear=true;} // A blocked native access check happens before submission and is terminal. {Fixture f;auto t=f.Job();ERR_InfantryAmmoAccess::clear=false;ERR_InfantryAmmoAccess::checks=0; assert(t.Tick(0)==FAILED&&!t.Submitted()&&!t.Unresolved()&&f.source.calls==0&&ERR_InfantryAmmoAccess::checks==1); ERR_InfantryAmmoAccess::clear=true;assert(t.Tick(1)==FAILED&&f.source.calls==0&&ERR_InfantryAmmoAccess::checks==1);} // Once native move is accepted, later geometry cannot cause a second operation or pretend cancellation. {Fixture f;auto t=f.Job();ERR_InfantryAmmoAccess::checks=0;assert(t.Tick(0)==PENDING&&ERR_InfantryAmmoAccess::checks==1); ERR_InfantryAmmoAccess::clear=false;assert(t.Tick(1)==PENDING&&t.Unresolved()&&f.source.calls==1&&ERR_InfantryAmmoAccess::checks==1); f.Move();f.source.last->OnComplete();assert(t.Tick(2)==SUCCEEDED);ERR_InfantryAmmoAccess::clear=true;} // Read-only selection follows the native inherited-well direction, excluding launcher muzzles and weapons. {Fixture f;assert(ERR_InfantryAmmoTransfer::Compatible(&f.recipient,&f.magEntity));Well derived;derived.type=2;derived.parent=1;f.magazine.well=&derived;assert(ERR_InfantryAmmoTransfer::Compatible(&f.recipient,&f.magEntity)); f.magazine.well=&f.well;f.muzzle.well=&derived;assert(!ERR_InfantryAmmoTransfer::Compatible(&f.recipient,&f.magEntity)); f.muzzle.well=&f.well;f.muzzle.kind=EMuzzleType::MT_UGLMuzzle;assert(!ERR_InfantryAmmoTransfer::Compatible(&f.recipient,&f.magEntity)); f.muzzle.kind=0;f.weapon.kind=EWeaponType::WT_ROCKETLAUNCHER;assert(!ERR_InfantryAmmoTransfer::Compatible(&f.recipient,&f.magEntity));} // Exactly one source move; neither a callback alone nor physical movement alone is a successful transaction. {Fixture f;auto t=f.Job();assert(t.Tick(100)==PENDING&&f.source.calls==1&&t.Unresolved());f.source.last->OnComplete();assert(t.Tick(101)==PENDING&&t.Unresolved()); f.Move();assert(t.Tick(102)==SUCCEEDED&&!t.Unresolved());t.Stop();assert(t.Tick(103)==SUCCEEDED&&f.source.calls==1);} {Fixture f;auto t=f.Job();t.Tick(100);f.Move();assert(t.Tick(101)==PENDING&&t.Unresolved());f.source.last->OnAllComplete();assert(t.Tick(102)==SUCCEEDED);} // Exact destination slot and known donor absence are mandatory even after success callback. {Fixture f;auto t=f.Job();t.Tick(100);f.Move();f.item.slot=&f.fromSlot;f.source.last->OnComplete();assert(t.Tick(101)==PENDING&&t.Unresolved()); f.item.slot=&f.toSlot;for(int i=0;i<513;i++)f.source.items.Insert(&f.foreign);assert(t.Tick(102)==PENDING&&t.Unresolved());} // Late callbacks resolve retained reservations after Stop without Tick or further operations; the stopped task stays failed. {Fixture f;auto t=f.Job();t.Tick(0);t.Stop();assert(t.Unresolved());f.Move();f.source.last->OnAllComplete();assert(!t.Unresolved());assert(t.Tick(2)==FAILED&&f.source.calls==1);} {Fixture f;auto t=f.Job();t.Tick(0);t.Stop();f.source.last->OnAllFailed();assert(!t.Unresolved());assert(t.Tick(1)==FAILED&&f.source.calls==1);} {Fixture f;auto t=f.Job();t.Tick(0);f.source.last->OnComplete();f.source.last->OnFailed();assert(t.Unresolved());f.Move();assert(!t.Unresolved()&&t.Tick(1)==SUCCEEDED);} // Failure/rejection and the 8s deadline never submit a second move. for(int failure=0;failure<3;failure++){Fixture f;if(failure==0)f.source.accept=false;if(failure==1)f.source.callback=2;auto t=f.Job();t.Tick(100); if(failure==2){assert(t.Tick(8100)==FAILED&&t.Unresolved());}else assert(t.Tick(101)==FAILED&&!t.Unresolved()); for(int i=0;i<10;i++)t.Tick(8200+i);assert(f.source.calls==1);} // Invalid physical state before submission spends no native action; the terminal object cannot revive. for(int invalid=0;invalid<25;invalid++){Fixture f;auto t=f.Job(); if(invalid==0)Replication::server=false;if(invalid==1)SCR_Global::editor=true;if(invalid==2)f.mode.active=false; if(invalid==3)f.truck.alive=false;if(invalid==4)f.recipient.alive=false;if(invalid==5)f.recipient.awake=false;if(invalid==6)f.recipient.player=true; if(invalid==7)f.recipient.vehicle=&f.truck;if(invalid==8)f.truck.captured=true;if(invalid==9)f.donorGroup.players=1; if(invalid==10)f.recipient.group=&f.otherGroup;if(invalid==11)f.donorRecord.Physical=false;if(invalid==12)f.recipientRecord.Eliminated=true; if(invalid==13)f.vehicleManager.vehicle=&f.foreign;if(invalid==14)f.driver.alive=false;if(invalid==15)f.driver.vehicle=nullptr; if(invalid==16)f.physics.velocity.x=.251f;if(invalid==17)f.physics.angular.x=.101f;if(invalid==18)f.recipient.position.x=4.001f; if(invalid==19)f.truck.faction=2;if(invalid==20)f.driver.faction=2;if(invalid==21)f.recipientGroup.slave=true; if(invalid==22)f.magazine.rounds=0;if(invalid==23)f.magazine.rounds=31;if(invalid==24)f.physics.velocity.x=std::numeric_limits::quiet_NaN(); assert(t.Tick(100)==FAILED&&f.source.calls==0&&!t.Unresolved());Replication::server=true;SCR_Global::editor=false;assert(t.Tick(200)==FAILED&&f.source.calls==0);} // Native stock/storage identity and capacity guards reject shared, foreign, oversized and inaccessible inventory. for(int invalid=0;invalid<9;invalid++){Fixture f;auto t=f.Job();if(invalid==0)f.source.items.clear();if(invalid==1)f.destination.items={&f.magEntity}; if(invalid==2)f.fromSlot.storage=&f.targetStorage;if(invalid==3)f.sourceStorage.owner=&f.foreign;if(invalid==4)f.destination.selected=nullptr; if(invalid==5)f.targetStorage.owner=&f.foreign;if(invalid==6)f.source.allow=false;if(invalid==7)f.destination.storages.clear();if(invalid==8){for(int i=0;i<65;i++)f.destination.storages.Insert(&f.targetStorage);} assert(t.Tick(0)==FAILED&&f.source.calls==0);} // Conditions and original native driver/ledger identities remain strict while an accepted move is pending. for(int changed=0;changed<4;changed++){Fixture f;auto t=f.Job();t.Tick(100);Record replacement=f.recipientRecord; if(changed==0)f.pilot.occupant=&f.spareDriver;if(changed==1)f.ledger.records[1]=&replacement;if(changed==2)f.physics.velocity.x=1;if(changed==3)f.recipient.position.x=8; assert(t.Tick(101)==FAILED&&t.Unresolved());f.source.last->OnFailed();assert(!t.Unresolved()&&f.source.calls==1);} {Fixture f;auto t=f.Job();t.Tick(100);assert(t.Tick(99)==FAILED&&t.Unresolved());} // Clothing storage ownership follows native inventory slots and bounds cycles. {Fixture f;Entity vest;Item vestItem;Slot vestSlot;Storage body;body.owner=&f.recipient;vestSlot.storage=&body;vestItem.slot=&vestSlot;vest.item=&vestItem;f.targetStorage.owner=&vest; auto t=f.Job();assert(t.Tick(0)==PENDING);f.Move();f.source.last->OnComplete();assert(t.Tick(1)==SUCCEEDED); vestSlot.storage=&f.targetStorage;assert(!ERR_InfantryAmmoTransfer::StoredUnder(&vest,&f.recipient));} } ''' # Brace tiny fixture statements to retain -Werror without suppressing useful compiler diagnostics. main=re.sub(r'if\((invalid|changed|failure)==(\d+)\)([^;{}]+);',r'if(\1==\2){\3;}',main) main=main.replace('for(int i=0;i<10;i++)t.Tick(8200+i);','for(int i=0;i<10;i++){t.Tick(8200+i);}') run(pre+translated_reservation()+code+'\n'.join(callbacks)+main) print('PASS: actual bounded empty-return and finite delivery; phase-isolated callbacks, exact ownership proof, stop quarantine and original actor/vehicle boundaries')