74 lines
5.0 KiB
Python
74 lines
5.0 KiB
Python
"""Execute the real five-minute gathering handler with deterministic travel."""
|
|
from pathlib import Path
|
|
import subprocess,tempfile
|
|
root=Path(__file__).resolve().parents[2]
|
|
s=(root/'src/server/game/World/AdventureBehaviorMgr.cpp').read_text();a=s.index('bool AdventureBehaviorMgr::UpdateGathering(');b=s.index('\nvoid AdventureBehaviorMgr::Update(',a)
|
|
code=r'''
|
|
#include "AdventureGroupPolicy.h"
|
|
#include <cassert>
|
|
#include <ctime>
|
|
#include <string>
|
|
#include <cmath>
|
|
#include <iostream>
|
|
#include <vector>
|
|
using uint32=unsigned;
|
|
#define TC_LOG_INFO(...) ((void)0)
|
|
struct Position{float x=0;};struct Guid{unsigned GetCounter(){return 26;}};
|
|
struct Player{float x=50;unsigned map=0;bool combat=false;unsigned stopped=0;Guid GetGUID(){return{};}unsigned GetMapId(){return map;}
|
|
float GetExactDist(Position const&p){return std::fabs(x-p.x);}void StopMoving(){++stopped;}};
|
|
bool Unsafe(Player*p){return p->combat;}
|
|
enum class ClientlessTravelState{Moving,Arrived,Rejected};
|
|
struct Travel{struct{ClientlessTravelState State=ClientlessTravelState::Rejected;}status;unsigned cancels=0;bool StartTravel(Player*,Position const&){status.State=ClientlessTravelState::Moving;return true;}auto GetStatus(unsigned){return &status;}void CancelTravel(unsigned){++cancels;status.State=ClientlessTravelState::Arrived;}}travel;
|
|
auto sClientlessTravelMgr=&travel;
|
|
namespace ClientlessPositioning{float clearance=10;bool available=false;unsigned reserves=0;
|
|
float Clearance(Player*,Player const&){return clearance;}void Reserve(Player*,Player const&){++reserves;}
|
|
bool Nearby(Player*,Position const&,float,Position&spot,std::vector<Position>&){spot.x=3;return available;}}
|
|
|
|
struct AdventureBehaviorMgr{enum class Phase{Travel,OnSite};struct Record{
|
|
std::string Intent="groupformation",Micro="profession_tools",Detail;time_t Deadline=400,GatherRetryAt=0,NextSpacing=0;
|
|
bool Gathering=false,Dirty=false;Phase State=Phase::OnSite;unsigned AnchorMap=0,MicroTimer=20000;Position Anchor;
|
|
struct{bool Active=false,StopRequested=false;}Leisure;
|
|
struct{bool Active=true;}Social;struct{bool Active=false;}Recovery;
|
|
};unsigned moves=0,resets=0;bool reachable=true;
|
|
bool UpdateGathering(Player*,Record&,time_t);
|
|
void ResetMicro(Player*,Record&r){++resets;r.Micro.clear();r.MicroTimer=0;r.Social.Active=r.Recovery.Active=false;}
|
|
bool LocalMove(Player*,Record&,Position const&target,float budget){assert(target.x==0&&budget==500);++moves;if(reachable)travel.status.State=ClientlessTravelState::Moving;return reachable;}
|
|
};
|
|
'''+s[a:b]+r'''
|
|
int main(){
|
|
using AdventureGroupPolicy::Gathering;
|
|
assert(!Gathering("groupformation",401,100));assert(Gathering("groupformation",400,100));
|
|
assert(Gathering("groupformation",400,399));assert(!Gathering("groupformation",400,400));
|
|
assert(!Gathering("groupformation",400,401));assert(!Gathering("groupformation",0,100));assert(!Gathering("leisure",400,100));
|
|
Player p;AdventureBehaviorMgr m;AdventureBehaviorMgr::Record r;
|
|
assert(!m.UpdateGathering(&p,r,99)&&m.moves==0);
|
|
r.Leisure.Active=true;assert(!m.UpdateGathering(&p,r,100));
|
|
assert(r.Gathering&&r.Leisure.StopRequested&&r.MicroTimer==0&&m.resets==0&&m.moves==0);
|
|
r.Leisure.Active=false;assert(m.UpdateGathering(&p,r,101));
|
|
assert(m.moves==1&&m.resets==1&&!r.Social.Active&&r.Micro.empty());
|
|
assert(m.UpdateGathering(&p,r,102)&&m.moves==1);
|
|
travel.status.State=ClientlessTravelState::Rejected;m.reachable=false;
|
|
assert(m.UpdateGathering(&p,r,105)&&m.moves==1);assert(m.UpdateGathering(&p,r,111)&&m.moves==2);
|
|
p.x=0;travel.status.State=ClientlessTravelState::Moving;
|
|
assert(m.UpdateGathering(&p,r,112)&&p.stopped==1&&travel.cancels==1);
|
|
assert(r.Detail=="waiting at group meeting point before departure");
|
|
auto n=m.moves;assert(m.UpdateGathering(&p,r,399)&&m.moves==n); // hold, no new action
|
|
ClientlessPositioning::clearance=0;ClientlessPositioning::available=true;
|
|
assert(m.UpdateGathering(&p,r,399)&&r.NextSpacing==429&&travel.status.State==ClientlessTravelState::Moving);
|
|
auto cancels=travel.cancels;
|
|
assert(m.UpdateGathering(&p,r,399)&&travel.cancels==cancels); // spacing walk must finish
|
|
p.x=3;travel.status.State=ClientlessTravelState::Arrived;
|
|
assert(m.UpdateGathering(&p,r,399)&&travel.cancels==cancels);
|
|
assert(!m.UpdateGathering(&p,r,400)&&!r.Gathering&&r.GatherRetryAt==0); // deadline never waits for members
|
|
r={};r.State=AdventureBehaviorMgr::Phase::Travel;assert(!m.UpdateGathering(&p,r,100)&&!r.Gathering);
|
|
r.State=AdventureBehaviorMgr::Phase::OnSite;r.Dirty=true;assert(!m.UpdateGathering(&p,r,100));
|
|
r.Dirty=false;p.combat=true;assert(!m.UpdateGathering(&p,r,100));
|
|
p.combat=false;r.Intent="instance";assert(!m.UpdateGathering(&p,r,100));
|
|
std::cout<<"Production five-minute gathering: exact cutoff, safe corridor return request, preparation cancellation, bounded retries, meeting hold and deadline release passed\n";
|
|
}
|
|
'''
|
|
with tempfile.TemporaryDirectory()as d:
|
|
p=Path(d);(p/'test.cpp').write_text(code)
|
|
subprocess.run(['c++','-std=c++17','-I'+str(root/'src/server/game/World'),str(p/'test.cpp'),'-o',str(p/'test')],check=True)
|
|
subprocess.run([str(p/'test')],check=True)
|