89 lines
4.8 KiB
Python
89 lines
4.8 KiB
Python
"""Exercise native sleep-space and candidate adapters with map/object fixtures."""
|
|
from pathlib import Path
|
|
import subprocess,tempfile
|
|
root=Path(__file__).resolve().parents[2]
|
|
source=(root/'src/server/game/World/AdventureBehaviorMgr.cpp').read_text()
|
|
def function(signature):
|
|
start=source.index(signature);body=source.index('{',start);end=body+1;depth=1
|
|
while depth:
|
|
depth+=(source[end]=='{')-(source[end]=='}');end+=1
|
|
return source[start:end]
|
|
code=r'''
|
|
#include "AdventureRestSpace.h"
|
|
#include <vector>
|
|
#include <cassert>
|
|
#include <cstdint>
|
|
using uint32=uint32_t;
|
|
#define TC_LOG_INFO(...) ((void)0)
|
|
constexpr float INVALID_HEIGHT=-100000;
|
|
constexpr int GAMEOBJECT_TYPE_CHAIR=7, LINEOFSIGHT_ALL_CHECKS=0;
|
|
namespace VMAP{enum class ModelIgnoreFlags{Nothing};}
|
|
struct Position{
|
|
float x=0,y=0,z=10,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;}
|
|
float GetExactDist(float a,float b,float c)const{return std::sqrt((x-a)*(x-a)+(y-b)*(y-b)+(z-c)*(z-c));}
|
|
float GetExactDist2d(float a,float b)const{return std::hypot(x-a,y-b);}
|
|
};
|
|
struct GameObject:Position{
|
|
std::string name="Wooden Chair";bool phase=true,spawned=true;int type=7;
|
|
bool isSpawned(){return spawned;}auto GetName(){return name;}int GetGoType(){return type;}
|
|
float GetObjectScale(){return 1;}
|
|
};
|
|
struct Creature:Position{bool phase=true;float GetBoundaryRadius(){return 0.5f;}};
|
|
struct PositionFullTerrainStatus{bool outdoors=false;};
|
|
struct Terrain{
|
|
bool outdoors=false;
|
|
void GetFullTerrainStatusForPosition(int,int,float,float,float,PositionFullTerrainStatus& t){t.outdoors=outdoors;}
|
|
};
|
|
struct Map{
|
|
Terrain terrain;bool water=false,bed=false;float level=10;
|
|
float GetHeight(int,float x,float y,float probe,bool,float){
|
|
float h=bed && std::fabs(x-4)<2.1f && std::fabs(y)<0.95f?10.7f:level;
|
|
return probe>=h?h:level;
|
|
}
|
|
float GetWaterLevel(int,float,float){return water?12:-100000;}
|
|
bool isInLineOfSight(int,float,float,float,float,float,float,int,VMAP::ModelIgnoreFlags){return true;}
|
|
Terrain* GetTerrain(){return &terrain;}
|
|
};
|
|
struct Player:Position{
|
|
bool phase=true;Map map;std::vector<GameObject*> objects;std::vector<Player*> people;std::vector<Creature*> creatures;
|
|
struct Guid{uint32 GetCounter(){return 26;}};Guid GetGUID(){return {};}
|
|
Map* GetMap(){return ↦}int GetPhaseShift(){return 0;}int GetMapId(){return 0;}
|
|
float GetCollisionHeight(){return 2;}
|
|
template<class T>bool IsInPhase(T* p){return p->phase;}
|
|
void GetGameObjectListWithEntryInGrid(std::vector<GameObject*>& v,int,float){v=objects;}
|
|
void GetPlayerListInGrid(std::vector<Player*>& v,float){v=people;}
|
|
void GetCreatureListWithEntryInGrid(std::vector<Creature*>& v,int,float){v=creatures;}
|
|
};
|
|
'''
|
|
code+=function(' bool SleepSpace(')+'\n'+function(' std::vector<Position> SleepCandidates(')
|
|
code+=r'''
|
|
int main(){
|
|
Player p;Position anchor(0,0,10);GameObject chair;p.objects={&chair};
|
|
assert(!SleepSpace(&p,anchor));
|
|
chair.phase=false;assert(SleepSpace(&p,anchor));chair.phase=true;
|
|
chair.spawned=false;assert(SleepSpace(&p,anchor));chair.spawned=true;
|
|
chair.z=3;assert(SleepSpace(&p,anchor));chair.z=10;
|
|
auto candidates=SleepCandidates(&p,anchor,true);
|
|
assert(!candidates.empty()); // shift off the chair, rather than merely reject the marker
|
|
for(auto const& c:candidates){assert(c.GetExactDist2d(0,0)>1);assert(std::fabs(c.z-10)<0.01f);}
|
|
p.map.terrain.outdoors=true;assert(SleepCandidates(&p,anchor,true).empty());p.map.terrain.outdoors=false;
|
|
p.map.water=true;assert(SleepCandidates(&p,anchor,true).empty());p.map.water=false;
|
|
p.map.level=3;assert(SleepCandidates(&p,anchor,true).empty());p.map.level=10; // not the storey below
|
|
p.objects.clear();Player visitor;visitor.x=1;p.people={&visitor};assert(!SleepSpace(&p,anchor));p.people.clear();
|
|
Creature npc;npc.x=1;p.creatures={&npc};assert(!SleepSpace(&p,anchor));p.creatures.clear();
|
|
GameObject bed;bed.name="Hospital Bed";bed.type=5;bed.x=4;p.objects={&bed};p.map.bed=true;
|
|
candidates=SleepCandidates(&p,anchor,true);assert(!candidates.empty());
|
|
assert(candidates.front().x==4 && std::fabs(candidates.front().z-10.7f)<0.01f); // real bed before floor
|
|
p.objects.clear();candidates=SleepCandidates(&p,anchor,true);assert(!candidates.empty());
|
|
assert(std::fabs(candidates.front().z-10.7f)<0.01f); // static raised surface before floor
|
|
}
|
|
'''
|
|
with tempfile.TemporaryDirectory() as tmp:
|
|
src=Path(tmp)/'targets.cpp';src.write_text(code);exe=Path(tmp)/'targets'
|
|
subprocess.run(['g++','-std=c++17','-Wall','-Wextra','-Werror','-I'+str(root/'src/server/game/World'),str(src),'-o',str(exe)],check=True)
|
|
subprocess.run([str(exe)],check=True)
|
|
print('Native sleep targets: chair exclusion, phase, despawn, floor search, indoors, water, storey, occupancy, bed/surface preference passed.')
|