Reduce redundant AI equipment, radio and observation checks
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:
2026-11-09 17:05:25 +01:00
parent 47cd4fa2bc
commit 4b737c825f
12 changed files with 335 additions and 18 deletions
+16 -3
View File
@@ -12,7 +12,7 @@ for cls in ('ERR_GameMode','SCR_AIGroup','ERR_EnemyRadio','ERR_EnemyEquipmentGro
for obj in ('m_Mode','existing','state','group','agent','entry','actor'):
coordinator=coordinator.replace(obj+'.',obj+'->')
coordinator=coordinator.replace('Group.GetAgents','Group->GetAgents').replace('Combat.ERR_','Combat->ERR_').replace('Mines.ReadyForResupply','Mines->ReadyForResupply').replace('Optics.Check','Optics->Check').replace('Radio.Check','Radio->Check').replace('Radio.Stop','Radio->Stop').replace('Radio.Register','Radio->Register')
for cls in ('Replication','ERR_GameMode','ERR_EnemyEquipmentRules','ERR_EquipmentLog'):coordinator=coordinator.replace(cls+'.',cls+'::')
for cls in ('Replication','ERR_GameMode','ERR_EnemyEquipmentRules','ERR_EquipmentLog','ERR_Actors'):coordinator=coordinator.replace(cls+'.',cls+'::')
coordinator=coordinator.replace('string.Format', 'Format')
coordinator=coordinator.replace('void ERR_EnemyEquipment(', 'ERR_EnemyEquipment(')
coordinator=coordinator.replace('GetGame().GetWorld().GetWorldTime()','worldTime').replace('foreach (','for (').replace('null','nullptr')
@@ -31,10 +31,11 @@ struct SCR_AIGroup;
struct ERR_GameMode{static inline ERR_GameMode* current=nullptr;bool active=true;bool Active(){return active;}static ERR_GameMode* Get(){return current;}};
namespace ERR_EquipmentLog{void Round(ERR_GameMode*){}void Write(string,string){}}
struct SCR_AICombatComponent{int binds=0,refreshes=0;void ERR_BindEnemySkill(ERR_GameMode*,SCR_AIGroup*){binds++;}void ERR_RefreshEnemySkill(){refreshes++;}};
struct IEntity{SCR_AICombatComponent* combat=nullptr;bool eligible=true,unconscious=false;};
struct IEntity{SCR_AICombatComponent* combat=nullptr;bool eligible=true,unconscious=false,alive=true,player=false,captured=false;};
struct AIAgent{IEntity* actor=nullptr;IEntity* GetControlledEntity(){return actor;}};
struct SCR_AIGroup{Array<AIAgent*> agents;void GetAgents(Array<AIAgent*>& out){out=agents;}};
namespace ERR_EnemyEquipmentRules{bool Owned(ERR_GameMode*,SCR_AIGroup*,IEntity* actor){return actor&&actor->eligible;}bool Eligible(ERR_GameMode* m,SCR_AIGroup* g,IEntity* actor){return Owned(m,g,actor)&&!actor->unconscious;}}
namespace ERR_Actors{bool CanFight(IEntity* actor){return actor&&actor->alive&&!actor->unconscious;}}
namespace ERR_EnemyEquipmentRules{int ownedChecks=0;bool Owned(ERR_GameMode*,SCR_AIGroup*,IEntity* actor){++ownedChecks;return actor&&actor->eligible&&actor->alive&&!actor->player&&!actor->captured;}bool Eligible(ERR_GameMode* m,SCR_AIGroup* g,IEntity* actor){return Owned(m,g,actor)&&ERR_Actors::CanFight(actor);}}
struct ERR_EnemyOptics{
IEntity* actor;SCR_AIGroup* group;int checks=0,stops=0;
ERR_EnemyOptics(IEntity* a,SCR_AIGroup* g):actor(a),group(g){}
@@ -66,7 +67,9 @@ int main(){
service.m_Stopped=true;assert(!service.MineSupplyReady(&group,&soldier));service.m_Stopped=false;
service.m_Entries.resize(2049,nullptr);assert(!service.MineSupplyReady(&group,&soldier));service.m_Entries.resize(1);
service.Tick(3001);assert(entry->checks==1&&entry->Optics->checks==1&&combat.refreshes==1);
ERR_EnemyEquipmentRules::ownedChecks=0;
service.Tick(6000);assert(entry->checks==2&&entry->Optics->checks==2&&combat.binds==1&&combat.refreshes==2);
assert(ERR_EnemyEquipmentRules::ownedChecks==1); // Immediate Eligible must not repeat successful Owned.
service.UnregisterGroup(&group);service.Tick(9000);assert(service.m_Entries[0]->Released&&service.m_Entries[0]->checks==2&&entry->Optics->checks==2&&entry->Optics->stops==1);
service.RegisterGroup(&group);service.Tick(12000);assert(service.m_Entries.Count()==1&&combat.binds==1&&combat.refreshes==2);
service.Stop();service.RegisterGroup(&group);service.Tick(50000);assert(service.m_Groups.Count()==0&&service.m_Stopped);
@@ -88,6 +91,16 @@ int main(){
auto capturedOptics=capture.m_Entries[0]->Optics;capturedBody.eligible=false;capture.Tick(6000);
assert(capturedOptics->checks==1&&capturedOptics->stops==1&&capture.m_Entries[0]->Released);
capturedBody.eligible=true;capture.Tick(9000);assert(capturedOptics->checks==1);
// Every pass still performs ownership vetoes before skill or equipment work.
for(int reason=0;reason<3;reason++){
ERR_EnemyEquipment ownership(&mode);SCR_AIGroup ownedGroup;IEntity ownedBody;AIAgent ownedAgent;ownedAgent.actor=&ownedBody;
ownedGroup.agents.Insert(&ownedAgent);ownership.RegisterGroup(&ownedGroup);ownership.Tick(3000);auto ownedEntry=ownership.m_Entries[0];
if(reason==0)ownedBody.alive=false;else if(reason==1)ownedBody.player=true;else ownedBody.captured=true;
ERR_EnemyEquipmentRules::ownedChecks=0;ownership.Tick(6000);
assert(ownedEntry->Released&&ownedEntry->stops==1&&ownedEntry->checks==1&&ERR_EnemyEquipmentRules::ownedChecks==1);
ownedBody.alive=true;ownedBody.player=false;ownedBody.captured=false;ownership.Tick(9000);
assert(ownedEntry->checks==1&&ownedEntry->stops==1); // Terminal release never restarts completed grants.
}
}
''')
print('PASS: actual equipment coordinator registration dedupe, startup delay, five member scans, finite component retries, unregister/stop terminal behavior and 256-group bound')