"""Execute production instance phases with native-transfer/persistence adapters.""" from pathlib import Path import subprocess,tempfile root=Path(__file__).resolve().parents[2] s=(root/'src/server/game/World/AdventureBehaviorMgr.cpp').read_text() start=s.index('bool AdventureBehaviorMgr::UpdateInstance(') code=r''' #include "AdventureInstancePolicy.h" #include #include #include #include #include using uint32=uint32_t;using uint8=uint8_t; #define TC_LOG_INFO(...) ((void)0) #define TC_LOG_WARN(...) ((void)0) constexpr int UNIT_STAND_STATE_STAND=0,UNIT_STAND_STATE_SIT=1,EMOTE_ONESHOT_KNEEL=16,CMSG_AREATRIGGER=1; struct Position{float x=0,y=0,z=0,o=0;Position()=default;Position(float a,float b,float c,float d=0):x(a),y(b),z(c),o(d){}float GetPositionX()const{return x;}float GetPositionY()const{return y;}float GetPositionZ()const{return z;}float GetOrientation()const{return o;}}; struct Trigger{uint32 ContinentID=0;struct{float X=0,Y=0,Z=0;}Pos;}; struct Target{uint32 target_mapId=36;float target_X=0,target_Y=0,target_Z=0,target_Orientation=0;}; struct Triggers{Trigger entrance,exit;Triggers(){exit.ContinentID=36;exit.Pos.X=100;}Trigger* LookupEntry(uint32 id){return id==78?&entrance:id==121?&exit:nullptr;}}sAreaTriggerStore; struct Targets{Target entrance,exit;Targets(){exit.target_mapId=0;exit.target_X=500;}Target* GetAreaTrigger(uint32 id){return id==78?&entrance:id==121?&exit:nullptr;}}targets;auto sObjectMgr=&targets; struct MapEntry{bool IsRaid(){return false;}}mapEntry; struct Maps{auto LookupEntry(uint32){return &mapEntry;}}sMapStore; struct WorldPacket{uint32 trigger=0;WorldPacket(int,int){}WorldPacket& operator<<(uint32 id){trigger=id;return *this;}}; struct Save{uint32 GetInstanceId(){return 7;}unsigned GetPlayerCount(){return 1;}unsigned GetGroupCount(){return 0;}}save; struct Bind{Save* save=nullptr;}; using Difficulty=unsigned;constexpr int MSG_SET_RAID_DIFFICULTY=2,MSG_SET_DUNGEON_DIFFICULTY=3; struct Group{unsigned GetLeaderGUID(){return 0;}Difficulty GetDifficulty(bool){return 0;}}group; struct Session; struct Player:Position{ uint32 map=0,instance=0,health=100,maximum=100;int stand=0,damages=0,entryCalls=0,exitCalls=0,teleports=0; bool safe=true,group=false,deny=false;Bind bind;Session* session=nullptr; struct Guid{uint32 GetCounter(){return 26;}operator unsigned()const{return 26;}};Guid GetGUID(){return {};} uint32 GetMapId(){return map;}uint32 GetInstanceId(){return instance;}bool IsInWorld(){return true;} bool IsBeingTeleported(){return false;}Group* GetGroup(){return group?&::group:nullptr;} Bind* GetBoundInstance(uint32,int){return bind.save?&bind:nullptr;}int GetDifficulty(bool){return 0;} bool IsInAreaTriggerRadius(Trigger* t){return map==t->ContinentID&&std::fabs(x-t->Pos.X)<3;} float GetAngle(float,float){return 0;}void SetFacingTo(float){}void HandleEmoteCommand(int){} void SetStandState(int v){stand=v;}uint32 GetHealth(){return health;}uint32 GetMaxHealth(){return maximum;} void SetHealth(uint32 h){health=h;++damages;}Session* GetSession(){return session;} float GetExactDist(float a,float b,float c){return std::sqrt((x-a)*(x-a)+(y-b)*(y-b)+(z-c)*(z-c));} float GetExactDist(Position const& p){return GetExactDist(p.x,p.y,p.z);} bool TeleportTo(uint32 m,float a,float b,float c,float o){++teleports;map=m;instance=m==36?7:0;x=a;y=b;z=c;this->o=o;return true;} }; namespace ObjectAccessor{Player*FindPlayer(unsigned){return nullptr;}} struct Session{bool IsClientless(){return true;}void HandleSetRaidDifficultyOpcode(WorldPacket&){}void HandleSetDungeonDifficultyOpcode(WorldPacket&){}Player* p;void CompleteClientlessTeleport(){}void HandleAreaTriggerOpcode(WorldPacket const& packet){ if(packet.trigger==78){++p->entryCalls;if(!p->deny){p->map=36;p->instance=7;p->x=0;}} else{++p->exitCalls;if(!p->deny){p->map=0;p->instance=0;p->x=500;}} }}; bool Unsafe(Player* p){return !p->safe;} struct Database{bool shared=false;templatebool PQuery(char const*,T...){return shared;}}CharacterDatabase; struct Manager{void ClearQueuedActions(uint32){}}manager;auto sClientlessPlayerMgr=&manager; struct Executor{void Clear(uint32){}}executor;auto sClientlessActionExecutorMgr=&executor; struct Travel{void CancelTravel(uint32){}}travel;auto sClientlessTravelMgr=&travel; struct Lua{void DismountGroundMount(Player*,char const*){}}lua;auto sClientlessLuaEngine=&lua; struct AdventureBehaviorMgr{ enum class Phase{Idle,Travel,OnSite}; struct Record{AdventureInstancePolicy::Visit Instance;Phase State=Phase::OnSite;bool Dirty=false;std::string Detail;}; int saves=0,finishes=0;bool saveOK=true; bool SaveInstance(Player*,Record&){++saves;return saveOK;} void FinishInstance(Player* p,Record&r){++finishes;r.Instance={};p->SetStandState(0);} bool UpdateInstance(Player*,Record&,time_t); }; '''+s[start:s.index("void AdventureBehaviorMgr::InterruptForCombat(")]+r''' using Stage=AdventureInstancePolicy::Phase; AdventureBehaviorMgr::Record fresh(){AdventureBehaviorMgr::Record r;r.Instance.Active=true;r.Instance.Entry=78;r.Instance.Exit=121;r.Instance.Map=36;r.Instance.BlockEnd=3600;r.Instance.LossPercent=50;return r;} int main(){ assert(AdventureInstancePolicy::ReturnAt(3600)==3300); assert(AdventureInstancePolicy::MayEnter(3299,3600)&&!AdventureInstancePolicy::MayEnter(3300,3600)); assert(AdventureInstancePolicy::ReturnHealth(100,100,0)==100); assert(AdventureInstancePolicy::ReturnHealth(100,100,50)==50); assert(AdventureInstancePolicy::ReturnHealth(40,100,50)==40); // no healing assert(AdventureInstancePolicy::ReturnHealth(UINT32_MAX,UINT32_MAX,50)==2147483647u); AdventureBehaviorMgr mgr;auto r=fresh();Player p;Session session{&p};p.session=&session; // 40 minutes' travel leaves 15 minutes inside and 5 outside. assert(mgr.UpdateInstance(&p,r,2400)&&r.Instance.Stage==Stage::Preparing&&p.entryCalls==0); assert(mgr.UpdateInstance(&p,r,2409)&&p.entryCalls==0); assert(mgr.UpdateInstance(&p,r,2410)&&p.entryCalls==1&&p.map==36); assert(mgr.UpdateInstance(&p,r,2411)&&r.Instance.Stage==Stage::Inside&&r.Instance.InstanceId==7); int transfers=p.teleports; assert(mgr.UpdateInstance(&p,r,3299)&&p.teleports==transfers&&p.exitCalls==0); assert(mgr.UpdateInstance(&p,r,3300)&&r.Instance.Stage==Stage::Rest&&p.map==0&&p.x==500); assert(p.exitCalls==1&&p.health==50&&p.damages==1&&r.Instance.InjuryApplied); assert(mgr.UpdateInstance(&p,r,3400)&&p.damages==1); assert(!mgr.UpdateInstance(&p,r,3600)&&mgr.finishes==1&&!r.Instance.Active); // Persisted inside state on restart keeps the absolute return time. r=fresh();r.Instance.Stage=Stage::Inside;r.Instance.InstanceId=7;p.map=36;p.instance=7;p.x=0; assert(mgr.UpdateInstance(&p,r,3299)&&p.map==36); assert(!mgr.UpdateInstance(&p,r,3700)&&p.map==0&&!r.Instance.Active); // If native login ejected an expired copy, return to its associated exit. r=fresh();r.Instance.Stage=Stage::Inside;r.Instance.InstanceId=7;p.map=0;p.x=999; assert(mgr.UpdateInstance(&p,r,3400)&&p.x==500&&r.Instance.InjuryApplied); // Replaying a saved return cannot compound damage. r=fresh();r.Instance.Stage=Stage::Returning;r.Instance.InjuryApplied=true;p.x=500; int damages=p.damages;assert(mgr.UpdateInstance(&p,r,3400)&&p.damages==damages); // A failed durable entering save must not start a portal transfer. r=fresh();r.Instance.Stage=Stage::Entering;p.map=0;p.x=0;mgr.saveOK=false; int prevented=p.entryCalls;assert(mgr.UpdateInstance(&p,r,100)&&p.entryCalls==prevented);mgr.saveOK=true; // A denied entrance is not a visit; no exit or damage is invented. r=fresh();r.Instance.Stage=Stage::Entering;p.map=0;p.x=0;p.deny=true;damages=p.damages; assert(mgr.UpdateInstance(&p,r,100)&&r.Instance.Stage==Stage::Rest&&p.damages==damages); p.deny=false; // Late arrival never enters, nor applies a fake injury. r=fresh();r.State=AdventureBehaviorMgr::Phase::Travel;int calls=p.entryCalls; assert(mgr.UpdateInstance(&p,r,3350)&&r.Instance.Stage==Stage::Rest&&p.entryCalls==calls&&p.damages==damages); // Native groups may enter their group copy; unrelated solo shared binds remain rejected. r=fresh();r.Instance.Stage=Stage::Entering;p.group=true; assert(mgr.UpdateInstance(&p,r,100)&&p.entryCalls==calls+1);++calls;p.group=false;p.map=0;p.instance=0;p.x=0; r=fresh();r.Instance.Stage=Stage::Entering;p.bind.save=&save;CharacterDatabase.shared=true; assert(mgr.UpdateInstance(&p,r,100)&&p.entryCalls==calls);CharacterDatabase.shared=false;p.bind.save=nullptr; // A denied exit remains pending and cannot wound a player still inside. r=fresh();r.Instance.Stage=Stage::Returning;p.map=36;p.instance=7;p.x=0;p.deny=true; assert(mgr.UpdateInstance(&p,r,3400)&&r.Instance.Stage==Stage::Returning&&p.damages==damages); p.deny=false; // With no separate native exit, use the original entrance location. r=fresh();r.Instance.Stage=Stage::Returning;r.Instance.Exit=0;p.map=36;p.instance=7;p.x=50; assert(mgr.UpdateInstance(&p,r,3400)&&p.map==0&&p.x==0); } ''' with tempfile.TemporaryDirectory() as tmp: src=Path(tmp)/'instance.cpp';exe=Path(tmp)/'instance';src.write_text(code) subprocess.run(['g++','-include',str(Path(__file__).with_name('telemetry_test_stub.h')),'-std=c++17','-I'+str(root/'src/server/game/World'),str(src),'-o',str(exe)],check=True) subprocess.run([str(exe)],check=True) print('Production instance lifecycle: time budget, true entry, denied/shared entry, native rear exit, restart, expired copy, late arrival, HP and return replay passed.')