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
7.0 KiB
Python
75 lines
7.0 KiB
Python
"""Execute actual authored storage-anchor selection and native trace guard."""
|
|
import os,re
|
|
from pathlib import Path
|
|
from policy_harness import ROOT,run
|
|
s=Path(os.environ.get('ERR_INFANTRY_ACCESS_SOURCE',ROOT/'addons/core/Scripts/Game/ERR/10_AI/ERR_InfantryAmmoAccess.c')).read_text()
|
|
s=re.sub(r'//[^\n]*','',s).replace('class ERR_InfantryAmmoAccess','struct ERR_InfantryAmmoAccess').replace('protected ','').replace('notnull ','')
|
|
s=s.replace('ActionsManagerComponent.Cast(donor.FindComponent(ActionsManagerComponent))','donor->manager').replace('SCR_OpenVehicleStorageAction.Cast(action)','dynamic_cast<SCR_OpenVehicleStorageAction*>(action)').replace('ChimeraCharacter.Cast(recipient)','dynamic_cast<Character*>(recipient)')
|
|
s=s.replace('array<UserActionContext>', 'array<UserActionContext*>').replace('array<BaseUserAction>', 'array<BaseUserAction*>')
|
|
s=s.replace('out array<vector> points','Array<vector>& points').replace('array<','Array<').replace('foreach (','for (')
|
|
for name in ('ActionsManagerComponent','UserActionContext','BaseUserAction','ChimeraCharacter','TraceParam','ERR_InfantryAmmoAccess'):
|
|
s=re.sub(r'\b'+name+r' (\w+)',name+r'* \1',s)
|
|
for name in ('manager','context','action','character','trace','access'):
|
|
s=s.replace(name+'.',name+'->')
|
|
for name in ('ERR_ConvoyRules','ERR_ForceRules','TraceFlags','vector'):
|
|
s=s.replace(name+'.',name+'::')
|
|
s=s.replace('GetGame().GetWorld()','GetGame()->GetWorld()').replace('GetWorld().','GetWorld()->').replace('null','nullptr')
|
|
s=s.replace('TraceMove(trace, Filter)','TraceMove(trace, [this](IEntity e){return Filter(e);})')
|
|
s=re.sub(r'\b(bool|IEntity) (\w+);',r'\1 \2{};',s).replace('\n}\n','\n};\n')
|
|
run(r'''
|
|
#include <cassert>
|
|
#include <vector>
|
|
#include <cmath>
|
|
#include <limits>
|
|
template<class T>struct Array:std::vector<T>{using std::vector<T>::vector;using std::vector<T>::operator=;int Count(){return this->size();}bool IsEmpty(){return this->empty();}void Insert(T t){this->push_back(t);}};
|
|
struct vector{float x=0,y=0,z=0;float& operator[](int n){return n==0?x:n==1?y:z;}static float Distance(vector a,vector b){return std::sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)+(a.z-b.z)*(a.z-b.z));}};
|
|
struct Entity;struct Manager;using IEntity=Entity*;using Vehicle=Entity*;
|
|
struct Entity{virtual ~Entity(){}Manager*manager=nullptr;IEntity parent=nullptr;};
|
|
struct Character:Entity{vector aim={0,1.4,0};vector AimingPosition(){return aim;}};using ChimeraCharacter=Character;
|
|
struct BaseUserAction{virtual ~BaseUserAction(){}IEntity owner=nullptr;auto GetOwner(){return owner;}};
|
|
struct SCR_OpenVehicleStorageAction:BaseUserAction{};
|
|
struct UserActionContext{Array<BaseUserAction*>actions;vector anchor={2,1.4,0};bool valid=true;void GetActionsList(Array<BaseUserAction*>&a){a=actions;}bool GetTransformationWorld(vector (&mat)[4]){mat[3]=anchor;return valid;}};
|
|
struct Manager{bool enabled=true;Array<UserActionContext*>contexts;bool IsEnabled(){return enabled;}void GetContextList(Array<UserActionContext*>&a){a=contexts;}};using ActionsManagerComponent=Manager;
|
|
struct TraceFlags{static constexpr int WORLD=1,ENTS=2;};static constexpr int TRACE_LAYER_CAMERA=99;
|
|
struct TraceParam{vector Start,End;int Flags=0,LayerMask=0;};
|
|
struct World{float fraction=1;Array<IEntity>obstacles;int traces=0;vector lastStart,lastEnd;
|
|
template<class F>float TraceMove(TraceParam*p,F filter){traces++;lastStart=p->Start;lastEnd=p->End;assert(p->Flags==3&&p->LayerMask==99);for(auto entity:obstacles)if(filter(entity))return .5;return fraction;}};
|
|
struct Game{World world;auto GetWorld(){return &world;}} game;Game*GetGame(){return &game;}
|
|
struct ERR_ConvoyRules{static bool PartOf(IEntity a,IEntity root){int n=0;while(a&&n++<32){if(a==root)return true;a=a->parent;}return false;}};
|
|
struct ERR_ForceRules{static bool FiniteVector(vector v){return std::isfinite(v.x)&&std::isfinite(v.y)&&std::isfinite(v.z);}};
|
|
''' + s + r'''
|
|
int main(){
|
|
Entity truck,truckPart,gear,wall,otherTruck,otherChild;Character actor;truckPart.parent=&truck;gear.parent=&actor;otherChild.parent=&otherTruck;
|
|
Manager manager;truck.manager=&manager;UserActionContext context;SCR_OpenVehicleStorageAction storage;storage.owner=&truck;context.actions={&storage};manager.contexts={&context};
|
|
Array<vector>points;assert(ERR_InfantryAmmoAccess::Points(&truck,points)&&points.Count()==1);
|
|
ERR_InfantryAmmoAccess access;assert(access.Check(&truck,&actor));assert(game.world.lastStart.y==1.4f&&game.world.lastEnd.x==2);
|
|
// Own hull/gear cannot falsely block an interior-authored native storage anchor.
|
|
game.world.obstacles={&truck,&truckPart,&actor,&gear};assert(access.Check(&truck,&actor));
|
|
// A wall or another vehicle still blocks even when owned geometry preceded it.
|
|
game.world.obstacles.push_back(&wall);assert(!access.Check(&truck,&actor));
|
|
game.world.obstacles={&truck,&otherChild};assert(!access.Check(&truck,&actor));game.world.obstacles.clear();
|
|
for(float value:{0.f,.99f,-1.f,2.f,std::numeric_limits<float>::quiet_NaN()}){game.world.fraction=value;assert(!access.Check(&truck,&actor));}game.world.fraction=1;
|
|
context.anchor.x=4.01;assert(!access.Check(&truck,&actor));context.anchor.x=0;assert(!access.Check(&truck,&actor));context.anchor.x=2;
|
|
actor.aim.y=std::numeric_limits<float>::quiet_NaN();assert(!access.Check(&truck,&actor));actor.aim.y=1.4;
|
|
context.valid=false;assert(!access.Check(&truck,&actor));context.valid=true;
|
|
context.anchor.z=std::numeric_limits<float>::quiet_NaN();assert(!access.Check(&truck,&actor));context.anchor.z=0;
|
|
storage.owner=&otherTruck;assert(!access.Check(&truck,&actor));storage.owner=&truck;
|
|
BaseUserAction door;door.owner=&truck;context.actions={&door};assert(!access.Check(&truck,&actor));context.actions={&storage};
|
|
manager.enabled=false;assert(!access.Check(&truck,&actor));manager.enabled=true;
|
|
// Stock Ural defines 36 root contexts and ammo adds one: a valid storage action near the end must remain discoverable.
|
|
for(int count:{37,64}){
|
|
std::vector<UserActionContext> stockContexts(count);manager.contexts.clear();
|
|
for(auto& authored:stockContexts){authored.actions={&door};manager.contexts.push_back(&authored);}
|
|
stockContexts.back().actions={&storage};
|
|
assert(ERR_InfantryAmmoAccess::Points(&truck,points)&&points.Count()==1&&access.Check(&truck,&actor));
|
|
}
|
|
manager.contexts.clear();manager.contexts.resize(65,&context);assert(!access.Check(&truck,&actor));manager.contexts={&context};
|
|
context.actions.resize(17,&storage);assert(!access.Check(&truck,&actor));context.actions={&storage};
|
|
manager.contexts={nullptr};assert(!access.Check(&truck,&actor));manager.contexts={&context};
|
|
assert(!access.Check(&truck,&wall));assert(!access.Check(nullptr,&actor));
|
|
// A blocked context never skips an intervening external entity; another independently clear authored context may qualify.
|
|
UserActionContext distant;distant.actions={&storage};distant.anchor={9,1.4,0};manager.contexts={&distant,&context};assert(access.Check(&truck,&actor));
|
|
}
|
|
''')
|
|
print('PASS: actual authored storage anchors, native trace flags, own-hierarchy exclusion, external wall/vehicle obstruction, range, unknown geometry and bounded context refusal')
|