Complete roadblocks in background and fix session regressions

Continue safe roadblock placement after admission and prison unlock, build posts incrementally, and clean up incomplete transactions. Add bounded stuck-patrol dismount recovery, defer deployment initialization during terrain takeover, reset deferred site search timing on first player arrival, and fix atlas page serialization and terrain resource lookup.

Validation: 30 native Everon posts with 120 living guards after unlock; seven affected regression suites pass; two final restart smoke rounds complete with 21 assertions and no script/runtime failures. Existing dependency asset errors remain.
This commit is contained in:
2026-10-14 19:48:29 +02:00
parent 01994ed344
commit fda19a5200
18 changed files with 684 additions and 74 deletions
+62
View File
@@ -0,0 +1,62 @@
"""Execute native deployment init with delayed mode arrival and teardown."""
from policy_harness import ROOT, body, run
p = ROOT / 'addons/core/Scripts/Game/ERR/00_Core/ERR_TerrainControllerInit.c'
for kind in ('Deploy',):
protected = 'protected ' if kind == 'Deploy' else ''
init_signature = 'protected override void OnPostInit(' if kind == 'Deploy' else '\n override void OnPostInit('
code = '\n'.join(body(p, signature) for signature in (
init_signature, f'protected void ERR_Retry{kind}Init(', f'override {protected}void OnDelete('))
for before, after in (
('protected ', ''), ('override ', ''), ('IEntity owner', 'IEntity* owner'),
('owner.', 'owner->'), ('GetGame().', 'GetGame()->'), ('GetCallqueue().', 'GetCallqueue()->'),
('super.', 'Base::'), ('null', 'nullptr'), ('LogLevel.ERROR', '1'),
(f'CallLater(ERR_Retry{kind}Init,', 'CallLater(1,'),
(f'Remove(ERR_Retry{kind}Init)', 'Remove(1)'),
):
code = code.replace(before, after)
fields = f'''
IEntity* m_ERRDeferred{kind}Owner=nullptr;
World* m_ERRDeferred{kind}World=nullptr;
int m_ERR{kind}InitAttempts=0;
bool m_ERR{kind}InitComplete=false;
'''
run(r'''
#include <cassert>
struct World{};
struct IEntity{World* world;World* GetWorld(){return world;}};
struct Queue{int scheduled=0,removed=0;void CallLater(int,int delay,bool repeat){assert(delay==50&&!repeat);scheduled++;}void Remove(int){removed++;}};
struct Game{World* world=nullptr;bool pending=false,mode=false;Queue queue;
bool ERR_ClientTerrainModePending(){return pending;}bool GetGameMode(){return mode;}
World* GetWorld(){return world;}Queue* GetCallqueue(){return &queue;}} game;
Game* current=&game;Game* GetGame(){return current;}
void Print(const char*,int=0){}
struct Base{int initialized=0,deleted=0;void OnPostInit(IEntity*){initialized++;}void OnDelete(IEntity*){deleted++;}};
struct Component:Base{
''' + fields + code + r'''
};
int main(){
World first,next;IEntity owner{&first};game.world=&first;
// Ordinary startup still calls native initialization immediately, only once.
game.mode=true;Component ordinary;ordinary.OnPostInit(&owner);ordinary.OnPostInit(&owner);
assert(ordinary.initialized==1&&game.queue.scheduled==0);
game.pending=true;game.mode=false;Component delayed;
delayed.OnPostInit(&owner);delayed.OnPostInit(&owner);
assert(delayed.initialized==0&&game.queue.scheduled==1);
delayed.RETRY();assert(delayed.initialized==0&&game.queue.scheduled==2);
game.mode=true;game.pending=false;delayed.RETRY();delayed.RETRY();delayed.OnPostInit(&owner);
assert(delayed.initialized==1);
// Deletion cancels pending initialization; even a late callback is harmless.
game.pending=true;game.mode=false;Component deleted;deleted.OnPostInit(&owner);deleted.OnDelete(&owner);
game.mode=true;deleted.RETRY();assert(deleted.initialized==0&&deleted.deleted==1&&game.queue.removed==1);
// World replacement must not initialize a controller from the outgoing round.
game.mode=false;Component stale;stale.OnPostInit(&owner);game.world=&next;game.mode=true;stale.RETRY();
assert(stale.initialized==0);
game.world=&first;game.mode=false;Component timeout;int before=game.queue.scheduled;timeout.OnPostInit(&owner);
for(int i=0;i<250;i++)timeout.RETRY();
assert(timeout.initialized==0&&game.queue.scheduled-before==200);
game.mode=true;timeout.RETRY();assert(timeout.initialized==0);
}
'''.replace('RETRY', f'ERR_Retry{kind}Init'))
assert 'modded class SCR_RespawnComponent' not in p.read_text(), 'Native respawn RPC registration must stay immediate'
print('PASS: deployment init waits for mode, runs once, cancels on deletion/world change and bounds retries; respawn RPC registration stays immediate')