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:
@@ -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')
|
||||
Reference in New Issue
Block a user