Add typed field-flight prototype and preserve native qualification failures

This commit is contained in:
2026-09-19 21:01:20 +02:00
parent 83ea247e62
commit 61e165ef5b
91 changed files with 40570 additions and 85 deletions
+19 -4
View File
@@ -3,7 +3,7 @@ import re
from policy_harness import ROOT, body, run
P=ROOT/'addons/core/Scripts/Game/ERR/ERR_OrdinaryGateObserver.c'
def cpp(s):
s=s.replace('protected ', '').replace('out float ', 'float& ').replace('out bool ', 'bool& ')
s=s.replace('protected ', '').replace('out bool held', 'bool& held').replace('out float ', 'float& ').replace('out bool ', 'bool& ')
types=('ERR_GameMode','BaseWorld','PlayerController','IEntity','ERR_PlayerLife','PlayerManager','BaseUserAction','ERR_UnlockPrisonAction','UserActionContext')
for typ in types:s=re.sub(r'\b'+typ+r' (\w+)',typ+r'* \1',s)
s=s.replace('array<BaseUserAction>', 'Array<BaseUserAction*>').replace('array<bool>', 'Array<bool>')
@@ -19,8 +19,10 @@ def cpp(s):
s=s.replace(scope+'.',scope+'::')
for getter in ('GetGame','Players','PrisonEscape','GetInputManager','GetMenuManager'):
s=s.replace(getter+'().',getter+'()->')
s=s.replace('nonce.Length()', 'int(nonce.size())').replace('allowed.Contains(nonce[i])', '(allowed.find(nonce[i]) != string::npos)')
return s.replace('null','nullptr').replace('string.Format(', 'Format(')
accessor=cpp(body(P,'bool ERR_GateReadProgress('))
shared='\n'.join(cpp(body(ROOT/'addons/core/Scripts/Game/ERR/ERR_OrdinaryInputObserver.c', signature)) for signature in ('static bool Nonce(', 'static bool HeldScope(', 'static bool PhaseAllowed('))
methods='\n'.join(cpp(body(P,s)) for s in ('protected static bool Enabled(', 'static void Sample(', 'protected bool BindGate(', 'protected bool Context(', 'protected void Cancel(', 'protected bool CachedPermission(', 'protected static bool FiniteVector(', 'protected static string ChoiceIdentity(', 'protected void ObserveChoices(', 'protected void Observe('))
run(r'''
#include <cassert>
@@ -51,7 +53,7 @@ struct PlayerManager {PlayerController* controller=nullptr;IEntity* actor=nullpt
struct ERR_PlayerLife {UUID AccountId="original-account";};
struct Roster {ERR_PlayerLife* life=nullptr;IEntity* actor=nullptr;ERR_PlayerLife* CurrentActor(IEntity* value){return value==actor?life:nullptr;}};
struct Prison {IEntity* gate=nullptr;bool registered=true,lost=false;bool Registered(){return registered;}bool GateLost(){return lost;}IEntity* Gate(){return gate;}};
namespace ERR_Phase {enum {PRISON,RADIO_SEARCH,EXTRACTION};}
namespace ERR_Phase {enum {PRISON=1,RADIO_SEARCH=2,EXTRACTION=4};}
struct ERR_GameMode {static ERR_GameMode* current;bool active=true;int phase=ERR_Phase::PRISON;BaseWorld* world=nullptr;Roster* roster=nullptr;Prison* prison=nullptr;static ERR_GameMode* Get(){return current;}bool Active(){return active;}int Phase(){return phase;}BaseWorld* GetWorld(){return world;}Roster* Players(){return roster;}Prison* PrisonEscape(){return prison;}vector prisonPosition=Vector(6090,210,7160);vector PrisonPosition(){return prisonPosition;}};ERR_GameMode* ERR_GameMode::current=nullptr;
struct InputManager {float pressed=0;ERR_GameMode* changeDuringRead=nullptr;float GetActionValue(string name){assert(name=="PerformAction");if(changeDuringRead)changeDuringRead->active=false;return pressed;}};
struct MenuManager {bool open=false;void* GetTopMenu(){return open?this:nullptr;}};
@@ -59,7 +61,9 @@ struct Game {BaseWorld* world=nullptr;PlayerController* controller=nullptr;Playe
namespace System {bool console=false;std::map<string,string> cli;bool IsConsoleApp(){return console;}bool GetCLIParam(string key,string& value){if(!cli.count(key))return false;value=cli[key];return true;}}
namespace Replication {bool server=true;bool IsServer(){return server;}}
namespace RplMode {enum {None,Listen,Dedicated};}namespace RplSession {int mode=RplMode::None;int Mode(){return mode;}}
namespace ERR_OrdinaryInputObserverRules {bool Nonce(string n){return !n.empty()&&n.size()<=32&&n.find_first_not_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")==string::npos;}}
struct ERR_OrdinaryInputObserverRules {
'''+shared+r'''
};
namespace ERR_Actors {bool CanFight(IEntity* actor){return actor&&actor->living;}}
namespace CompartmentAccessComponent {IEntity* GetVehicleIn(IEntity* actor){return actor->vehicle?actor:nullptr;}}
int headers=0,samples=0,geometries=0,cancels=0,choices=0;string lastChoice;string reason;bool lastSelected=false,lastContext=false,lastPermitted=false,lastBound=false,lastPerforming=false;float lastProgress=0;int lastPhase=0;
@@ -74,7 +78,7 @@ void PrintFormat(string format,string,int,int,string value){if(format.find("ERR
class ERR_OrdinaryGateObserver {public:
static ERR_OrdinaryGateObserver* s_Request;static bool s_Attempted;
ERR_GameMode* m_Mode=nullptr;BaseWorld* m_World=nullptr;PlayerController* m_Controller=nullptr;IEntity* m_Actor=nullptr;ERR_PlayerLife* m_Life=nullptr;UUID m_Account;IEntity* m_Gate=nullptr;BaseActionsManagerComponent* m_Manager=nullptr;ERR_UnlockPrisonAction* m_Lock=nullptr;UserActionContext* m_Context=nullptr;BaseDoorComponent* m_Door=nullptr;SCR_InteractionHandlerComponent* m_Handler=nullptr;
string m_Nonce;int m_Start=0,m_Previous=0,m_Index=0;bool m_Stopped=false;
string m_Nonce;int m_Start=0,m_Previous=0,m_Index=0;bool m_Stopped=false,m_HeldAction=false;int m_ObservedPhase=-1;
'''+methods+r'''
};
ERR_OrdinaryGateObserver* ERR_OrdinaryGateObserver::s_Request=nullptr;bool ERR_OrdinaryGateObserver::s_Attempted=false;
@@ -84,6 +88,17 @@ struct Fixture {BaseWorld world,otherWorld;ERR_GameMode mode;IEntity actor,other
};
int main(){
// Held mode changes only admissible phase, never the original pins or clock.
{Fixture f;System::cli["errOrdinaryHeldAction"]="Run42";System::cli["errOrdinaryLookObserve"]="Run42";System::cli["errOrdinaryGateObserve"]="Run42"; f.sample();auto p=ERR_OrdinaryGateObserver::s_Request;assert(p&&p->m_HeldAction&&p->m_ObservedPhase==ERR_Phase::PRISON);f.mode.phase=ERR_Phase::RADIO_SEARCH;f.sample(2,1200);f.sample(3,1300);assert(samples==3&&!cancels&&p->m_Start==1000&&p->m_ObservedPhase==ERR_Phase::RADIO_SEARCH);f.mode.phase=ERR_Phase::PRISON;f.sample(4,1400);assert(samples==3&&cancels==1);f.mode.phase=ERR_Phase::RADIO_SEARCH;f.sample(5,1500);assert(samples==3&&cancels==1);}
for(int fault=0;fault<5;fault++){Fixture f;System::cli["errOrdinaryHeldAction"]="Run42";System::cli["errOrdinaryLookObserve"]="Run42";System::cli["errOrdinaryGateObserve"]="Run42"; if(fault==0)System::cli["errOrdinaryHeldAction"]="foreign";if(fault==1)System::cli.erase("errOrdinaryLookObserve");if(fault==2)System::cli["errOrdinaryLookObserve"]="foreign";if(fault==3)f.mode.phase=ERR_Phase::RADIO_SEARCH;if(fault==4)System::cli["errOrdinaryHeldAction"]="";f.sample();assert(!samples);f.mode.phase=ERR_Phase::PRISON;System::cli["errOrdinaryHeldAction"]="Run42";System::cli["errOrdinaryLookObserve"]="Run42";System::cli["errOrdinaryGateObserve"]="Run42"; f.sample(2,1200);assert(!samples);}
for(int fault=0;fault<8;fault++){Fixture f;System::cli["errOrdinaryHeldAction"]="Run42";System::cli["errOrdinaryLookObserve"]="Run42";System::cli["errOrdinaryGateObserve"]="Run42"; f.sample();f.mode.phase=ERR_Phase::RADIO_SEARCH;f.sample(2,1200);assert(samples==2&&!cancels);if(fault==0)System::cli.erase("errOrdinaryHeldAction");if(fault==1)System::cli["errOrdinaryLookObserve"]="foreign";if(fault==2)f.actor.vehicle=true;if(fault==3)f.menus.open=true;if(fault==4)f.life.AccountId="replacement";if(fault==5)f.mode.phase=ERR_Phase::EXTRACTION;if(fault==6)f.players.actor=nullptr;if(fault==7)game.world=nullptr;f.sample(3,1300);assert(samples==2&&cancels==1);}
{Fixture f;f.sample();System::cli["errOrdinaryHeldAction"]="Run42";System::cli["errOrdinaryLookObserve"]="Run42";System::cli["errOrdinaryGateObserve"]="Run42"; f.sample(2,1200);assert(samples==1&&cancels==1);}
{Fixture f;System::cli["errOrdinaryHeldAction"]="Run42";System::cli["errOrdinaryLookObserve"]="Run42";System::cli["errOrdinaryGateObserve"]="Run42"; f.sample();f.mode.phase=ERR_Phase::RADIO_SEARCH;f.sample(2,45999);assert(samples==2);f.sample(3,46000);assert(samples==2&&cancels==1);}
{Fixture f;System::cli["errOrdinaryHeldAction"]="Run42";System::cli["errOrdinaryLookObserve"]="Run42";System::cli["errOrdinaryGateObserve"]="Run42"; f.sample();f.mode.phase=ERR_Phase::RADIO_SEARCH;f.sample(451,1200);assert(samples==1&&cancels==1);}
{Fixture f;System::cli["errOrdinaryHeldAction"]="Run42";System::cli["errOrdinaryLookObserve"]="Run42";System::cli["errOrdinaryGateObserve"]="Run42"; f.sample();f.mode.phase=ERR_Phase::RADIO_SEARCH;f.door.control=1;f.door.state=.4;f.context.origin=Vector(6091,212,7155);f.gate.forward=Vector(1,0,0);f.handler.selected=nullptr;f.handler.current=nullptr;f.sample(2,1200);assert(samples==2&&geometries==2&&!cancels&&!lastSelected&&!lastBound&&lastPhase==ERR_Phase::RADIO_SEARCH);f.manager.context=&f.otherContext;f.sample(3,1300);assert(samples==2&&cancels==1);}
// Legacy gate-only observation retains its prior permitted phase reversal.
{Fixture f;f.sample();f.mode.phase=ERR_Phase::RADIO_SEARCH;f.sample(2,1200);f.mode.phase=ERR_Phase::PRISON;f.sample(3,1300);assert(samples==3&&!cancels);}
// Diagnostics are an independent opt-in beneath the same validated observer.
{Fixture f;f.sample();assert(choices==0);System::cli["errOrdinaryGateChoices"]="foreign";f.sample(2,1200);assert(choices==0&&samples==2);}
// A disabled stock door can be selected while the exact lock is cached available.