Files
Viano-Core/tests/clientless/test_adventure_profession_targets.py
T
Nico 440c53acd7
clang PCH / build (push) Canceled after 0s
GCC PCH / build (push) Canceled after 0s
Validate profession scenes and fix native workstation and area targeting
2026-10-27 18:01:03 +01:00

79 lines
6.8 KiB
Python

"""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 <vector>
#include <deque>
#include <cmath>
#include <cassert>
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<std::string> TargetHistory;};
std::vector<Creature*> creatures;std::vector<GameObject*> 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<Creature*>& v,int,int){v=creatures;}void GetGameObjectListWithEntryInGrid(std::vector<GameObject*>&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<Spell> 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<std::pair<int,Ability*>> 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<WorldObject*> 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.')