Integrate faction and random settings menus, generated objectives, scouts, convoys, air support, mortar stations and body-intel recovery. Add identified-body aggression, finite hunter UAZ deployment, dedicated objective defence and maximum AI skill with separate reduced aim accuracy. Include policy tests, native probes, evidence and documentation.
118 lines
13 KiB
Python
118 lines
13 KiB
Python
"""Exercise actual admin utility command/state methods through native API adapters."""
|
|
from policy_harness import ROOT, body, run
|
|
source=ROOT/'addons/core/Scripts/Game/ERR/00_Core/ERR_AdminPlayerTools.c'
|
|
def adapt(s):
|
|
s=s.replace('protected ', '').replace('null', 'nullptr')
|
|
s=s.replace('array<string> replies','Array<String>& replies')
|
|
s=s.replace('string ', 'String ').replace('ResourceName ', 'String ')
|
|
s=s.replace('args.Trim()', 'args.Trim()')
|
|
for typ in ['ERR_GameMode', 'SCR_PlayerController', 'PlayerManager', 'IEntity', 'DamageManagerComponent', 'SCR_InventoryStorageManagerComponent']:
|
|
pass
|
|
for name in ['actor','m_Actor','mode','controller','manager','m_Mode','m_Controller','m_Damage','inventory','m_Grants','Operation']:
|
|
s=s.replace(name+'.',name+'->')
|
|
s=s.replace('GetGame().','GetGame()->').replace('GetWorld().','GetWorld()->').replace('Players().','Players()->')
|
|
s=s.replace('ERR_GameMode.Get()', 'Mode::Get()').replace('Replication.IsServer()', 'Replication::IsServer()').replace('SCR_Global.IsAdmin(', 'Global::IsAdmin(').replace('ERR_Actors.Alive(', 'Actors::Alive(')
|
|
s=s.replace('FindComponent(DamageManagerComponent)', 'FindDamage()').replace('FindComponent(SCR_InventoryStorageManagerComponent)', 'FindInventory()')
|
|
s=s.replace('DamageManagerComponent.Cast(', 'Damage::Cast(').replace('SCR_InventoryStorageManagerComponent.Cast(', 'Inventory::Cast(')
|
|
s=s.replace('purpose: EStoragePurpose.PURPOSE_DEPOSIT, cb: m_Grants->Operation', '1, m_Grants->Operation')
|
|
s=s.replace('String item;', 'String item;').replace('string.Format(', 'String::Format(').replace('ERR_DebugAI.', 'DebugAI::').replace('ERR_DebugIntel.', 'DebugIntel::')
|
|
return s
|
|
binding=adapt(body(source,'void Bind('))
|
|
constructor=adapt(body(source,'void ERR_AdminPlayerTools(')).replace('void ERR_AdminPlayerTools(ERR_AdminGrantState grants = nullptr)', 'Tools(GrantState* grants = nullptr)')
|
|
methods='\n'.join(adapt(body(source,signature)) for signature in [
|
|
'protected IEntity CurrentBody(', 'protected ResourceName ItemPrefab(', 'protected void RestoreDamage(',
|
|
'bool Execute(', 'void Tick(', 'void Stop('])
|
|
run(r'''
|
|
#include <cassert>
|
|
#include <algorithm>
|
|
#include <cctype>
|
|
#include <string>
|
|
#include <vector>
|
|
struct String:std::string {
|
|
using std::string::string;String()=default;String(const std::string& s):std::string(s){}
|
|
static String Format(String text,int n){text.replace(text.find("%1"),2,std::to_string(n));return text;}
|
|
String Trim(){auto a=find_first_not_of(" \t\n");return a==npos?String():String(substr(a,find_last_not_of(" \t\n")-a+1));}
|
|
void ToLower(){std::transform(begin(),end(),begin(),[](unsigned char c){return std::tolower(c);});}
|
|
bool StartsWith(const char* p){return rfind(p,0)==0;}bool IsEmpty(){return empty();}
|
|
int Length(){return size();}String Substring(int start,int count){return substr(start,count);}
|
|
};
|
|
template<class T>struct Array:std::vector<T>{void Insert(T v){this->push_back(v);}};
|
|
struct ERR_AdminItemCallback{bool Finished=false,Succeeded=false;};
|
|
struct Damage{bool enabled=true;int changes=0;bool IsDamageHandlingEnabled(){return enabled;}void EnableDamageHandling(bool value){enabled=value;changes++;}static Damage* Cast(Damage* value){return value;}};
|
|
using DamageManagerComponent=Damage*;
|
|
struct Inventory{bool accept=true;int submissions=0;String prefab;ERR_AdminItemCallback* callback=nullptr;static Inventory* Cast(Inventory* value){return value;}
|
|
bool TrySpawnPrefabToStorage(String p,int purpose,ERR_AdminItemCallback* cb){assert(purpose==1);submissions++;prefab=p;callback=cb;return accept;}
|
|
};using SCR_InventoryStorageManagerComponent=Inventory*;
|
|
struct Entity{bool alive=true;Damage damage;Inventory inventory;bool hasDamage=true,hasInventory=true;Damage* FindDamage(){return hasDamage?&damage:nullptr;}Inventory* FindInventory(){return hasInventory?&inventory:nullptr;}};using IEntity=Entity*;
|
|
struct Controller{int id=1;Entity* actor=nullptr;int GetPlayerId(){return id;}Entity* GetControlledEntity(){return actor;}};using SCR_PlayerController=Controller*;
|
|
struct Manager{Controller* controller=nullptr;Entity* actor=nullptr;Controller* GetPlayerController(int){return controller;}Entity* GetPlayerControlledEntity(int){return actor;}};using PlayerManager=Manager*;
|
|
struct Roster{Entity* actor=nullptr;bool CurrentActor(Entity* a){return actor==a;}};
|
|
struct Mode{bool active=true;Roster roster;bool hasRoster=true;static Mode* current;static Mode* Get(){return current;}bool Active(){return active;}Roster* Players(){return hasRoster?&roster:nullptr;}};Mode* Mode::current=nullptr;using ERR_GameMode=Mode*;
|
|
struct Game{float now=0;Manager manager;Manager* GetPlayerManager(){return &manager;}Game* GetWorld(){return this;}float GetWorldTime(){return now;}}game;Game* GetGame(){return &game;}
|
|
namespace Replication{bool server=true;bool IsServer(){return server;}}
|
|
namespace Global{bool admin=true;bool IsAdmin(int){return admin;}}
|
|
namespace Actors{bool Alive(Entity* a){return a&&a->alive;}}
|
|
namespace DebugAI {int calls=0;int KillNearby(Mode* m,Entity* e){assert(m&&e);calls++;return 3;}}
|
|
namespace DebugIntel {int calls=0;bool success=true;bool SpawnSix(Mode* m,Entity* e){assert(m&&e);calls++;return success;}}
|
|
struct GrantState{IEntity Actor=nullptr;ERR_AdminItemCallback* Operation=nullptr;String Item;float Deadline=0;bool TimedOut=false;
|
|
'''+binding+r'''
|
|
};
|
|
struct Tools{
|
|
ERR_GameMode m_Mode=nullptr;SCR_PlayerController m_Controller=nullptr;IEntity m_Actor=nullptr;DamageManagerComponent m_Damage=nullptr;
|
|
bool m_PreviousDamage=false,m_God=false,m_Stopped=false;GrantState* m_Grants=new GrantState();
|
|
'''+constructor+methods+r'''
|
|
};
|
|
struct Fixture{
|
|
Mode mode;Controller controller;Entity actor;Tools tools;Array<String> replies;
|
|
Fixture(){Mode::current=&mode;controller.actor=&actor;mode.roster.actor=&actor;game.manager.controller=&controller;game.manager.actor=&actor;game.now=0;Global::admin=true;Replication::server=true;}
|
|
bool command(String args){replies.clear();return tools.Execute(&mode,&controller,args,replies);}void tick(){replies.clear();tools.Tick(replies);}
|
|
};
|
|
int main(){
|
|
{Fixture f;int before=DebugIntel::calls;f.command("cheat intel");assert(DebugIntel::calls==before+1&&f.replies[0].find("Spawned 6")!=String::npos&&f.actor.inventory.submissions==0);Global::admin=false;f.command("cheat intel");assert(DebugIntel::calls==before+1);}
|
|
{Fixture f;DebugIntel::success=false;f.command("cheat intel");assert(f.replies[0].find("Could not place")!=String::npos);DebugIntel::success=true;}
|
|
|
|
{Fixture f;int before=DebugAI::calls;f.command("killais");assert(DebugAI::calls==before+1&&f.replies[0].find("Killed 3")!=String::npos);Global::admin=false;f.command("killais");assert(DebugAI::calls==before+1);}
|
|
|
|
{Fixture f;assert(!f.command("mission time show")&&f.replies.empty());assert(f.command(" GOD SET ON ")&&!f.actor.damage.enabled);assert(f.tools.m_God);f.command("god");assert(f.actor.damage.changes==1);f.command("god show");assert(f.replies[0].find("on")!=String::npos);f.command("ungod");assert(f.actor.damage.enabled&&f.actor.damage.changes==2);f.tools.Stop();assert(f.actor.damage.changes==2);}
|
|
{Fixture f;f.actor.damage.enabled=false;f.command("god");f.command("god set off");assert(!f.actor.damage.enabled);}
|
|
{Fixture f;f.command("god");Global::admin=false;f.tick();assert(f.actor.damage.enabled&&f.tools.m_Stopped&&f.replies.empty());Global::admin=true;f.command("god");assert(f.actor.damage.enabled);}
|
|
{Fixture f;f.command("god");Entity replacement;f.controller.actor=&replacement;game.manager.actor=&replacement;f.mode.roster.actor=&replacement;f.tick();assert(f.actor.damage.enabled&&replacement.damage.enabled&&f.tools.m_Stopped);}
|
|
{Fixture f;f.command("god");f.mode.active=false;f.tick();assert(f.actor.damage.enabled&&f.tools.m_Stopped);}
|
|
{Fixture f;Global::admin=false;f.command("cheat map");assert(f.actor.inventory.submissions==0);}
|
|
{Fixture f;Controller impostor;game.manager.controller=&impostor;f.command("god");assert(f.actor.damage.enabled);}
|
|
{Fixture f;f.mode.roster.actor=nullptr;f.command("cheat map");assert(f.actor.inventory.submissions==0);}
|
|
{Fixture f;f.actor.alive=false;f.command("god");assert(f.actor.damage.enabled);}
|
|
{Fixture f;f.actor.hasDamage=false;f.command("god");assert(!f.tools.m_God);}
|
|
{Fixture f;f.actor.hasInventory=false;f.command("cheat map");assert(!f.tools.m_Grants->Operation);}
|
|
{Fixture f;f.command("help god");assert(f.replies[0].find("god show")!=String::npos);f.command("help cheat");assert(f.replies[0].find("PASGT")!=String::npos&&f.actor.inventory.submissions==0);f.command("god invalid");assert(f.actor.damage.enabled);f.command("cheat invalid");assert(f.actor.inventory.submissions==0);}
|
|
{Fixture f;f.command("cheat map");assert(f.actor.inventory.submissions==1&&f.tools.m_Grants->Operation);for(int i=0;i<5;i++){f.command("cheat helmet");f.tick();}assert(f.actor.inventory.submissions==1);f.actor.inventory.callback->Finished=true;f.actor.inventory.callback->Succeeded=true;f.tick();assert(!f.tools.m_Grants->Operation&&f.replies.size()==1);f.tick();assert(f.replies.empty());f.command("cheat uniform");assert(f.actor.inventory.submissions==2&&f.actor.inventory.prefab.find("Jacket_US_BDU")!=String::npos);}
|
|
{Fixture f;f.command("cheat helmet");assert(f.actor.inventory.prefab.find("Helmet_PASGT_01_base")!=String::npos);f.actor.inventory.callback->Finished=true;f.actor.inventory.callback->Succeeded=false;f.tick();assert(f.replies.size()==1&&f.replies[0].find("could not")!=String::npos&&!f.tools.m_Grants->Operation);}
|
|
{Fixture f;f.actor.inventory.accept=false;f.command("cheat map");assert(f.actor.inventory.submissions==1&&!f.tools.m_Grants->Operation);f.tick();assert(f.replies.empty());}
|
|
{Fixture f;f.command("cheat map");game.now=29999;f.tick();assert(!f.tools.m_Grants->TimedOut);game.now=30000;f.tick();assert(f.tools.m_Grants->TimedOut&&f.replies.size()==1);f.actor.inventory.callback->Finished=true;f.actor.inventory.callback->Succeeded=true;f.tick();assert(f.replies.empty());f.command("cheat map");assert(f.actor.inventory.submissions==1);f.command("god");assert(!f.actor.damage.enabled);}
|
|
{Fixture f;f.command("cheat map");auto callback=f.actor.inventory.callback;f.tools.Stop();callback->Finished=true;callback->Succeeded=true;f.tick();assert(f.replies.empty()&&f.actor.inventory.submissions==1);}
|
|
{Fixture f;f.command("god");f.actor.alive=false;f.tick();assert(f.actor.damage.enabled&&f.tools.m_Stopped);}
|
|
|
|
// Same physical body keeps accepted insertion state after revoke/regrant.
|
|
{Fixture f;f.command("god");f.command("cheat map");auto shared=f.tools.m_Grants;auto pending=shared->Operation;Global::admin=false;f.tick();assert(f.actor.damage.enabled&&f.tools.m_Stopped);Global::admin=true;Tools renewed(shared);renewed.Execute(&f.mode,&f.controller,"cheat map",f.replies);assert(f.actor.inventory.submissions==1&&shared->Operation==pending);pending->Finished=true;pending->Succeeded=true;renewed.Tick(f.replies);assert(!shared->Operation);renewed.Execute(&f.mode,&f.controller,"cheat map",f.replies);assert(f.actor.inventory.submissions==2);}
|
|
// Timeout quarantine survives fresh sessions even after a late callback.
|
|
{Fixture f;f.actor.damage.enabled=false;f.command("god");f.command("cheat map");game.now=30000;f.tick();auto shared=f.tools.m_Grants;Global::admin=false;f.tick();assert(!f.actor.damage.enabled);Global::admin=true;shared->Operation->Finished=true;shared->Operation->Succeeded=true;Tools renewed(shared);renewed.Execute(&f.mode,&f.controller,"cheat helmet",f.replies);renewed.Tick(f.replies);assert(f.actor.inventory.submissions==1&&shared->TimedOut);}
|
|
// A different canonical body gets a fresh grant state, never god mode.
|
|
{Fixture f;f.command("god");f.command("cheat map");auto shared=f.tools.m_Grants;auto oldCallback=shared->Operation;f.tools.Stop();Entity next;f.controller.actor=&next;game.manager.actor=&next;f.mode.roster.actor=&next;Tools renewed(shared);renewed.Execute(&f.mode,&f.controller,"cheat helmet",f.replies);assert(f.actor.damage.enabled&&next.damage.enabled&&next.inventory.submissions==1&&shared->Actor==&next&&shared->Operation!=oldCallback);oldCallback->Finished=true;oldCallback->Succeeded=true;f.replies.clear();renewed.Tick(f.replies);assert(f.replies.empty());}
|
|
}
|
|
''')
|
|
s=source.read_text()
|
|
assert 'PURPOSE_DEPOSIT' in s and 'PURPOSE_ANY' not in s
|
|
assert 'FullHeal' not in s and 'DeleteEntity' not in s and 'CallLater' not in s
|
|
assert 'protected override void OnComplete() { Finish(true); }' in s
|
|
assert 'protected override void OnFailed() { Finish(false); }' in s
|
|
assert 'protected void Finish(bool success) { if (!Finished)' in s
|
|
print('PASS: actual admin body authorization, god restoration, vanilla item deposit, callback completion/failure, timeout quarantine and stop/revocation paths')
|
|
|
|
bridge=(ROOT/'addons/core/Scripts/Game/ERR/00_Core/ERR_PlayerAdminCommands.c').read_text()
|
|
session=(ROOT/'addons/core/Scripts/Game/ERR/00_Core/ERR_AdminSession.c').read_text()
|
|
assert 'protected ref ERR_AdminGrantState m_ERRAdminGrants = new ERR_AdminGrantState();' in bridge
|
|
assert 'new ERR_AdminSession(mode, this, token, m_ERRAdminGrants)' in bridge
|
|
assert session.count('new ERR_AdminPlayerTools(m_Grants)')==2
|
|
assert 'm_Grants' not in body(source, 'void Stop(')
|
|
print('PASS: same-body revoke/regrant preserves pending insertions and timeout quarantine; new-body binding isolates late callbacks and never inherits god mode')
|