Merge owned systems into one addon while preserving resource identities. Gate player admission on the replicated prison scene, restore the original framed door, and hold enemy AI until escape. Correct scenario branding and author metadata, include publishing assets, and retain regression and native verification evidence.
75 lines
5.4 KiB
Python
75 lines
5.4 KiB
Python
"""Execute actual gate method and document pre-inventory guard; no native/MP claim."""
|
|
from policy_harness import ROOT, body, run
|
|
unlock = body(ROOT/'addons/core/Scripts/Game/ERR/00_Core/ERR_GameMode.c', 'bool UnlockPrison(')
|
|
recover = body(ROOT/'addons/core/Scripts/Game/ERR/00_Core/ERR_DiscoveryService.c', 'protected void Recover(')
|
|
# Run precisely the production admission prefix. Inventory is the observable
|
|
# boundary: rejected bodies must never inspect or spend their carried documents.
|
|
assert recover.count('InventoryStorageManagerComponent inventory') == 1
|
|
prefix = recover[:recover.index('InventoryStorageManagerComponent inventory')]
|
|
prefix = prefix.replace('protected void Recover(', 'void Recover(') + 'inventoryReads++;\n}'
|
|
def cpp(s):
|
|
for namespace in ('Replication','ERR_Actors','SCR_FactionManager','vector','ERR_Phase'):
|
|
s=s.replace(namespace+'.', namespace+'::')
|
|
for var in ('m_Mode','m_Roster','player'):
|
|
s=s.replace(var+'.',var+'->')
|
|
return s.replace('Players().','Players()->')
|
|
run('''#include <cassert>
|
|
struct Point {float x;};
|
|
struct Faction {};
|
|
struct Actor {bool alive=true;bool conscious=true;Faction* faction=nullptr;Point origin{0};Point GetOrigin(){return origin;}};
|
|
using IEntity=Actor*;
|
|
namespace Replication {bool server=true;bool IsServer(){return server;}}
|
|
namespace ERR_Actors {bool Alive(IEntity p){return p&&p->alive;}bool CanFight(IEntity p){return Alive(p)&&p->conscious;}}
|
|
namespace SCR_FactionManager {Faction* SGetFaction(IEntity p){return p?p->faction:nullptr;}}
|
|
namespace vector {float DistanceXZ(Point a,Point b){return a.x>b.x?a.x-b.x:b.x-a.x;}}
|
|
namespace ERR_Phase {constexpr int PRISON=1,RADIO_SEARCH=2;}
|
|
struct Roster {IEntity actor=nullptr;bool connected=true,used=true,sameAccount=true; bool CurrentActor(IEntity p){return p&&p==actor&&connected&&used&&sameAccount;}};
|
|
struct Mode {
|
|
Roster* m_Roster=nullptr;Faction* faction=nullptr;int m_Phase=1, transitions=0;
|
|
Roster* Players(){return m_Roster;}Faction* PlayerFaction(){return faction;}
|
|
Point PrisonPosition(){return {0};}bool Transition(int phase){m_Phase=phase;transitions++;return true;}
|
|
'''+cpp(unlock)+'''
|
|
};
|
|
struct Discovery {Mode* m_Mode=nullptr;int inventoryReads=0;
|
|
'''+cpp(prefix)+'''
|
|
};
|
|
int main(){
|
|
Faction friendly,foreign;Actor prisoner,other;prisoner.faction=&friendly;other.faction=&friendly;
|
|
Roster roster;roster.actor=&prisoner;Mode mode;mode.m_Roster=&roster;mode.faction=&friendly;
|
|
Discovery discovery;discovery.m_Mode=&mode;
|
|
auto denyBoth=[&](Actor* p){mode.m_Phase=1;int before=discovery.inventoryReads, prior=mode.transitions;assert(!mode.UnlockPrison(p));discovery.Recover(p);assert(discovery.inventoryReads==before&&mode.transitions==prior);};
|
|
denyBoth(nullptr);denyBoth(&other); // player-controlled replacement is not the round body
|
|
roster.connected=false;denyBoth(&prisoner);roster.connected=true;
|
|
roster.used=false;denyBoth(&prisoner);roster.used=true;
|
|
roster.sameAccount=false;denyBoth(&prisoner);roster.sameAccount=true;
|
|
prisoner.faction=&foreign;denyBoth(&prisoner);prisoner.faction=&friendly;
|
|
mode.faction=nullptr;denyBoth(&prisoner);mode.faction=&friendly;
|
|
mode.m_Roster=nullptr;denyBoth(&prisoner);mode.m_Roster=&roster;
|
|
prisoner.alive=false;denyBoth(&prisoner);prisoner.alive=true;
|
|
Replication::server=false;denyBoth(&prisoner);Replication::server=true;
|
|
// Restoring the canonical reconnect relation requires no replacement life.
|
|
mode.m_Phase=1;assert(mode.UnlockPrison(&prisoner));discovery.Recover(&prisoner);assert(discovery.inventoryReads==1);
|
|
// Canonical living unconscious inventory still reveals documents, but no lock picking.
|
|
mode.m_Phase=1;prisoner.conscious=false;assert(!mode.UnlockPrison(&prisoner));discovery.Recover(&prisoner);assert(discovery.inventoryReads==2);prisoner.conscious=true;
|
|
prisoner.origin.x=15.01;assert(!mode.UnlockPrison(&prisoner));prisoner.origin.x=15;assert(mode.UnlockPrison(&prisoner));assert(!mode.UnlockPrison(&prisoner));
|
|
discovery.m_Mode=nullptr;discovery.Recover(&prisoner);assert(discovery.inventoryReads==2);
|
|
}
|
|
''')
|
|
print('PASS: actual gate and pre-inventory document guards reject noncanonical/faction/life/disconnect/server mismatches; canonical reconnect and unconscious carried intel preserved')
|
|
|
|
# Native probe safety contracts: actual engine behavior remains for the central run.
|
|
probe=(ROOT/'addons/core/Scripts/Game/ERR/00_Core/ERR_NativeProgressionIdentityProbe.c').read_text()
|
|
assert probe.startswith('#ifdef WORKBENCH') and probe.rstrip().endswith('#endif')
|
|
assert probe.count('life.Actor = null;') == 2
|
|
for segment in probe.split('life.Actor = null;')[1:]:
|
|
assert 'life.Actor = savedActor;' in segment
|
|
injection=segment[:segment.index('life.Actor = savedActor;')]
|
|
for forbidden in ('Check(', 'return', 'CallLater', 'Bind(', 'Disconnect(', 'SetControlledEntity', 'SetAffiliatedFaction', 'AccountId ='):
|
|
assert forbidden not in injection, forbidden
|
|
assert 'super.Recover(player);' in probe.split('life.Actor = null;')[2].split('life.Actor = savedActor;')[0]
|
|
assert 'm_Spent.Contains(folder)' in probe and 'location.Knowledge() < 2' in probe
|
|
assert 'GetParentSlot().GetStorage().Contains(folder)' in probe
|
|
assert probe.index('if (!candidate)') < probe.index('ERR_NativeProgressionIdentityProbe.AttemptDocument();')
|
|
assert 'm_Spent.Contains(candidate) && m_Spent.Count() > spent && target.Knowledge() > previousKnowledge' in probe
|
|
print('PASS: WB-only native fault injection restores both body mutations before checks/returns and requires eligible held-document negative/positive proof; runtime pending')
|