"""Execute the production bounded PlayerAI exercise and native selection and cleanup.""" from pathlib import Path import subprocess,tempfile root=Path(__file__).resolve().parents[2] s=(root/'src/server/scripts/Custom/viano_bot_commands.cpp').read_text() a=s.index(' class Exercise : public PlayerAI');b=s.index(' std::unordered_map>',a) code=r''' #include #include #include #include #include using uint32=uint32_t; #define TC_LOG_INFO(...) ((void)0) constexpr int UNIT_STATE_CASTING=1; struct ObjectGuid{int value=1;bool operator==(ObjectGuid const&o)const{return value==o.value;}static const ObjectGuid Empty;};const ObjectGuid ObjectGuid::Empty{0}; struct Creature{ObjectGuid guid;bool alive=true,phase=true,rend=false;std::string script="npc_training_dummy";ObjectGuid GetGUID(){return guid;}bool IsAlive(){return alive;}std::string GetScriptName(){return script;}bool GetAuraApplicationOfRankedSpell(uint32,ObjectGuid){return rend;}}target; struct Motion{int clears=0;void Clear(){++clears;}}; struct Player{ bool alive=true,charmed=false,casting=false;float distance=12;std::set auras,phases{1,169};std::vector casts;Creature* victim=nullptr;int swings=0,stops=0;Motion motion; bool IsAlive(){return alive;}bool IsCharmed(){return charmed;}bool IsInPhase(Creature*c){return c->phase;} float GetExactDist(Creature*){return distance;}bool HasUnitState(int){return casting;}void SetFacingToObject(Creature*){} bool HasAura(uint32 id){return auras.count(id);}bool IsWithinMeleeRange(Creature*){return distance<4;} Creature* GetVictim(){return victim;}ObjectGuid GetGUID(){return {26};} void AttackStop(){++stops;victim=nullptr;}void CastStop(){casting=false;}void StopMoving(){}Motion* GetMotionMaster(){return &motion;} void SetSelection(ObjectGuid){} }; namespace ObjectAccessor{Creature* GetCreature(Player&,ObjectGuid){return ⌖}} struct PhasingHandler{static void RemovePhase(Player* p,uint32 id,bool){p->phases.erase(id);}}; constexpr int SPELL_CAST_OK=0; struct SpellCastTargets{void SetUnitTarget(void*){}}; struct Spell{ Player* player;std::set* available;struct Info{uint32 Id;}info; auto GetSpellInfo(){return &info;} int prepare(SpellCastTargets const&){auto id=info.Id;player->casts.push_back(id);available->erase(id);if(id==2457||id==6673)player->auras.insert(id);if(id==100)player->distance=2;if(id==772)target.rend=true;delete this;return SPELL_CAST_OK;} }; struct PlayerAI{ Player* me;explicit PlayerAI(Player*p):me(p){}virtual ~PlayerAI()=default;virtual void UpdateAI(uint32)=0; struct TargetedSpell{Spell* first=nullptr;void* second=nullptr;explicit operator bool()const{return first!=nullptr;}}; std::set available{2457,100,6673,12294,772,7384,1464,78}; templateTargetedSpell VerifySpellCast(uint32 id,T* t){return available.count(id)?TargetedSpell{new Spell{me,&available,{id}},t}:TargetedSpell{};} void AttackStart(Creature*c){me->victim=c;}void DoAutoAttackIfReady(){++me->swings;} }; '''+s[a:b]+r''' int main(){ Player p;Exercise exercise(&p,&target,20); for(unsigned i=0;i<24;++i)assert(exercise.Tick(500)); assert((p.casts==std::vector{2457,100,6673,12294,772,7384,1464,78}));assert(p.swings>0); p.casting=true;auto count=p.casts.size();assert(exercise.Tick(500)&&p.casts.size()==count); p.distance=61;assert(!exercise.Tick(500));exercise.Stop(); assert(p.phases.count(169)&&p.phases.count(1)&&p.stops==1&&p.motion.clears==1); Player q;q.phases={1,169};Exercise withoutAddedPhase(&q,&target,10);withoutAddedPhase.Stop();assert(q.phases.count(169)); Player hostile;target.script="not_a_training_dummy";Exercise rejected(&hostile,&target,10);assert(!rejected.Tick(500)&&hostile.casts.empty()); target.script="npc_training_dummy";hostile.charmed=true;assert(!rejected.Tick(500)); hostile.charmed=false;hostile.alive=false;assert(!rejected.Tick(500)); } ''' with tempfile.TemporaryDirectory() as tmp: src=Path(tmp)/'exercise.cpp';exe=Path(tmp)/'exercise';src.write_text(code) subprocess.run(['g++','-std=c++17',str(src),'-o',str(exe)],check=True) subprocess.run([str(exe)],check=True) print('Production exercise: stance/charge/melee/casts, native validation delegation, bounded lifetime, invalid targets and unchanged native phases passed.')