"""Run native profession classification with deterministic world-data doubles.""" from pathlib import Path import subprocess,tempfile root=Path(__file__).resolve().parents[2] s=(root/'src/server/game/World/AdventureProfessionTargets.cpp').read_text() code=r''' #include "AdventureProfessionPolicy.h" #include #include #include #include constexpr int CORPSE=1,CREATURE_TYPE_BEAST=1,UNIT_FIELD_FLAGS=0,UNIT_FLAG_SKINNABLE=1; constexpr int GAMEOBJECT_TYPE_CHEST=3,GAMEOBJECT_TYPE_SPELL_FOCUS=8,GO_READY=0,LOCK_KEY_SKILL=2,MAX_LOCK_CASE=2; using LockType=unsigned;unsigned SkillByLockType(unsigned type){return type==1?186:type==2?182:0;} struct Creature;struct GameObject; struct Guid{std::string ToString(){return "source";}bool IsEmpty(){return true;}}; struct WorldObject{virtual ~WorldObject()=default;bool world=true;int map=0;float z=0;bool IsInWorld(){return world;}int GetMapId(){return map;}float GetPositionZ(){return z;}virtual Creature* ToCreature(){return nullptr;}virtual GameObject* ToGameObject(){return nullptr;}Guid GetGUID(){return {};}}; struct Creature:WorldObject{ bool alive=true,combat=false,skin=false,trainer=false,vendor=false;int death=CORPSE,type=CREATURE_TYPE_BEAST; Creature* ToCreature()override{return this;}bool IsTrainer(){return trainer;}bool IsAlive(){return alive;}int getDeathState(){return death;}int GetCreatureType(){return type;}bool HasFlag(int,int){return skin;}bool IsInCombat(){return combat;}bool IsVendor(){return vendor;}Guid GetCharmerOrOwnerGUID(){return {};}int GetEntry(){return 1;} }; struct GameObject:WorldObject{ int type=GAMEOBJECT_TYPE_CHEST,loot=GO_READY,entry=1;bool spawned=true; struct Info{unsigned lock=1;unsigned GetLockId(){return lock;}}info; GameObject* ToGameObject()override{return this;}bool isSpawned(){return spawned;}int GetGoType(){return type;}int getLootState(){return loot;}Info* GetGOInfo(){return &info;}int GetEntry(){return entry;} }; struct Position{float distance=0,z=0;float GetExactDist(WorldObject*)const{return distance;}float GetPositionZ()const{return z;}}; struct AdventureSocialContext{std::string Intent="profession";AdventureProfessionPolicy::Professions PrimaryProfessions{"mining","blacksmithing"};int MapId=0;Position Anchor;std::deque TargetHistory;}; std::vector creatures;std::vector objects; struct Player{bool phase=true,visible=true,los=true,friendly=true;bool IsInPhase(WorldObject*){return phase;}bool CanSeeOrDetect(WorldObject*){return visible;}bool IsWithinLOSInMap(WorldObject*){return los;}bool IsFriendlyTo(Creature*){return friendly;}void GetCreatureListWithEntryInGrid(std::vector& v,int,int){v=creatures;}void GetGameObjectListWithEntryInGrid(std::vector&v,int,int){v=objects;}}; namespace Trainer{enum class Type{Tradeskill,Other};struct Spell{unsigned ReqSkillLine=0,SpellId=1;};struct Data{Type type=Type::Tradeskill;std::vector spells;Type GetTrainerType(){return type;}auto const& GetSpells(){return spells;}};} struct ObjectMgr{Trainer::Data trainer;int GetCreatureDefaultTrainer(int){return 1;}auto GetTrainer(int){return &trainer;}}objectMgr;auto sObjectMgr=&objectMgr; struct Ability{unsigned SkillLine=0;}ability; struct SpellMgr{std::vector> entries;auto GetSkillLineAbilityMapBounds(unsigned){return std::make_pair(entries.begin(),entries.end());}}spellMgr;auto sSpellMgr=&spellMgr; struct Lock{unsigned Type[2]={LOCK_KEY_SKILL,0},Index[2]={1,0};}lockEntry; struct LockStore{Lock* LookupEntry(unsigned id){return id?&lockEntry:nullptr;}}sLockStore; struct Locations{std::string station="anvil";bool enabled=true;bool IsWorkstation(int,std::string const& role){return enabled&&role==station;}}locations;auto sAdventureLocationMgr=&locations; struct AdventureProfessionTargets{static bool Valid(Player*,WorldObject*,std::string const&,AdventureSocialContext const&);static std::vector Find(Player*,std::string const&,AdventureSocialContext&);}; '''+s[s.index('namespace\n{'):]+r''' int main(){ Player p;GameObject go;AdventureSocialContext c;objects={&go}; auto valid=[&](char const* kind){return AdventureProfessionTargets::Valid(&p,&go,kind,c);}; assert(valid("work_mining"));assert(!valid("work_herbalism")); lockEntry.Index[0]=2;assert(!valid("work_mining")); c.PrimaryProfessions={"herbalism","alchemy"};assert(valid("work_herbalism"));assert(!valid("work_blacksmithing")); c.PrimaryProfessions={"mining","blacksmithing"};lockEntry.Index[0]=1; p.phase=false;assert(!valid("work_mining"));p.phase=true; p.visible=false;assert(!valid("work_mining"));p.visible=true; go.spawned=false;assert(!valid("work_mining"));go.spawned=true; go.loot=1;assert(!valid("work_mining"));go.loot=0; go.info.lock=0;assert(!valid("work_mining"));go.info.lock=1; c.Anchor.distance=201;assert(!valid("work_mining"));c.Anchor.distance=0; go.type=GAMEOBJECT_TYPE_SPELL_FOCUS;p.visible=false; assert(valid("work_blacksmithing"));assert(!valid("work_smelting")); locations.station="forge";assert(valid("work_smelting"));assert(!valid("work_blacksmithing")); locations.enabled=false;assert(!valid("work_smelting"));locations.enabled=true; go.type=GAMEOBJECT_TYPE_CHEST;p.visible=true; assert(AdventureProfessionTargets::Find(&p,"work_mining",c).size()==1); c.TargetHistory.push_back("work:source");assert(AdventureProfessionTargets::Find(&p,"work_mining",c).empty()); Creature npc;creatures={&npc};c.PrimaryProfessions={"skinning"}; assert(!AdventureProfessionTargets::Valid(&p,&npc,"work_skinning",c));npc.alive=false;npc.skin=true; assert(AdventureProfessionTargets::Valid(&p,&npc,"work_skinning",c));npc.type=2; assert(!AdventureProfessionTargets::Valid(&p,&npc,"work_skinning",c));npc.type=1;npc.death=2; assert(!AdventureProfessionTargets::Valid(&p,&npc,"work_skinning",c)); npc.alive=true;npc.trainer=true;objectMgr.trainer.spells={{186,1}};c.PrimaryProfessions={"mining"}; assert(AdventureProfessionTargets::Valid(&p,&npc,"profession_trainer",c)); c.PrimaryProfessions.clear();assert(!AdventureProfessionTargets::Valid(&p,&npc,"profession_trainer",c)); objectMgr.trainer.spells={{185,1}};assert(AdventureProfessionTargets::Valid(&p,&npc,"profession_trainer",c)); objectMgr.trainer.spells={{0,1}};spellMgr.entries={{1,&ability}};ability.SkillLine=182; assert(!AdventureProfessionTargets::Valid(&p,&npc,"profession_trainer",c));c.PrimaryProfessions={"herbalism"}; assert(AdventureProfessionTargets::Valid(&p,&npc,"profession_trainer",c)); } ''' with tempfile.TemporaryDirectory(prefix='vcore-profession-targets-') as folder: cpp=Path(folder)/'test.cpp';binary=Path(folder)/'test';cpp.write_text(code) subprocess.run(['c++','-std=c++17','-I',str(root/'src/server/game/World'),str(cpp),'-o',str(binary)],check=True) subprocess.run([str(binary)],check=True) print('Production profession targets: native locks, phase/spawn/loot, stations, corpses, history and trainers passed.')