76 lines
9.8 KiB
Python
76 lines
9.8 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/ERR_OrdinaryLookObserver.c'
|
|
def cpp(s):
|
|
s=s.replace('protected ', '')
|
|
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'):
|
|
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()')
|
|
return s
|
|
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; 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,EXTRACTION};}
|
|
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;}}
|
|
namespace ERR_OrdinaryInputObserverRules {bool Nonce(string n){return !n.empty()&&n.size()<=32&&n.find_first_not_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")==string::npos;}}
|
|
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;
|
|
'''+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(){
|
|
{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);}
|
|
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<4;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);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')
|