Reduce redundant AI equipment, radio and observation checks
continuous-integration/drone/push Build is passing
continuous-integration/drone/push Build is passing
Preserve live ownership and detection rules while skipping redundant work. Record published Workshop version 0.0.150 and add operation-count regressions.
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
"""Execute actual HQ/vehicle radio queries; prove max-capability short circuit."""
|
||||
import os,re
|
||||
from pathlib import Path
|
||||
from policy_harness import ROOT,body,run
|
||||
source=Path(os.environ.get('ERR_HQ_REPORT_SOURCE',ROOT/'addons/core/Scripts/Game/ERR/10_AI/ERR_HQReport.c'))
|
||||
hq=body(source,'static int Capability(')
|
||||
hq=hq.replace('IEntity character','Entity* character').replace('ERR_Actors.CanFight','CanFight')
|
||||
hq=hq.replace('InventoryStorageManagerComponent inventory = InventoryStorageManagerComponent.Cast(character.FindComponent(InventoryStorageManagerComponent));','Storage* inventory = character->storage;')
|
||||
hq=hq.replace('array<IEntity> items = {};','std::vector<Entity*> items;').replace('inventory.GetItems','inventory->GetItems').replace('ERR_HQ hq = ERR_HQ.Get();','HQ* hq = HQ::current;').replace('hq.Hunters()','hq->Hunters()').replace('Hunters().','Hunters()->')
|
||||
hq=hq.replace('foreach (IEntity item : items)','for (Entity* item : items)').replace('item.FindComponent(BaseRadioComponent)','HasBaseRadio(item)').replace('SCR_RadioComponent gadget = SCR_RadioComponent.Cast(item.FindComponent(SCR_RadioComponent));','Radio* gadget = GetRadio(item);').replace('gadget.','gadget->').replace('Math.Max','std::max').replace('int result;','int result=0;')
|
||||
vehicle=body(ROOT/'addons/core/Scripts/Game/ERR/10_AI/ERR_HunterService.c','int VehicleRadioCapability(')
|
||||
vehicle=vehicle.replace('IEntity actor','Entity* actor').replace('foreach (ERR_HunterVehicle unit : m_Hunters)','for (Unit* unit : m_Hunters)').replace('InventoryStorageManagerComponent storage = InventoryStorageManagerComponent.Cast(unit.Entity.FindComponent(InventoryStorageManagerComponent));','Storage* storage = unit->Entity->storage;')
|
||||
vehicle=vehicle.replace('array<IEntity> items = {};','std::vector<Entity*> items;').replace('foreach (IEntity item : items)','for (Entity* item : items)').replace('item.FindComponent(BaseRadioComponent)','HasBaseRadio(item)').replace('SCR_RadioComponent radio = SCR_RadioComponent.Cast(item.FindComponent(SCR_RadioComponent));','Radio* radio = GetRadio(item);')
|
||||
for obj in ('m_Mode','unit','storage','radio'):vehicle=vehicle.replace(obj+'.',obj+'->')
|
||||
vehicle=vehicle.replace('ERR_Actors.Alive','Alive').replace('CompartmentAccessComponent.GetVehicleIn','VehicleIn').replace('ERR_ConvoyRules.Captured','Captured')
|
||||
run(r'''
|
||||
#include <cassert>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
struct Radio{bool pack=false;bool ERR_IsHQManpack(){return pack;}};
|
||||
struct Storage;
|
||||
struct Entity{bool alive=true,fit=true,baseRadio=false,captured=false;Entity* vehicle=nullptr;Storage* storage=nullptr;Radio* radio=nullptr;int componentQueries=0;};
|
||||
struct Storage{int enumerations=0;std::vector<Entity*>items;void GetItems(std::vector<Entity*>&out){enumerations++;out=items;}};
|
||||
struct Members:std::vector<Entity*>{bool Contains(Entity*p){return std::find(begin(),end(),p)!=end();}};
|
||||
struct Mode{bool active=true;bool Active(){return active;}};
|
||||
struct Unit{struct Entity* Entity=nullptr;void* Group=nullptr;bool Released=false,valid=true;struct Members Members;bool CrewValid(Mode*){return valid;}};
|
||||
bool Alive(Entity*e){return e&&e->alive;}bool CanFight(Entity*e){return Alive(e)&&e->fit;}
|
||||
Entity* VehicleIn(Entity*e){return e->vehicle;}bool Captured(Entity*e,void*){return e->captured;}
|
||||
bool HasBaseRadio(Entity*e){e->componentQueries++;return e->baseRadio;}Radio* GetRadio(Entity*e){e->componentQueries++;return e->radio;}
|
||||
struct Service{Mode* m_Mode=nullptr;bool m_Stopped=false;std::vector<Unit*>m_Hunters;
|
||||
'''+vehicle+r'''
|
||||
};
|
||||
struct HQ{static inline HQ*current=nullptr;Service* service=nullptr;Service*Hunters(){return service;}};
|
||||
struct Query{
|
||||
'''+hq+r'''
|
||||
};
|
||||
int main(){
|
||||
HQ h;Service service;Mode mode;HQ::current=&h;h.service=&service;service.m_Mode=&mode;
|
||||
Entity actor,car,manpack,basic,junk;Storage carried,mounted;Radio packRadio,basicRadio;packRadio.pack=true;
|
||||
actor.storage=&carried;car.storage=&mounted;manpack.baseRadio=true;manpack.radio=&packRadio;basic.baseRadio=true;basic.radio=&basicRadio;
|
||||
Unit unit;unit.Entity=&car;unit.Members.push_back(&actor);service.m_Hunters={&unit};actor.vehicle=&car;mounted.items={&manpack};
|
||||
assert(Query::Capability(nullptr)==0);actor.fit=false;assert(Query::Capability(&actor)==0&&carried.enumerations==0&&mounted.enumerations==0);actor.fit=true;
|
||||
actor.alive=false;assert(Query::Capability(&actor)==0);actor.alive=true;
|
||||
actor.storage=nullptr;assert(Query::Capability(&actor)==0&&mounted.enumerations==0);actor.storage=&carried;
|
||||
// The real vehicle helper still validates ownership and physical inventory.
|
||||
//128 carried objects must not be enumerated or scanned when it returns max2.
|
||||
carried.items.assign(128,&junk);
|
||||
assert(Query::Capability(&actor)==2);
|
||||
std::cout<<"OPCOUNTS actor_inventory="<<carried.enumerations<<" carried_item_components="<<junk.componentQueries<<" vehicle_inventory="<<mounted.enumerations<<std::endl;
|
||||
assert(carried.enumerations==0&&junk.componentQueries==0&&mounted.enumerations==1);
|
||||
// Every following call observes current vehicle state; no added cache.
|
||||
carried.items={&basic};
|
||||
for(int reason=0;reason<7;reason++){
|
||||
if(reason==0)actor.vehicle=nullptr;
|
||||
if(reason==1)car.captured=true;
|
||||
if(reason==2)car.alive=false;
|
||||
if(reason==3)unit.Released=true;
|
||||
if(reason==4)unit.valid=false;
|
||||
if(reason==5)mounted.items.clear();
|
||||
if(reason==6)unit.Members.clear();
|
||||
int before=carried.enumerations;assert(Query::Capability(&actor)==1&&carried.enumerations==before+1);
|
||||
actor.vehicle=&car;car.captured=false;car.alive=true;unit.Released=false;unit.valid=true;mounted.items={&manpack};unit.Members.clear();unit.Members.push_back(&actor);
|
||||
before=carried.enumerations;assert(Query::Capability(&actor)==2&&carried.enumerations==before);
|
||||
}
|
||||
// Lack of HQ/service/active mission never invents a mounted link; ordinary
|
||||
//personal inventory classification keeps its existing0/1/2 behavior.
|
||||
mode.active=false;assert(Query::Capability(&actor)==1);mode.active=true;
|
||||
service.m_Stopped=true;assert(Query::Capability(&actor)==1);service.m_Stopped=false;
|
||||
h.service=nullptr;
|
||||
for(int cap=0;cap<=2;cap++){
|
||||
carried.items={nullptr,&junk};if(cap==1)carried.items.push_back(&basic);if(cap==2)carried.items.push_back(&manpack);
|
||||
int before=carried.enumerations;assert(Query::Capability(&actor)==cap&&carried.enumerations==before+1);
|
||||
}
|
||||
HQ::current=nullptr;assert(Query::Capability(&actor)==2);
|
||||
}
|
||||
''')
|
||||
print('PASS: actual HQ/vehicle capability preserves living/inventory/ownership/physical-radio gates; max2 skips128 carried-item checks and one enumeration; changes remain live')
|
||||
Reference in New Issue
Block a user