"""Execute actual collection policy; compare outputs and classification calls. Native sphere queries and FriendlyActor's engine getters are not benchmarked. """ from pathlib import Path import os from policy_harness import ROOT, body, run source = Path(os.environ.get('ERR_MINE_SOURCE', str( ROOT / 'addons/core/Scripts/Game/ERR/10_AI/ERR_KnownMines.c'))) candidate = body(source, 'protected bool Collect(').replace('protected ', '') new = 'if (ChimeraCharacter.Cast(actor) && !m_Near.Contains(actor) && FriendlyActor(actor))' old = 'if (FriendlyActor(actor) && !m_Near.Contains(actor))' # Retain the exact predecessor expression as a differential reference. Nothing # else in the actual extracted body is replaced except the function name. baseline = candidate.replace(new, old).replace('bool Collect(', 'bool Baseline(') friendly = body(source, 'protected bool FriendlyActor(').replace('protected ', '') friendly = friendly.replace('{', '{ ++calls;', 1) for name in ('ChimeraCharacter', 'ERR_Actors', 'CompartmentAccessComponent', 'SCR_FactionManager'): friendly = friendly.replace(name + '.', name + '::') friendly = friendly.replace('m_Mode.', 'm_Mode->').replace('faction.', 'faction->') friendly = friendly.replace('EnemyFaction().', 'EnemyFaction()->') candidate = candidate.replace('ChimeraCharacter.Cast', 'ChimeraCharacter::Cast') run(r''' #include #include #include #include struct Actor {bool friendly=false;bool character=true;}; using IEntity=Actor*; int casts=0; struct ChimeraCharacter {static IEntity Cast(IEntity actor) { ++casts;return actor && actor->character ? actor : nullptr; }}; struct ERR_Actors { static bool CanFight(IEntity actor) {return actor && actor->friendly;} static bool Player(IEntity) {return false;} }; struct CompartmentAccessComponent {static bool GetVehicleIn(IEntity) {return false;}}; struct FactionState {bool IsFactionEnemy(FactionState*) {return false;}}; using Faction=FactionState*; FactionState faction; struct SCR_FactionManager {static Faction SGetFaction(IEntity) {return &faction;}}; struct Mode {Faction EnemyFaction() {return &faction;}}; struct Entities:std::vector { mutable int contains=0; int Count() const {return size();} bool Contains(IEntity actor) const { ++contains; return std::find(begin(),end(),actor)!=end(); } void Insert(IEntity actor) {push_back(actor);} }; struct Collector { Entities m_Near; int calls=0,castCalls=0; Mode mode;Mode* m_Mode=&mode; ''' + friendly + '\n' + candidate + '\n' + baseline + r''' }; bool Step(Collector& before,Collector& after,IEntity actor) { int stamp=casts;bool b=before.Baseline(actor);before.castCalls+=casts-stamp; stamp=casts;bool a=after.Collect(actor);after.castCalls+=casts-stamp; assert(b==a); assert(before.m_Near==after.m_Near); // identity, order and multiplicity return a; } int main() { { Collector b,a;Actor actor{true}; for(int i=0;i<32;i++) assert(Step(b,a,&actor)); assert(a.m_Near.size()==1 && b.calls==32 && a.calls==1); // Already accepted actors remain in this pass even if later classified false. actor.friendly=false;assert(Step(b,a,&actor)); assert(b.calls==33 && a.calls==1); std::cout<<"duplicate_accepted baseline_calls=33 candidate_calls=1 members=1\n"; } { Collector b,a;Actor actor{false}; assert(Step(b,a,&actor));assert(Step(b,a,&actor)); assert(a.m_Near.empty() && b.calls==2 && a.calls==2); actor.friendly=true;assert(Step(b,a,&actor)); assert(Step(b,a,&actor)); assert(a.m_Near.size()==1 && b.calls==4 && a.calls==3); std::cout<<"rejected_then_friendly baseline_calls=4 candidate_calls=3 members=1\n"; } { Collector b,a; assert(Step(b,a,nullptr));assert(Step(b,a,nullptr)); assert(a.m_Near.empty() && b.calls==2 && a.calls==0); assert(b.castCalls==2 && a.castCalls==2); assert(b.m_Near.contains==0 && a.m_Near.contains==0); std::cout<<"null baseline_calls=2 candidate_calls=0 casts_each=2 contains_each=0 members=0\n"; } { Collector b,a;Actor actors[129]; for(int i=0;i<128;i++) {actors[i].friendly=true;assert(Step(b,a,&actors[i]));} assert(a.m_Near.size()==128 && b.calls==128 && a.calls==128); actors[128].friendly=true; assert(!Step(b,a,&actors[128])); // new eligible actor assert(!Step(b,a,&actors[0])); // accepted duplicate assert(!Step(b,a,nullptr)); // rejected/null callback assert(b.calls==128 && a.calls==128); std::cout<<"capacity baseline_calls=128 candidate_calls=128 blocked_callbacks=3 members=128\n"; } { Collector b,a;Actor actors[3]{{true},{false},{true}}; for(IEntity actor:{&actors[2],&actors[0],&actors[2],&actors[1],IEntity(nullptr),&actors[0]}) assert(Step(b,a,actor)); assert(a.m_Near[0]==&actors[2] && a.m_Near[1]==&actors[0]); assert(b.calls==6 && a.calls==3); // A fresh tick must reconsider every actor; no cache survives m_Near.Clear(). b.m_Near.clear();a.m_Near.clear(); assert(Step(b,a,&actors[0]));assert(Step(b,a,&actors[2])); assert(b.calls==8 && a.calls==5); std::cout<<"mixed_and_fresh_pass baseline_calls=8 candidate_calls=5 members=2\n"; } { Collector b,a;Actor accepted{true},prop{true,false}; assert(Step(b,a,&accepted)); int bc=b.castCalls,ac=a.castCalls,bl=b.m_Near.contains,al=a.m_Near.contains; for(int i=0;i<1000;i++) assert(Step(b,a,&prop)); assert(b.castCalls-bc==1000 && a.castCalls-ac==1000); assert(b.m_Near.contains==bl && a.m_Near.contains==al); assert(b.calls==1001 && a.calls==1); std::cout<<"props callbacks=1000 casts_each=1000 contains_each=0 baseline_classifications=1000 candidate_classifications=0\n"; } { Collector b,a;Actor accepted{true}; assert(Step(b,a,&accepted)); assert(b.castCalls==1 && a.castCalls==2); // Explicit first-seen character overhead. for(int i=0;i<31;i++) assert(Step(b,a,&accepted)); assert(b.castCalls==32 && a.castCalls==33); assert(b.calls==32 && a.calls==1); std::cout<<"character_cast_tradeoff callbacks=32 baseline_casts=32 candidate_casts=33 baseline_classifications=32 candidate_classifications=1\n"; } { Collector b,a;Actor accepted[127],rejected{false}; for(auto& actor:accepted) {actor.friendly=true;assert(Step(b,a,&actor));} int bl=b.m_Near.contains,al=a.m_Near.contains; for(int i=0;i<100;i++) assert(Step(b,a,&rejected)); assert(b.m_Near.contains==bl && a.m_Near.contains-al==100); assert(a.m_Near.size()==127 && b.calls==227 && a.calls==227); std::cout<<"rejected_character_tradeoff callbacks=100 accepted_members=127 baseline_contains=0 candidate_contains=100 classifications_each=100\n"; } } ''') print('PASS: actual Collect output/order/capacity equivalence and classification operation counts')