Files
EscapistsReintroduced/tests/test_ordinary_look_observer.py
jakub cab998fb64 Combine Workshop addon and fix prison startup
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.
2026-09-20 16:42:52 +02:00

92 lines
14 KiB
Python

"""Execute actual observer methods against fake read-only native boundaries."""
import re
from policy_harness import ROOT, body, run
P=ROOT/'addons/core/Scripts/Game/ERR/00_Core/ERR_OrdinaryLookObserver.c'
def cpp(s):
s=s.replace('protected ', '').replace('out bool held', 'bool& held')
types=('ERR_GameMode','BaseWorld','PlayerController','IEntity','PlayerCamera','ERR_PlayerLife','PlayerManager','CameraManager')
for typ in types:s=re.sub(r'\b'+typ+r' (\w+)',typ+r'* \1',s)
for name in ('mode','world','controller','actor','manager','cameras','m_Mode','m_World','m_Controller','m_Actor','m_Camera','m_Life','s_Request'):
s=s.replace(name+'.',name+'->')
for scope in ('System','Replication','RplSession','RplMode','ERR_Phase','ERR_GameMode','ERR_Actors','ERR_OrdinaryInputObserverRules','CompartmentAccessComponent'):
s=s.replace(scope+'.',scope+'::')
s=s.replace('GetGame().','GetGame()->').replace('Players().','Players()->').replace('GetInputManager().','GetInputManager()->').replace('GetMenuManager().','GetMenuManager()->')
s=s.replace('null','nullptr').replace('new ERR_OrdinaryLookObserver()', 'new ERR_OrdinaryLookObserver()')
s=s.replace('nonce.Length()', 'int(nonce.size())').replace('allowed.Contains(nonce[i])', '(allowed.find(nonce[i]) != string::npos)')
return s
shared='\n'.join(cpp(body(ROOT/'addons/core/Scripts/Game/ERR/00_Core/ERR_OrdinaryInputObserver.c', signature)) for signature in ('static bool Nonce(', 'static bool HeldScope(', 'static bool PhaseAllowed('))
methods='\n'.join(cpp(body(P,signature)) for signature in (
'protected static bool Enabled(', 'static void Sample(', 'protected void Cancel(', 'protected bool Context(', 'protected static bool FiniteVector(', 'protected void Observe('))
run(r'''
#include <cassert>
#include <cmath>
#include <limits>
#include <map>
#include <string>
#include <vector>
using string=std::string;using UUID=string;
struct vector {float v[3]={0,0,0}; float& operator[](int i){return v[i];}float Length(){return std::sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);}vector operator/(float n){return {{v[0]/n,v[1]/n,v[2]/n}};}};
vector Vector(float a,float b,float c){return {{a,b,c}};}
struct BaseWorld {};
struct IEntity {BaseWorld* world=nullptr;bool living=true,vehicle=false;vector origin=Vector(100,2,100);vector GetOrigin(){return origin;} vector matrix[4]={Vector(1,0,0),Vector(0,1,0),Vector(0,0,1),Vector(100,2,100)};BaseWorld* GetWorld(){return world;}void GetTransform(vector out[4]){for(int i=0;i<4;i++)out[i]=matrix[i];}};
struct CameraManager;
struct PlayerCamera:IEntity {CameraManager* replaceDuringRead=nullptr;void GetWorldCameraTransform(vector out[4]);};
struct CameraManager {PlayerCamera* current=nullptr;PlayerCamera* CurrentCamera(){return current;}};
void PlayerCamera::GetWorldCameraTransform(vector out[4]){GetTransform(out);if(replaceDuringRead)replaceDuringRead->current=nullptr;}
struct PlayerController {int id=1;IEntity* actor=nullptr;PlayerCamera* camera=nullptr;int GetPlayerId(){return id;}IEntity* GetControlledEntity(){return actor;}PlayerCamera* GetPlayerCamera(){return camera;}};
struct PlayerManager {PlayerController* controller=nullptr;IEntity* actor=nullptr;PlayerController* GetPlayerController(int){return controller;}IEntity* GetPlayerControlledEntity(int){return actor;}};
struct ERR_PlayerLife {UUID AccountId="account";};
struct Roster {ERR_PlayerLife* life=nullptr;IEntity* actor=nullptr;ERR_PlayerLife* CurrentActor(IEntity* value){return value==actor?life:nullptr;}};
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;static ERR_GameMode* Get(){return current;}bool Active(){return active;}int Phase(){return phase;}BaseWorld* GetWorld(){return world;}Roster* Players(){return roster;}};ERR_GameMode* ERR_GameMode::current=nullptr;
struct InputManager {float right=0,up=0;float GetActionValue(string name){return name=="CharacterTurnRight"?right:up;}};
struct MenuManager {bool open=false;void* GetTopMenu(){return open?this:nullptr;}};
struct Game {BaseWorld* world=nullptr;PlayerController* controller=nullptr;PlayerManager* players=nullptr;CameraManager* cameras=nullptr;InputManager* input=nullptr;MenuManager* menus=nullptr;BaseWorld* GetWorld(){return world;}PlayerController* GetPlayerController(){return controller;}PlayerManager* GetPlayerManager(){return players;}CameraManager* GetCameraManager(){return cameras;}InputManager* GetInputManager(){return input;}MenuManager* GetMenuManager(){return menus;}} game;Game* activeGame=&game;Game* GetGame(){return activeGame;}
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;}}
struct ERR_OrdinaryInputObserverRules {
'''+shared+r'''
};
namespace CompartmentAccessComponent {IEntity* GetVehicleIn(IEntity* actor){return actor->vehicle?actor:nullptr;}}
namespace ERR_Actors {bool CanFight(IEntity* actor){return actor&&actor->living;}}
int headers=0,samples=0,cancels=0;string reason;vector lastDirection,lastCamera,lastBody,lastFacing,lastTurn;
void PrintFormat(string,string,int,int){headers++;}
void PrintFormat(string,string,int,int,string why){cancels++;reason=why;}
void PrintFormat(string,string,int,int,vector direction,vector camera,vector actor,vector facing,vector turn){samples++;lastDirection=direction;lastCamera=camera;lastBody=actor;lastFacing=facing;lastTurn=turn;}
class ERR_OrdinaryLookObserver {public:
static ERR_OrdinaryLookObserver* s_Request;static bool s_Attempted;
ERR_GameMode* m_Mode=nullptr;BaseWorld* m_World=nullptr;PlayerController* m_Controller=nullptr;IEntity* m_Actor=nullptr;PlayerCamera* m_Camera=nullptr;ERR_PlayerLife* m_Life=nullptr;
UUID m_Account;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_OrdinaryLookObserver* ERR_OrdinaryLookObserver::s_Request=nullptr;bool ERR_OrdinaryLookObserver::s_Attempted=false;
struct Fixture {BaseWorld world,foreignWorld;ERR_GameMode mode;IEntity actor,otherActor;PlayerCamera camera,otherCamera;PlayerController controller,otherController;PlayerManager players;CameraManager cameras;Roster roster;ERR_PlayerLife life,otherLife;InputManager input;MenuManager menus;
Fixture(){ERR_OrdinaryLookObserver::s_Request=nullptr;ERR_OrdinaryLookObserver::s_Attempted=false;headers=samples=cancels=0;reason="";System::console=false;System::cli={{"errOrdinaryScenario","core"},{"errOrdinaryInputObserve","Run42"},{"errOrdinaryLookObserve","Run42"}};Replication::server=true;RplSession::mode=RplMode::None;ERR_GameMode::current=&mode;activeGame=&game;mode.world=&world;mode.roster=&roster;actor.world=&world;camera.world=&world;controller.actor=&actor;controller.camera=&camera;players.controller=&controller;players.actor=&actor;cameras.current=&camera;roster.actor=&actor;roster.life=&life;game={&world,&controller,&players,&cameras,&input,&menus};camera.matrix[2]=Vector(2,0,0);camera.matrix[3]=Vector(100,3.6,100);input.right=.25;input.up=-.1;}
void sample(int index=1,int now=1100){ERR_OrdinaryLookObserver::Sample(&mode,&world,&controller,&actor,"Run42",1000,index,now);}
};
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_OrdinaryLookObserver::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("errOrdinaryGateObserve");if(fault==2)System::cli["errOrdinaryGateObserve"]="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["errOrdinaryGateObserve"]="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.controller.camera=&f.otherCamera;f.sample(2,1200);assert(samples==1&&cancels==1);}
{Fixture f;f.sample();f.mode.phase=ERR_Phase::RADIO_SEARCH;f.sample(2,1200);assert(samples==1&&cancels==1);}
{Fixture f;f.sample();assert(headers==1&&samples==1&&!cancels);assert(lastDirection[0]==1&&lastDirection[2]==0);assert(lastFacing[2]==1);assert(lastCamera[1]!=lastBody[1]);assert(lastTurn[0]==.25f&&lastTurn[1]==-.1f);f.sample(2,1200);assert(headers==1&&samples==2);}
{Fixture f;f.actor.origin=Vector(100.04,1.999,99.97);f.actor.matrix[3]=Vector(100,2,100);f.actor.matrix[2]=Vector(0,0,-1);f.sample();assert(samples==1&&!cancels);assert(lastBody[0]==f.actor.origin[0]&&lastBody[1]==f.actor.origin[1]&&lastBody[2]==f.actor.origin[2]);assert(lastBody[0]!=f.actor.matrix[3][0]);assert(lastFacing[2]==-1);assert(lastCamera[1]==f.camera.matrix[3][1]&&lastDirection[0]==1);}
for(int fault=0;fault<7;fault++){Fixture f;if(fault==0)System::cli.erase("errOrdinaryLookObserve");if(fault==1)System::cli["errOrdinaryLookObserve"]="foreign";if(fault==2)System::cli["errOrdinaryInputObserve"]="foreign";if(fault==3)System::console=true;if(fault==4)Replication::server=false;if(fault==5)RplSession::mode=RplMode::Listen;if(fault==6)System::cli["errOrdinaryScenario"]="other";f.sample();assert(!samples&&!headers&&!cancels&&!ERR_OrdinaryLookObserver::s_Attempted);}
{Fixture f;System::cli["errOrdinaryScenario"]="chat";f.sample();assert(samples==1);System::cli.erase("errOrdinaryLookObserve");f.sample(2,1200);assert(cancels==1);System::cli["errOrdinaryLookObserve"]="Run42";f.sample(3,1300);assert(samples==1&&cancels==1);}
for(int fault=0;fault<16;fault++){Fixture f;f.sample();if(fault==0)f.cameras.current=&f.otherCamera;if(fault==1)f.controller.camera=&f.otherCamera;if(fault==2)game.controller=&f.otherController;if(fault==3)f.controller.actor=&f.otherActor;if(fault==4)f.players.actor=&f.otherActor;if(fault==5)f.players.controller=&f.otherController;if(fault==6)f.life.AccountId="replacement";if(fault==7)f.roster.life=&f.otherLife;if(fault==8)f.actor.world=&f.foreignWorld;if(fault==9)f.camera.world=&f.foreignWorld;if(fault==10)f.mode.active=false;if(fault==11)f.mode.phase=ERR_Phase::EXTRACTION;if(fault==12)f.actor.living=false;if(fault==13)game.cameras=nullptr;if(fault==14)activeGame=nullptr;if(fault==15)f.menus.open=true;f.sample(2,1200);assert(samples==1&&cancels==1);if(fault==15)assert(reason=="menu-opened");f.sample(3,1300);assert(cancels==1);}
for(int fault=0;fault<5;fault++){Fixture f;f.sample();int index=2,now=1200;if(fault==0)index=1;if(fault==1)index=3;if(fault==2)index=451;if(fault==3)now=1099;if(fault==4)now=46000;f.sample(index,now);assert(samples==1&&cancels==1&&reason=="sample-or-clock-bound");}
{Fixture f;f.sample();for(int i=2;i<=450;i++)f.sample(i,1000+i*99);assert(samples==450&&!cancels);f.sample(451,45649);assert(cancels==1);}
{Fixture f;f.camera.replaceDuringRead=&f.cameras;f.sample();assert(!headers&&!samples&&cancels==1);}
for(int fault=0;fault<5;fault++){Fixture f;if(fault==0)f.camera.matrix[2]=Vector(0,0,0);if(fault==1)f.camera.matrix[3][0]=std::numeric_limits<float>::infinity();if(fault==2)f.input.up=std::numeric_limits<float>::quiet_NaN();if(fault==3)f.actor.matrix[2]=Vector(3,0,0);if(fault==4)f.actor.origin[0]=std::numeric_limits<float>::quiet_NaN();f.sample();assert(!samples&&cancels==1&&reason=="invalid-native-pose");}
{Fixture f;f.sample();ERR_OrdinaryLookObserver::Sample(&f.mode,&f.foreignWorld,&f.controller,&f.actor,"Run42",1000,2,1200);assert(cancels==1&&reason=="original-binding-changed");}
}
''')
print('PASS: actual read-only look observer methods enforce explicit scope, pinned native camera/body/identity, normalized pose, terminal cancellation and original sample/time bounds')