"""Execute production item-station lifecycle with modeled native subscriptions.""" from policy_harness import ROOT, body, run p=ROOT/'addons/core/Scripts/Game/ERR/00_Core/ERR_ItemStationLifecycle.c' code='\n'.join(body(p,x) for x in ['override void OnPostInit(', 'protected override void DelayedInit(', 'protected override void AddRemoveOnDamageStateChanged(', 'override void OnDelete(']) code=code.replace('protected ','').replace('override ','').replace('IEntity owner','IEntity* owner') for name in ['owner','m_ERRItemStationManager','m_ERRItemStationResource']: code=code.replace(name+'.',name+'->') for name in ['SCR_Global','ERR_GameMode','ERR_TerrainTakeoverSettings','SCR_EntityCatalogManagerComponent','SCR_SupportStationManagerComponent']: code=code.replace(name+'.',name+'::') code=code.replace('GetGame().','GetGame()->').replace('Remove(DelayedInit)','Remove(0)').replace('Remove(TEMP_OnInteractorReplicated)','Remove(1)') for method in ['OnPostInit','DelayedInit','OnDelete','AddRemoveOnDamageStateChanged']: code=code.replace('super.'+method,'Native'+method) run(r''' #include #define null nullptr namespace SCR_Global{bool editing=false;bool IsEditMode(){return editing;}} namespace ERR_GameMode{bool present=true;bool Get(){return present;}} namespace ERR_TerrainTakeoverSettings{bool enabled=true;bool Enabled(){return enabled;}} namespace SCR_EntityCatalogManagerComponent{bool present=true;bool GetInstance(){return present;}} struct Queue{int cancelled=0;void Remove(int){cancelled++;}}; struct Game{int world=1;Queue queue;int GetWorld(){return world;}Queue& GetCallqueue(){return queue;}}game; Game* gamePtr=&game;Game* GetGame(){return gamePtr;} struct Event{int subscribed=0,removed=0;void Remove(int){subscribed=0;removed++;}}; struct Resource{Event event;Event& TEMP_GetOnInteractorReplicated(){return event;}}; struct Manager{int removed=0;void RemoveSupportStation(void*){removed++;}}oldManager,newManager; namespace SCR_SupportStationManagerComponent{Manager* current=&oldManager;Manager* GetInstance(){return current;}} struct IEntity{int world=1;int GetWorld(){return world;}}; struct Station{ bool m_ERRItemStationScoped=false,m_ERRItemStationInitializing=false,m_ERRItemStationInitialized=false,m_ERRItemStationDeleted=false; Resource* m_ERRItemStationResource=nullptr;Manager* m_ERRItemStationManager=nullptr; bool m_ResourceConsumer=false,m_ResourceGenerator=false,range=false,invalid=false; Resource resource;int initCalls=0,errors=0,deleteCalls=0,damageAdded=0,damageRemoved=0; Resource* GetResourceComponent(){return &resource;}bool UsesRange(){return range;} void NativeOnPostInit(IEntity*){} void NativeDelayedInit(IEntity* owner){initCalls++;if(!SCR_EntityCatalogManagerComponent::present||invalid){errors++;return;}m_ResourceConsumer=true;resource.event.subscribed++;AddRemoveOnDamageStateChanged(owner,true);} void NativeOnDelete(IEntity*){deleteCalls++;} void NativeAddRemoveOnDamageStateChanged(IEntity*,bool subscribe){if(subscribe)damageAdded++;else damageRemoved++;} '''+code+r''' }; int main(){ IEntity main,preview{2}; // Live initialization validates normally and records both subscriptions. Station live;live.range=true;live.OnPostInit(&main);live.DelayedInit(&main); assert(live.m_ERRItemStationInitialized&&live.damageAdded==1&&live.resource.event.subscribed==1); // Destroy the catalog and replace the global manager before cleanup. SCR_EntityCatalogManagerComponent::present=false;SCR_SupportStationManagerComponent::current=&newManager; live.OnDelete(&main);live.OnDelete(&main);assert(!live.deleteCalls&&live.damageRemoved==1&&live.resource.event.removed==1); assert(oldManager.removed==1&&newManager.removed==0&&!live.m_ERRItemStationResource&&!live.m_ERRItemStationManager); live.DelayedInit(&main);assert(live.initCalls==1); // Late queued init cannot resurrect subscriptions. // Delete before the scheduled initialization: no subscription and no startup revalidation. Station unborn;unborn.OnPostInit(&main);unborn.OnDelete(&main);unborn.DelayedInit(&main); assert(unborn.initCalls==0&&unborn.damageRemoved==0&&unborn.errors==0); // A catalog-less preload object is not a live station and requires no validation. Station preload;preload.OnPostInit(&preview);preload.DelayedInit(&preview);preload.OnDelete(&preview); assert(!preload.initCalls&&!preload.errors&&!preload.damageRemoved); // Missing catalogs in the MAIN world remain a real validation error. Station broken;broken.OnPostInit(&main);broken.DelayedInit(&main);assert(broken.errors==1&&!broken.m_ERRItemStationInitialized); broken.OnDelete(&main);assert(!broken.damageRemoved); // Non-range stations also detach the resource event, which native teardown skipped. SCR_EntityCatalogManagerComponent::present=true;Station portable;portable.OnPostInit(&main);portable.DelayedInit(&main);portable.OnDelete(&main); assert(portable.resource.event.removed==1&&newManager.removed==0); Station badType;badType.invalid=true;badType.OnPostInit(&main);badType.DelayedInit(&main);badType.OnDelete(&main);assert(badType.errors==1&&!badType.damageRemoved); // Opted-out unrelated modes and editor mode keep their original lifecycle. ERR_GameMode::present=false;ERR_TerrainTakeoverSettings::enabled=false; Station unrelated;unrelated.OnPostInit(&main);unrelated.OnDelete(&main);assert(unrelated.deleteCalls==1); ERR_TerrainTakeoverSettings::enabled=true;SCR_Global::editing=true; Station editing;editing.OnPostInit(&preview);editing.OnDelete(&preview);assert(editing.deleteCalls==1); } ''') print('PASS: catalog-independent cleanup removes original subscriptions once, handles never-initialized/preload items, preserves live validation and opted-out/editor behavior')