"""Run production save/restore with a transactional character-DB adapter.""" from pathlib import Path import subprocess,tempfile root=Path(__file__).resolve().parents[2] s=(root/'src/server/game/World/AdventureBehaviorMgr.cpp').read_text() def function(signature): a=s.index(signature);b=s.index('{',a);n=b+1;depth=1 while depth: depth+=(s[n]=='{')-(s[n]=='}');n+=1 return s[a:n] code=r''' #include "AdventureInstancePolicy.h" struct MapEntry{bool IsRaid(){return false;}}mapEntry;struct Maps{MapEntry*LookupEntry(unsigned){return &mapEntry;}}sMapStore; #include #include #include #include #include using uint32=uint32_t;using uint64=uint64_t;using uint8=uint8_t; #define TC_LOG_INFO(...) ((void)0) #define TC_LOG_ERROR(...) ((void)0) constexpr int UNIT_STAND_STATE_STAND=0; std::string str(char const* s){return s;}templatestd::string str(T n){return std::to_string(n);} struct Field{std::string value;std::string GetString(){return value;}uint8 GetUInt8(){return std::stoul(value);}uint32 GetUInt32(){return std::stoul(value);}uint64 GetUInt64(){return std::stoull(value);}}; struct Row{std::vector fields;Field* Fetch(){return fields.data();}}; using Result=std::shared_ptr; struct Operation{std::string sql;std::vector args;}; struct Transaction{std::vector ops;templatevoid PAppend(char const* sql,A... args){ops.push_back({sql,{str(args)...}});}}; using Tx=std::shared_ptr; struct DB{ bool fail=false,table=true;std::vector row;std::vector character;std::vector last; Tx BeginTransaction(){return std::make_shared();}void EscapeString(std::string&){} struct Future{bool success;bool get(){return success;}}; struct Commit{Future m_future;}; Commit AsyncCommitTransaction(Tx& tx){last=tx->ops;if(fail)return {{false}};for(auto const& op:tx->ops){ if(op.sql=="CHARACTER_SAVE")character=op.args; else if(op.sql.find("REPLACE INTO")==0)row=op.args; else if(op.sql.find("DELETE FROM")==0)row.clear(); }return {{true}};} Result Query(char const*){return table?std::make_shared():nullptr;} Result PQuery(char const* sql,uint32){if(row.empty())return nullptr;auto r=std::make_shared(); if(std::string(sql).find("SELECT phase,")==0)for(auto i:{8,6,10})r->fields.push_back({row.at(i)}); else for(unsigned i=1;ifields.push_back({row[i]}); return r; } }CharacterDatabase; struct Player{ unsigned GetDifficulty(bool){return 0;} uint32 health=100,map=36,instance=7;bool teleport=false;int stand=0; struct Guid{uint32 GetCounter(){return 26;}};Guid GetGUID(){return {};} bool IsBeingTeleported(){return teleport;}uint32 GetMapId(){return map;}uint32 GetInstanceId(){return instance;} void SaveToDB(Tx& tx){tx->PAppend("CHARACTER_SAVE",health,map,instance);} void SetStandState(int v){stand=v;} }; struct Location{unsigned InstanceDifficulty=1;};struct Locations{Location l;Location*Find(std::string const&){return &l;}}locations;auto sAdventureLocationMgr=&locations; struct AdventureBehaviorMgr{ enum class Phase{Idle,OnSite}; struct Record{AdventureInstancePolicy::Visit Instance;bool Schedule=false,Dirty=false,ExpeditionStarted=false;Phase State=Phase::Idle; std::string Intent,WantedIntent,Location,WantedLocation,Detail;time_t Deadline=0;}; bool SaveInstance(Player*,Record&);bool RestoreInstance(Player*,Record&);void FinishInstance(Player*,Record&); }; ''' for signature in ('bool AdventureBehaviorMgr::SaveInstance(', 'bool AdventureBehaviorMgr::RestoreInstance(', 'void AdventureBehaviorMgr::FinishInstance('):code+=function(signature)+'\n' code+=r''' int main(){ AdventureBehaviorMgr mgr;AdventureBehaviorMgr::Record r;Player p; assert(!mgr.RestoreInstance(&p,r)&&!r.ExpeditionStarted); auto& v=r.Instance;v.Active=true;v.Location="instance_visit_at_78";v.Entry=78;v.Exit=121;v.Map=36;v.InstanceId=7; v.BlockEnd=3600;v.PrepareUntil=2410;v.Stage=AdventureInstancePolicy::Phase::Inside;v.LossPercent=37;r.Schedule=true; assert(mgr.SaveInstance(&p,r));assert(CharacterDatabase.last.size()==2); assert(CharacterDatabase.character[0]=="100"&&CharacterDatabase.character[2]=="7"); // Restart creates an empty behavior record, then restores the actual visit. AdventureBehaviorMgr::Record restored;assert(mgr.RestoreInstance(&p,restored)); assert(restored.Intent=="instance"&&restored.Location==v.Location&&restored.Deadline==3600&&restored.Schedule); assert(restored.ExpeditionStarted); assert(restored.Instance.Stage==AdventureInstancePolicy::Phase::Inside&&restored.Instance.InstanceId==7); assert(restored.Instance.LossPercent==37&&!restored.Instance.InjuryApplied); // Character health and the once-only marker commit together, never separately. v.Stage=AdventureInstancePolicy::Phase::Rest;v.InjuryApplied=true;p.health=63;p.map=0;p.instance=0; CharacterDatabase.fail=true;assert(!mgr.SaveInstance(&p,r)); assert(CharacterDatabase.character[0]=="100");assert(mgr.RestoreInstance(&p,restored)&&!restored.Instance.InjuryApplied); CharacterDatabase.fail=false;assert(mgr.SaveInstance(&p,r)); assert(CharacterDatabase.character[0]=="63"&&CharacterDatabase.character[1]=="0"); assert(mgr.RestoreInstance(&p,restored)&&restored.Instance.InjuryApplied&&restored.Deadline==3600); // Clear the visit atomically with final character state, and release a queued intent. r.Dirty=true;r.State=AdventureBehaviorMgr::Phase::OnSite;mgr.FinishInstance(&p,r); assert(!r.Instance.Active&&r.State==AdventureBehaviorMgr::Phase::Idle&&CharacterDatabase.row.empty()); assert(!mgr.RestoreInstance(&p,restored)); } ''' with tempfile.TemporaryDirectory() as tmp: src=Path(tmp)/'save.cpp';exe=Path(tmp)/'save';src.write_text(code) subprocess.run(['g++','-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 persistence: phases, original deadline, instance ID, transactional HP marker, failed commit and intent release passed.')