"""Run production readiness/ack/timeout bodies with delayed replication adapters.""" from policy_harness import ROOT, body, run source = ROOT/'addons/core/Scripts/Game/ERR/00_Core/ERR_SpawnClientScene.c' keys = ('bool ERR_SpawnSceneReady(', 'bool ERR_SpawnSceneMayFinish(', 'protected void ERR_AcknowledgeSpawnScene(', 'protected void ERR_ClearClientSpawnScene(', 'protected void ERR_CheckClientSpawnScene(', 'protected void ERR_CancelClientSpawnScene(') methods = '\n'.join(body(source, key) for key in keys) methods = methods.replace('protected ', '').replace('Replication.IsServer()', 'Replication::IsServer()') methods = methods.replace('ERR_GameMode.Get()', 'Mode::Get()') methods = methods.replace('RplComponent component = RplComponent.Cast(Replication.FindItem(id));', 'RplComponent* component = Replication::FindItem(id);') methods = methods.replace('component.GetEntity()', 'component->GetEntity()') methods = methods.replace('foreach (RplId id :', 'for (RplId id :') methods = methods.replace('GetGame().GetWorld().GetWorldTime()', 'game.now') methods = methods.replace('GetGame().GetCallqueue().Remove(ERR_CheckClientSpawnScene)', 'game.removes++') methods = methods.replace('Rpc(ERR_AcknowledgeSpawnScene, token)', 'SendAck(token)') run(r''' #include #include #include using RplId=int; struct RplComponent{bool entity=true;bool GetEntity(){return entity;}}; namespace Replication{bool server=true;std::map items;bool IsServer(){return server;}RplComponent* FindItem(int id){return items.count(id)?items[id]:nullptr;}} struct Mode{static bool present;static bool Get(){return present;}};bool Mode::present=true; struct Game{float now=0;int removes=0;}game;Game* GetGame(){return &game;} struct Nodes:std::vector{using std::vector::operator=;void Clear(){clear();}int Count(){return size();}}; templatevoid PrintFormat(const char*,T...){} struct Probe{ int m_ERRSceneToken=4,m_ERRClientSceneToken=4,acks=0,lastAck=0; bool m_ERRScenePending=false,m_ERRSceneAcknowledged=false,m_ERRSceneTimedOut=false,m_ERRClientScenePending=false; float m_ERRSceneDeadline=1000,m_ERRSceneStartedAt=0;Nodes m_ERRClientSceneNodes,m_ERRClientStockOwners,m_ERRClientStockItems; bool stockReady=true;bool ERR_ClientStockReady(){return stockReady;}void ERR_RefreshSceneInventory(){} int GetPlayerId(){return 1;}void SendAck(int token){acks++;lastAck=token;} '''+methods+r''' }; int main(){ Probe server;assert(!server.ERR_SpawnSceneReady()); server.ERR_AcknowledgeSpawnScene(4);assert(!server.m_ERRSceneAcknowledged); server.m_ERRScenePending=true;assert(!server.ERR_SpawnSceneMayFinish()); server.ERR_AcknowledgeSpawnScene(3);assert(!server.ERR_SpawnSceneReady()); Replication::server=false;server.ERR_AcknowledgeSpawnScene(4);assert(!server.ERR_SpawnSceneReady());Replication::server=true; server.ERR_AcknowledgeSpawnScene(4);assert(server.ERR_SpawnSceneReady()&&server.ERR_SpawnSceneMayFinish()); server.m_ERRSceneAcknowledged=false;game.now=999;assert(!server.ERR_SpawnSceneMayFinish()); game.now=1000;assert(server.ERR_SpawnSceneMayFinish()&&server.m_ERRSceneTimedOut&&!server.ERR_SpawnSceneReady()); server.ERR_AcknowledgeSpawnScene(4);assert(!server.ERR_SpawnSceneReady()); Probe client;client.m_ERRClientScenePending=true;client.m_ERRClientSceneNodes={11,22,33}; RplComponent root,wall,gate;Replication::items[11]=&root; for(int i=0;i<100;i++){client.ERR_CheckClientSpawnScene();}assert(client.acks==0&&client.m_ERRClientScenePending); Replication::items[22]=&wall;client.ERR_CheckClientSpawnScene();assert(client.acks==0); gate.entity=false;Replication::items[33]=&gate;client.ERR_CheckClientSpawnScene();assert(client.acks==0); gate.entity=true;client.stockReady=false;client.ERR_CheckClientSpawnScene();assert(client.acks==0&&client.m_ERRClientScenePending); client.stockReady=true;client.ERR_CheckClientSpawnScene();assert(client.acks==1&&client.lastAck==4&&!client.m_ERRClientScenePending&&client.m_ERRClientSceneNodes.empty()); client.ERR_CheckClientSpawnScene();assert(client.acks==1); client.m_ERRClientScenePending=true;client.m_ERRClientSceneToken=5;client.m_ERRClientSceneNodes={99}; client.ERR_CancelClientSpawnScene(4);assert(client.m_ERRClientScenePending); client.ERR_CancelClientSpawnScene(5);assert(!client.m_ERRClientScenePending&&client.m_ERRClientSceneNodes.empty()); client.m_ERRClientScenePending=true;Mode::present=false;client.ERR_CheckClientSpawnScene();assert(!client.m_ERRClientScenePending&&client.acks==1); } ''') finalizer = ROOT/'addons/core/Scripts/Game/ERR/00_Core/ERR_SpawnFinalization.c' methods = '\n'.join(body(finalizer, key) for key in ('override bool CanFinalize_S(', 'override SCR_ESpawnResult FinalizeRequest_S(')) for old, new in [('override ', ''), ('SCR_SpawnRequestComponent requestComponent', 'Request* requestComponent'), ('SCR_SpawnData data', 'Data* data'), ('IEntity entity', 'Actor* entity'), ('ERR_SpawnLogic logic', 'Logic* logic'), ('ERR_SpawnTicket ticket', 'Ticket* ticket'), ('ERR_GameMode.Get()', 'Mode::Get()'), ('SCR_ESpawnResult.', 'SCR_ESpawnResult::'), ('requestComponent.', 'requestComponent->'), ('logic.', 'logic->'), ('super.', 'Native::')]: methods = methods.replace(old, new) run(r''' #include enum class SCR_ESpawnResult{OK,SPAWN_NOT_ALLOWED,CANNOT_ASSIGN}; struct Request{bool ready=false,mayFinish=false;int ends=0;bool ERR_SpawnSceneReady(){return ready;}bool ERR_SpawnSceneMayFinish(){return mayFinish;}bool preloadRequired=true;bool ERR_TakeScenePreload(){if(!ready||!preloadRequired)return false;preloadRequired=false;return true;}void ERR_EndSpawnScene(){ends++;}}; struct Data{};struct Actor{};struct Ticket{}; struct Mode{static bool current;static bool Get(){return current;}};bool Mode::current=true; struct Logic{Ticket ticket;bool hasTicket=true,allowed=true;Ticket* TakeSpawnTicket(Request*,Data*,Actor*){return hasTicket?&ticket:nullptr;}bool MayFinalizeSpawn(Ticket*){return allowed;}}; struct Native{bool preloadReady=false;int assignments=0,preloadStarts=0;void OnFinalizeBegin_S(Request*,Data*,Actor*){preloadStarts++;preloadReady=false;}SCR_ESpawnResult result=SCR_ESpawnResult::OK;bool CanFinalize_S(Request*,Data*,Actor*){return preloadReady;}SCR_ESpawnResult FinalizeRequest_S(Request*,Data*,Actor*){assignments++;return result;}}; struct Handler:Native{Logic storage;Logic* logic=&storage;int rejects=0;Logic* ERR_AdmissionLogic(){return logic;}void ERR_RejectOwnedActor(Request*,Actor*,Data*){rejects++;} '''+methods+r''' }; int main(){ Request request;Data data;Actor actor;Handler h; h.preloadReady=true;assert(!h.CanFinalize_S(&request,&data,&actor)); request.mayFinish=true;h.preloadReady=false;assert(!h.CanFinalize_S(&request,&data,&actor)); h.preloadReady=true;assert(h.CanFinalize_S(&request,&data,&actor)); // Timeout can end the pending request, but cannot assign an actor. assert(h.FinalizeRequest_S(&request,&data,&actor)==SCR_ESpawnResult::SPAWN_NOT_ALLOWED&&h.assignments==0&&h.rejects==1&&request.ends==1); request.ready=true;assert(!h.CanFinalize_S(&request,&data,&actor)&&h.preloadStarts==1); h.preloadReady=true;assert(h.CanFinalize_S(&request,&data,&actor)&&h.preloadStarts==1); h.storage.allowed=false; assert(h.FinalizeRequest_S(&request,&data,&actor)==SCR_ESpawnResult::SPAWN_NOT_ALLOWED&&h.assignments==0&&h.rejects==2); h.storage.allowed=true;assert(h.FinalizeRequest_S(&request,&data,&actor)==SCR_ESpawnResult::OK&&h.assignments==1&&request.ends==3); h.storage.hasTicket=false;assert(h.FinalizeRequest_S(&request,&data,&actor)==SCR_ESpawnResult::SPAWN_NOT_ALLOWED&&h.assignments==1&&h.rejects==2); Mode::current=false;h.logic=nullptr;assert(h.FinalizeRequest_S(&request,&data,&actor)==SCR_ESpawnResult::OK&&h.assignments==2); } ''') cleanup = body(source, 'void ERR_EndSpawnScene(') for old, new in [('Replication.IsServer()', 'Replication::server'), ('foreach (IEntity entity :', 'for (int entity :'), ('GetPlayerController().GetControlledEntity()', 'GetPlayerController()->GetControlledEntity()'), ('Rpc(ERR_CancelClientSpawnScene, m_ERRSceneToken)', 'Cancel(m_ERRSceneToken)')]: cleanup = cleanup.replace(old, new) run(r''' #include #include namespace Replication{bool server=true;} struct Items:std::vector{using std::vector::vector;void Clear(){clear();}}; struct Controller{int GetControlledEntity(){return 42;}}; struct Probe{ Items m_ERRSceneEntities{1,2},m_ERRSceneRoots,m_ERRSceneStockOwners,m_ERRSceneStockItems; bool m_ERRSceneObserver=true,m_ERRScenePending=true,m_ERRSceneAcknowledged=true,m_ERRSceneTimedOut=true,m_ERRScenePreloadRequired=true; int m_ERRSceneToken=7,restored=0,cancelled=0,observed=0;Controller controller;bool connected=true; Controller* GetPlayerController(){return connected?&controller:nullptr;} void ERR_StreamScene(int,bool normal){assert(normal);restored++;} void UpdateObserverMP_S(int entity){observed=entity;}void Cancel(int token){assert(token==7);cancelled++;} '''+cleanup+r''' }; int main(){ Probe p;Replication::server=false;p.ERR_EndSpawnScene();assert(p.restored==0&&p.m_ERRScenePending); Replication::server=true;p.ERR_EndSpawnScene();assert(p.restored==2&&p.cancelled==1&&p.observed==42); assert(p.m_ERRSceneEntities.empty()&&!p.m_ERRSceneObserver&&!p.m_ERRScenePending&&!p.m_ERRSceneAcknowledged&&!p.m_ERRSceneTimedOut&&!p.m_ERRScenePreloadRequired); p.ERR_EndSpawnScene();assert(p.restored==2&&p.cancelled==1); Probe disconnected;disconnected.connected=false;disconnected.ERR_EndSpawnScene();assert(disconnected.observed==0&&!disconnected.m_ERRSceneObserver); } ''') print('PASS: delayed scene/inventory arrival, deferred preload, identity checks, stale replies, timeout and observer cleanup')