"""Execute production inventory manifest and client containment checks.""" from policy_harness import ROOT, body, run inventory=ROOT/'addons/core/Scripts/Game/ERR/00_Core/ERR_SpawnSceneInventory.c' scene=ROOT/'addons/core/Scripts/Game/ERR/00_Core/ERR_SpawnClientScene.c' def cpp(s): s=s.replace('protected ','').replace('static ','') s=s.replace('ERR_SpawnSceneInventory.InStorage(', 'InStorage(') s=s.replace('InventoryItemComponent item = InventoryItemComponent.Cast(entity.FindComponent(InventoryItemComponent));', 'Item* item = entity->item;') s=s.replace('InventoryStorageSlot slot = item.GetParentSlot();', 'Slot* slot = item->slot;') s=s.replace('BaseInventoryStorageComponent storage = slot.GetStorage();', 'Storage* storage = slot->storage;') s=s.replace('storage.FindItemSlot(entity)', 'storage->FindItemSlot(entity)').replace('storage.Get(slot.GetID())', 'storage->Get(slot->id)').replace('storage.GetAll(visible)', 'storage->GetAll(visible)') s=s.replace('out array ', 'Items& ').replace('array ', 'Items ') s=s.replace('foreach (IEntity root : roots)', 'for (IEntity root : roots)').replace('foreach (IEntity item : contents)', 'for (IEntity item : contents)') s=s.replace('InventoryStorageManagerComponent inventory = InventoryStorageManagerComponent.Cast(root.FindComponent(InventoryStorageManagerComponent));', 'Inventory* inventory = root->inventory;') s=s.replace('InventoryStorageManagerComponent inventory = InventoryStorageManagerComponent.Cast(owner.GetEntity().FindComponent(InventoryStorageManagerComponent));', 'Inventory* inventory = owner->GetEntity()->inventory;') s=s.replace('RplComponent owner = RplComponent.Cast(Replication.FindItem(ownerId));', 'RplComponent* owner = Replication::FindItem(ownerId);') s=s.replace('RplComponent item = RplComponent.Cast(Replication.FindItem(m_ERRClientStockItems[i]));', 'RplComponent* item = Replication::FindItem(m_ERRClientStockItems[i]);') s=s.replace('owner.GetEntity()', 'owner->GetEntity()').replace('item.GetEntity()', 'item->GetEntity()') s=s.replace('RplId.Invalid()', '-1').replace('ERR_Inventory.Items(', 'InventoryItems(') s=s.replace('Replication.IsServer()', 'Replication::server').replace('GetGame().GetWorld().GetWorldTime()', 'now') s=s.replace('ERR_SpawnSceneInventory.Gather(', 'Gather(').replace('ERR_SpawnSceneInventory.Same(', 'Same(') return s methods='\n'.join(cpp(body(inventory,key)) for key in ('static bool InStorage(', 'static bool Gather(', 'static bool Same(')) methods+='\n'+cpp(body(scene,'protected bool ERR_ClientStockReady(')) methods+='\n'+cpp(body(scene,'protected void ERR_RefreshSceneInventory(')) methods+='\n'+cpp(body(scene,'bool ERR_TakeScenePreload(')) run(r''' #include #include #include #include templatestruct List:std::vector{using std::vector::vector;using std::vector::operator=; int Count()const{return this->size();}void Insert(T x){this->push_back(x);}bool Contains(T x)const{return std::find(this->begin(),this->end(),x)!=this->end();} int Find(T x)const{auto i=std::find(this->begin(),this->end(),x);return i==this->end()?-1:i-this->begin();}}; struct Entity;using IEntity=Entity*;using Items=List;using RplId=int; struct Storage;struct Slot{Storage* storage=nullptr;int id=0;};struct Item{Slot* slot=nullptr;}; struct Inventory{Items items;};struct Entity{Inventory* inventory=nullptr;Item* item=nullptr;}; struct Storage{Items visible;IEntity stored=nullptr;Slot* slot=nullptr; Slot* FindItemSlot(IEntity e){return stored==e?slot:nullptr;}IEntity Get(int id){return slot&&slot->id==id?stored:nullptr;}void GetAll(Items& out){out=visible;}}; void InventoryItems(Inventory* inv,Items& items){items={};for(auto x:inv->items)if(x&&!items.Contains(x))items.Insert(x);} struct RplComponent{IEntity entity=nullptr;IEntity GetEntity(){return entity;}}; namespace Replication{bool server=true;std::map nodes;RplComponent* FindItem(int id){auto it=nodes.find(id);return it==nodes.end()?nullptr:it->second;}} templatevoid PrintFormat(const char*,T...){} struct Probe{ List m_ERRClientStockOwners,m_ERRClientStockItems; bool m_ERRScenePending=true,m_ERRSceneTimedOut=false,m_ERRSceneAcknowledged=false,m_ERRScenePreloadRequired=true,preloading=false; int publishes=0,waits=0,m_ERRSceneToken=7; float now=0,m_ERRSceneInventoryPoll=0,m_ERRSceneDeadline=60000,m_ERRSceneStartedAt=0; Items m_ERRSceneRoots,m_ERRSceneStockOwners,m_ERRSceneStockItems; void ERR_ReportStockWait(int,int,int){waits++;}int GetPlayerId(){return 1;} bool IsPreloading(){return preloading;}bool ERR_SpawnSceneReady(){return m_ERRSceneAcknowledged&&!m_ERRSceneTimedOut;} void ERR_PublishSpawnScene(Items owners,Items items,bool valid){publishes++;m_ERRSceneToken++;m_ERRSceneAcknowledged=false;m_ERRSceneStockOwners=owners;m_ERRSceneStockItems=items;m_ERRSceneTimedOut=!valid;} '''+methods+r''' }; int main(){ Inventory inv;Entity crate{&inv},gun,mag,map;inv.items={&gun,&mag,&map,&gun,nullptr}; Probe p;Items owners,items;assert(p.Gather({&crate,&crate,nullptr},owners,items)&&items.Count()==3); assert((items==Items{&gun,&mag,&map})&&(owners==Items{&crate,&crate,&crate})); assert(p.Same(owners,items,{&crate,&crate,&crate},{&map,&mag,&gun})); Entity other;assert(!p.Same(owners,items,{&other,&crate,&crate},items)); assert(!p.Same(owners,items,{&crate,&crate},{&gun,&mag})); std::vector many(257);Inventory full;for(auto& e:many)full.items.Insert(&e);Entity huge{&full}; assert(!p.Gather({&huge},owners,items)&&items.Count()==256&&owners.Count()==256); // Receiving every replication entity is insufficient: inventory links may // arrive later, and a wrong crate with the same item count is insufficient. RplComponent cr{&crate},gr{&gun},mr{&mag},pr{&map}; Replication::nodes={{10,&cr},{11,&gr},{12,&mr},{13,&pr}}; p.m_ERRClientStockOwners={10,10,10};p.m_ERRClientStockItems={11,12,13}; inv.items={};for(int i=0;i<20;i++)assert(!p.ERR_ClientStockReady()); inv.items={&gun,&mag};assert(!p.ERR_ClientStockReady()); inv.items={&gun,&mag,&other};assert(!p.ERR_ClientStockReady()); inv.items={&gun,&mag,&map};assert(!p.ERR_ClientStockReady()); Storage gs,ms,ps;Slot gslot{&gs,0},mslot{&ms,1},pslot{&ps,2};Item gi{&gslot},mi{&mslot},pi{&pslot}; gun.item=&gi;mag.item=&mi;map.item=π gs.stored=&gun;gs.slot=&gslot;gs.visible={&gun};ms.stored=&mag;ms.slot=&mslot;ms.visible={&mag};ps.stored=↦ps.slot=&pslot;ps.visible={&map}; assert(p.ERR_ClientStockReady()); // Manager still contains the gun, but the actual crate UI cannot read it. gs.visible={};assert(!p.ERR_ClientStockReady());gs.visible={&gun}; gs.stored=&other;assert(!p.ERR_ClientStockReady());gs.stored=&gun; gi.slot=nullptr;assert(!p.ERR_ClientStockReady());gi.slot=&gslot; gslot.storage=nullptr;assert(!p.ERR_ClientStockReady());gslot.storage=&gs; gs.slot=&mslot;assert(!p.ERR_ClientStockReady());gs.slot=&gslot; assert(p.ERR_ClientStockReady()); cr.entity=nullptr;assert(!p.ERR_ClientStockReady());cr.entity=&crate; crate.inventory=nullptr;assert(!p.ERR_ClientStockReady());crate.inventory=&inv; mr.entity=nullptr;assert(!p.ERR_ClientStockReady());mr.entity=&mag; p.m_ERRClientStockOwners={10};assert(!p.ERR_ClientStockReady()); // Refresh a consumed/relocated stock snapshot without extending its timeout. p.m_ERRSceneRoots={&crate};assert(p.Gather(p.m_ERRSceneRoots,p.m_ERRSceneStockOwners,p.m_ERRSceneStockItems)); p.ERR_RefreshSceneInventory();assert(p.publishes==0); p.m_ERRSceneAcknowledged=true;inv.items={&gun};p.now=499;p.ERR_RefreshSceneInventory();assert(p.publishes==0); p.now=500;p.ERR_RefreshSceneInventory();assert(p.publishes==1&&p.m_ERRSceneToken==8&&!p.m_ERRSceneAcknowledged&&p.m_ERRSceneDeadline==60000); assert((p.m_ERRSceneStockItems==Items{&gun})); p.m_ERRSceneStockItems={&gun,&mag};p.now=1000;Replication::server=false;p.ERR_RefreshSceneInventory();assert(p.publishes==1);Replication::server=true; p.m_ERRSceneTimedOut=true;p.ERR_RefreshSceneInventory();assert(p.publishes==1);p.m_ERRSceneTimedOut=false; p.m_ERRScenePending=false;p.ERR_RefreshSceneInventory();assert(p.publishes==1); // Preload cannot start before inventory acknowledgement, starts once, and // waits for an earlier native pass before consuming a refreshed request. assert(!p.ERR_TakeScenePreload());p.m_ERRSceneAcknowledged=true; assert(p.ERR_TakeScenePreload()&&!p.ERR_TakeScenePreload()); p.m_ERRScenePreloadRequired=true;p.preloading=true;assert(!p.ERR_TakeScenePreload()); p.preloading=false;assert(p.ERR_TakeScenePreload()); } ''') print('PASS: actual inventory manifest, delayed/missing/wrong-owner item links, finite cap, consumed-stock refresh and preload ordering')